Add Haiku repository support to libsolvext
[platform/upstream/libsolv.git] / ext / repo_haiku.cpp
1 /*
2  * Copyright (c) 2011-2013, Ingo Weinhold <ingo_weinhold@gmx.de>
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #include <package/PackageInfo.h>
9 #include <package/PackageInfoSet.h>
10 #include <package/PackageRoster.h>
11 #include <package/PackageVersion.h>
12 #include <package/RepositoryCache.h>
13 #include <package/RepositoryConfig.h>
14
15 #include "repo_haiku.h"
16
17 using namespace BPackageKit;
18 using namespace BPackageKit::BHPKG;
19
20 static BString haiku_version_to_string(const BPackageVersion &version)
21 {
22   if (version.InitCheck() != B_OK)
23     return BString();
24
25   // compose ":<major>.<minor>.<micro>" (empty epoch)
26   BString string(":");
27   string << version.Major();
28   if (!version.Minor().IsEmpty())
29     {
30       string << '.' << version.Minor();
31       if (!version.Micro().IsEmpty())
32         string << '.' << version.Micro();
33     }
34
35   // append pre-release -- separate it with '/' to keep pool_evrcmp_str() happy
36   // (it expects only the release to be separated by '-')
37   if (!version.PreRelease().IsEmpty())
38     string << '/' << version.PreRelease();
39
40   // append revision
41   if (version.Revision() != 0)
42     string << '-' << version.Revision();
43
44   return string;
45 }
46
47 static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
48   const char *version, int flags, const char* compatVersion = NULL)
49 {
50   Pool *pool = repo->pool;
51
52   Id dependency = pool_str2id(pool, name, 1);
53
54   if (version && version[0] != '\0')
55   {
56     Id versionId = pool_str2id(pool, version, 1);
57
58     if (compatVersion && compatVersion[0] != '\0')
59       {
60         versionId = pool_rel2id(pool, pool_str2id(pool, compatVersion, 1),
61           versionId, REL_COMPAT, 1);
62         versionId = MAKERELDEP(versionId);
63       }
64
65     dependency = pool_rel2id(pool, dependency, versionId, flags, 1);
66   }
67
68   dependencies = repo_addid_dep(repo, dependencies, dependency, 0);
69 }
70
71 static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
72   const BPackageVersion &version, int flags)
73 {
74   add_dependency(repo, dependencies, name, haiku_version_to_string(version),
75     flags);
76 }
77
78 static void add_resolvables(Repo *repo, Offset &dependencies,
79   const BObjectList<BPackageResolvable> &resolvables)
80 {
81   for (int32 i = 0; BPackageResolvable *resolvable = resolvables.ItemAt(i); i++)
82     {
83       add_dependency(repo, dependencies, resolvable->Name(),
84         haiku_version_to_string(resolvable->Version()), REL_EQ,
85         haiku_version_to_string(resolvable->CompatibleVersion()));
86     }
87 }
88
89 static void add_resolvable_expressions(Repo *repo, Offset &dependencies,
90   const BObjectList<BPackageResolvableExpression> &expressions)
91 {
92   for (int32 i = 0;
93     BPackageResolvableExpression *expression = expressions.ItemAt(i); i++)
94     {
95       // It is possible that no version is specified. In that case any version
96       // is acceptable.
97       if (expression->Version().InitCheck() != B_OK)
98         {
99           BPackageVersion version;
100           add_dependency(repo, dependencies, expression->Name(), NULL, 0);
101           continue;
102         }
103
104       int flags = 0;
105       switch (expression->Operator())
106         {
107           case B_PACKAGE_RESOLVABLE_OP_LESS:
108             flags |= REL_LT;
109             break;
110           case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL:
111             flags |= REL_LT | REL_EQ;
112             break;
113           case B_PACKAGE_RESOLVABLE_OP_EQUAL:
114             flags |= REL_EQ;
115             break;
116           case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL:
117             break;
118           case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL:
119             flags |= REL_GT | REL_EQ;
120             break;
121           case B_PACKAGE_RESOLVABLE_OP_GREATER:
122               flags |= REL_GT;
123             break;
124         }
125
126       add_dependency(repo, dependencies, expression->Name(),
127         expression->Version(), flags);
128     }
129 }
130
131 static void add_replaces_list(Repo *repo, Offset &dependencies,
132   const BStringList &packageNames)
133 {
134   int32 count = packageNames.CountStrings();
135   for (int32 i = 0; i < count; i++)
136     {
137       const BString &packageName = packageNames.StringAt(i);
138       add_dependency(repo, dependencies, packageName, BPackageVersion(), 0);
139     }
140 }
141
142 static Id add_package_info_to_repo(Repo *repo, Repodata *repoData,
143   const BPackageInfo &packageInfo)
144 {
145   Pool *pool = repo->pool;
146
147   Id solvableId = repo_add_solvable(repo);
148   Solvable *solvable = pool_id2solvable(pool, solvableId);
149   // Prepend "pkg:" to package name, so "provides" don't match unless explicitly
150   // specified this way.
151   BString name("pkg:");
152   name << packageInfo.Name();
153   solvable->name = pool_str2id(pool, name, 1);
154   if (packageInfo.Architecture() == B_PACKAGE_ARCHITECTURE_ANY)
155     solvable->arch = ARCH_NOARCH;
156   else
157     solvable->arch = pool_str2id(pool,
158       BPackageInfo::kArchitectureNames[packageInfo.Architecture()], 1);
159   solvable->evr = pool_str2id(pool,
160     haiku_version_to_string(packageInfo.Version()), 1);
161   solvable->vendor = pool_str2id(pool, packageInfo.Vendor(), 1);
162   repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_SUMMARY,
163     packageInfo.Summary());
164   repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_DESCRIPTION,
165     packageInfo.Description());
166   repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_PACKAGER,
167     packageInfo.Packager());
168
169   if (!packageInfo.Checksum().IsEmpty())
170     repodata_set_checksum(repoData, solvable - pool->solvables,
171       SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, packageInfo.Checksum());
172
173   solvable->provides = repo_addid_dep(repo, solvable->provides,
174     pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
175
176   add_resolvables(repo, solvable->provides, packageInfo.ProvidesList());
177   add_resolvable_expressions(repo, solvable->requires,
178     packageInfo.RequiresList());
179   add_resolvable_expressions(repo, solvable->supplements,
180     packageInfo.SupplementsList());
181   add_resolvable_expressions(repo, solvable->conflicts,
182     packageInfo.ConflictsList());
183   add_resolvable_expressions(repo, solvable->enhances,
184     packageInfo.FreshensList());
185   add_replaces_list(repo, solvable->obsoletes, packageInfo.ReplacesList());
186   // TODO: Check whether freshens and replaces does indeed work as intended
187   // here.
188
189   // TODO: copyrights, licenses, URLs, source URLs
190
191   return solvableId;
192 }
193
194 static void add_installed_packages(Repo *repo, Repodata *repoData,
195   BPackageInstallationLocation location)
196 {
197   BPackageRoster roster;
198   BPackageInfoSet packageInfos;
199   if (roster.GetActivePackages(location, packageInfos) == B_OK)
200     {
201       BRepositoryCache::Iterator it = packageInfos.GetIterator();
202       while (const BPackageInfo *packageInfo = it.Next())
203         add_package_info_to_repo(repo, repoData, *packageInfo);
204     }
205 }
206
207 int repo_add_haiku_installed_packages(Repo *repo, const char *rootdir,
208   int flags)
209 {
210   Repodata *repoData = repo_add_repodata(repo, flags);
211
212   add_installed_packages(repo, repoData,
213     B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
214   add_installed_packages(repo, repoData,
215     B_PACKAGE_INSTALLATION_LOCATION_COMMON);
216   add_installed_packages(repo, repoData, B_PACKAGE_INSTALLATION_LOCATION_HOME);
217
218   if (!(flags & REPO_NO_INTERNALIZE))
219     repodata_internalize(repoData);
220
221   return 0;
222 }
223
224 Id repo_add_haiku_package(Repo *repo, const char *hpkgPath, int flags)
225 {
226   BPackageInfo packageInfo;
227   if (packageInfo.ReadFromPackageFile(hpkgPath) != B_OK)
228     return 0;
229
230   return repo_add_haiku_package_info(repo, packageInfo, flags);
231 }
232
233 int repo_add_haiku_packages(Repo *repo, const char *repoName, int flags)
234 {
235   BPackageRoster roster;
236   BRepositoryCache cache;
237   if (roster.GetRepositoryCache(repoName, &cache) != B_OK)
238     return 0;
239
240   Repodata *repoData = repo_add_repodata(repo, flags);
241
242   BRepositoryCache::Iterator it = cache.GetIterator();
243   while (const BPackageInfo *packageInfo = it.Next())
244     add_package_info_to_repo(repo, repoData, *packageInfo);
245
246   if (!(flags & REPO_NO_INTERNALIZE))
247     repodata_internalize(repoData);
248
249   return 0;
250 }
251
252 Id repo_add_haiku_package_info(Repo *repo,
253   const BPackageKit::BPackageInfo &packageInfo, int flags)
254 {
255   if (packageInfo.InitCheck() != B_OK)
256     return 0;
257   
258   Repodata *repoData = repo_add_repodata(repo, flags);
259
260   Id id = add_package_info_to_repo(repo, repoData, packageInfo);
261
262   if (!(flags & REPO_NO_INTERNALIZE))
263     repodata_internalize(repoData);
264
265   return id;
266 }