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