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