]> cygwin.com Git - cygwin-apps/setup.git/blame - libsolv.cc
Change to using a libsolv pool for storing package information
[cygwin-apps/setup.git] / libsolv.cc
CommitLineData
1c159e0a
JT
1/*
2 * Copyright (c) 2017 Jon Turney
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 */
13
14#include "libsolv.h"
15
16#include "solv/solver.h"
17#include "solv/solverdebug.h"
18#include "solv/evr.h"
19
20#include "LogSingleton.h"
21
22// ---------------------------------------------------------------------------
23// Utility functions for mapping between Operators and Relation Ids
24// ---------------------------------------------------------------------------
25
26static Id
27Operator2RelId(PackageSpecification::_operators op)
28{
29 switch (op)
30 {
31 case PackageSpecification::Equals:
32 return REL_EQ;
33 case PackageSpecification::LessThan:
34 return REL_LT;
35 case PackageSpecification::MoreThan:
36 return REL_GT;
37 case PackageSpecification::LessThanEquals:
38 return REL_LT | REL_EQ;
39 case PackageSpecification::MoreThanEquals:
40 return REL_GT | REL_EQ;
41 }
42
43 return 0;
44}
45
46static PackageSpecification::_operators
47RelId2Operator(Id id)
48{
49 switch (id)
50 {
51 case REL_EQ:
52 return PackageSpecification::Equals;
53 case REL_LT:
54 return PackageSpecification::LessThan;
55 case REL_GT:
56 return PackageSpecification::MoreThan;
57 case REL_LT | REL_EQ:
58 return PackageSpecification::LessThanEquals;
59 case REL_GT | REL_EQ:
60 return PackageSpecification::MoreThanEquals;
61 }
62
63 return PackageSpecification::Equals;
64}
65
66// ---------------------------------------------------------------------------
67// implements class SolvableVersion
68//
69// a wrapper around a libsolv Solvable
70// ---------------------------------------------------------------------------
71
72const std::string
73SolvableVersion::Name () const
74{
75 Solvable *solvable = pool_id2solvable(pool, id);
76 return std::string(pool_id2str(pool, solvable->name));
77}
78
79const std::string
80SolvableVersion::Canonical_version() const
81{
82 Solvable *solvable = pool_id2solvable(pool, id);
83 return std::string(pool_id2str(pool, solvable->evr));
84}
85
86package_type_t
87SolvableVersion::Type () const
88{
89 Solvable *solvable = pool_id2solvable(pool, id);
90 if (solvable->arch == ARCH_SRC)
91 return package_source;
92 else
93 return package_binary;
94}
95
96const PackageDepends
97SolvableVersion::depends() const
98{
99 Solvable *solvable = pool_id2solvable(pool, id);
100
101 Queue q;
102 queue_init(&q);
103
104 if (repo_lookup_idarray(solvable->repo, id, SOLVABLE_REQUIRES, &q))
105 {
106 // convert
107 PackageDepends dep;
108
109 for (int i = 0; i < q.count; i++)
110 {
111#ifdef DEBUG
112 Log (LOG_PLAIN) << "dep " << std::hex << q.elements[i] << ": " << pool_dep2str(pool, q.elements[i]) << endLog;
113#endif
114
115 const char *name = pool_id2str(pool, q.elements[i]);
116 PackageSpecification *spec = new PackageSpecification (name);
117
118 if (ISRELDEP(id))
119 {
120 Reldep *rd = GETRELDEP(pool, id);
121 spec->setOperator(RelId2Operator(rd->flags));
122 spec->setVersion(pool_id2str(pool, rd->evr));
123 }
124
125 dep.push_back (spec);
126 }
127
128 queue_empty(&q);
129
130 return dep;
131 }
132
133 // otherwise, return an empty depends list
134 static PackageDepends empty_package;
135 return empty_package;
136}
137
138const std::string
139SolvableVersion::SDesc () const
140{
141 Solvable *solvable = pool_id2solvable(pool, id);
142 const char *sdesc = repo_lookup_str(solvable->repo, id, SOLVABLE_SUMMARY);
143 return sdesc;
144}
145
146SolvableVersion
147SolvableVersion::sourcePackage () const
148{
149 if (!id)
150 return SolvableVersion();
151
152 // extract source package id
153 Solvable *solvable = pool_id2solvable(pool, id);
154 Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
155 Id spkg_id = repo_lookup_id(solvable->repo, id, spkg_attr);
156
157 // has no such attribute
158 if (!spkg_id)
159 return SolvableVersion();
160
161 return SolvableVersion(spkg_id, pool);
162}
163
164packagesource *
165SolvableVersion::source() const
166{
167 if (!id) {
168 static packagesource empty_source = packagesource();
169 return &empty_source;
170 }
171
172 Solvable *solvable = pool_id2solvable(pool, id);
173 Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
174 return (packagesource *)repo_lookup_num(solvable->repo, id, psrc_attr, 0);
175}
176
177bool
178SolvableVersion::accessible () const
179{
180 // XXX: accessible if archive is locally available, or we know a mirror
181 //
182 // (This seems utterly pointless. Packages which aren't locally available are
183 // removed from the package list. Packages we don't know a mirror for don't
184 // appear in the packagelist.)
185 return TRUE;
186}
187
188package_stability_t
189SolvableVersion::Stability () const
190{
191 Solvable *solvable = pool_id2solvable(pool, id);
192 Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
193 return (package_stability_t)repo_lookup_num(solvable->repo, id, stability_attr, TRUST_UNKNOWN);
194}
195
196bool
197SolvableVersion::operator <(SolvableVersion const &rhs) const
198{
199 return (compareVersions(*this, rhs) < 0);
200}
201
202bool
203SolvableVersion::operator ==(SolvableVersion const &rhs) const
204{
205 return (compareVersions(*this, rhs) == 0);
206}
207
208bool
209SolvableVersion::operator !=(SolvableVersion const &rhs) const
210{
211 return (compareVersions(*this, rhs) != 0);
212}
213
214int
215SolvableVersion::compareVersions(const SolvableVersion &a,
216 const SolvableVersion &b)
217{
218 if (a.id == b.id)
219 return 0;
220
221 // if a and b are different, at least one of them has a pool
222 Pool *pool = a.pool ? a.pool : b.pool;
223
224 Solvable *sa = a.id ? pool_id2solvable(a.pool, a.id) : NULL;
225 Solvable *sb = b.id ? pool_id2solvable(b.pool, b.id) : NULL;
226
227 // empty versions compare as if their version is the empty string
228 Id evra = sa ? sa->evr : pool_str2id(pool, "", 1);
229 Id evrb = sb ? sb->evr : pool_str2id(pool, "", 1);
230
231 return pool_evrcmp(pool, evra, evrb, EVRCMP_COMPARE);
232}
233
234// ---------------------------------------------------------------------------
235// implements class SolverPool
236//
237// a simplified wrapper for libsolv
238// ---------------------------------------------------------------------------
239
240static
241void debug_callback(Pool *pool, void *data, int type, const char *str)
242{
243 if (type & (SOLV_FATAL|SOLV_ERROR))
244 LogPlainPrintf("libsolv: %s", str);
245 else
246 LogBabblePrintf("libsolv: %s", str);
247}
248
249SolverPool::SolverPool()
250{
251 /* create a pool */
252 pool = pool_create();
253
254 pool_setdebugcallback(pool, debug_callback, NULL);
255
256 int level = 1;
257#if DEBUG
258 level = 3;
259#endif
260 pool_setdebuglevel(pool, level);
261
262 /* create the repo to hold installed packages */
263 SolvRepo *installed = getRepo("_installed");
264 pool_set_installed(pool, installed->repo);
265}
266
267SolvRepo *
268SolverPool::getRepo(const std::string &name, bool test)
269{
270 RepoList::iterator i = repos.find(name);
271 if (i != repos.end())
272 return i->second;
273
274 /* create repo if not found */
275 SolvRepo *r = new(SolvRepo);
276 r->repo = repo_create(pool, name.c_str());
277
278 /* create attribute store, with no local pool */
279 r->data = repo_add_repodata(r->repo, 0);
280
281 /* remember if this is a test stability repo */
282 r->test = test;
283
284 repos[name] = r;
285
286 return r;
287}
288
289/*
290 Helper function to convert a PackageDepends list to libsolv dependencies.
291*/
292Id
293SolverPool::makedeps(Repo *repo, PackageDepends *requires)
294{
295 Id deps = 0;
296
297 for (PackageDepends::iterator i = requires->begin();
298 i != requires->end();
299 i++)
300 {
301 Id name = pool_str2id(pool, (*i)->packageName().c_str(), 1);
302
303 if ((*i)->version().size() == 0)
304 {
305 // no relation, so dependency is just on package name
306 deps = repo_addid_dep(repo, deps, name, 0);
307 }
308 else
309 {
310 // otherwise, dependency is on package name with a version condition
311 Id evr = pool_str2id(pool, (*i)->version().c_str(), 1);
312 int rel = pool_rel2id(pool, name, evr, Operator2RelId((*i)->op()), 1);
313
314 deps = repo_addid_dep(repo, deps, rel, 0);
315 }
316 }
317
318 return deps;
319}
320
321SolvableVersion
322SolverPool::addPackage(const std::string& pkgname, const addPackageData &pkgdata)
323{
324 std::string repoName = pkgdata.reponame;
325 bool test = false;
326
327 /* It's simplest to place test packages into a separate repo, and then
328 arrange for that repo to be disabled, if we don't want to consider
329 those packages */
330
331 if (pkgdata.stability == TRUST_TEST)
332 {
333 repoName = pkgdata.reponame + "_test_";
334 test = true;
335 }
336
337 SolvRepo *r = getRepo(repoName, test);
338 Repo *repo = r->repo;
339
340 /* create a solvable */
341 Id s = repo_add_solvable(repo);
342 Solvable *solvable = pool_id2solvable(pool, s);
343
344 /* initialize solvable for this packageo/version/etc. */
345 solvable->name = pool_str2id(pool, pkgname.c_str(), 1);
346 solvable->arch = (pkgdata.type == package_binary) ? ARCH_ANY : ARCH_SRC;
347 solvable->evr = pool_str2id(repo->pool, pkgdata.version.c_str(), 1);
348 solvable->vendor = pool_str2id(repo->pool, pkgdata.vendor.c_str(), 1);
349 solvable->provides = repo_addid_dep(repo, solvable->provides, pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
350 if (pkgdata.requires)
351 solvable->requires = makedeps(repo, pkgdata.requires);
352
353 /* a solvable can also store arbitrary attributes not needed for dependency
354 resolution, if we need them */
355
356 Repodata *data = r->data;
357 Id handle = s;
358#if DEBUG
359 Log (LOG_PLAIN) << "solvable " << s << " name " << pkgname << endLog;
360#endif
361
362 /* store short description attribute */
363 repodata_set_str(data, handle, SOLVABLE_SUMMARY, pkgdata.sdesc.c_str());
364 /* store long description attribute */
365 repodata_set_str(data, handle, SOLVABLE_DESCRIPTION, pkgdata.ldesc.c_str());
366
367 /* store source-package attribute */
368 const std::string sname = pkgdata.spkg.packageName();
369 if (!sname.empty())
370 repodata_set_id(data, handle, SOLVABLE_SOURCENAME, pool_str2id(pool, sname.c_str(), 1));
371 else
372 repodata_set_void(data, handle, SOLVABLE_SOURCENAME);
373 /* solvable:sourceevr may also be available from spkg but assumed to be same
374 as evr for the moment */
375
376 /* store source-package id */
377 /* XXX: this assumes we create install package after source package and so can
378 know that id */
379 Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
380 repodata_set_id(data, handle, spkg_attr, pkgdata.spkg_id.id);
381
382 /* we could store packagesource information as attributes ...
383
384 e.g.
385 size SOLVABLE_DOWNLOADSIZE
386 pathname SOLVABLE_MEDIAFILE
387 site SOLVABLE_MEDIABASE
388 checksum SOLVABLE_CHECKSUM
389
390 ... but for the moment, we just store a pointer to a packagesource object
391 */
392 Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
393 packagesource *psrc = new packagesource(pkgdata.archive);
394 repodata_set_num(data, handle, psrc_attr, (intptr_t)psrc);
395
396 /* store stability level attribute */
397 Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
398 repodata_set_num(data, handle, stability_attr, pkgdata.stability);
399
400#if 0
401 repodata_internalize(data);
402
403 /* debug: verify the attributes we've just set get retrieved correctly */
404 SolvableVersion sv = SolvableVersion(s, pool);
405 const std::string check_sdesc = sv.SDesc();
406 if (pkgdata.sdesc.compare(check_sdesc) != 0) {
407 Log (LOG_PLAIN) << pkgname << " has sdesc mismatch: '" << pkgdata.sdesc << "' and '"
408 << check_sdesc << "'" << endLog;
409 }
410 if (!sname.empty()) {
411 SolvableVersion check_spkg = sv.sourcePackage();
412 Solvable *check_spkg_solvable = pool_id2solvable(pool, check_spkg.id);
413 std::string check_sname = pool_id2str(pool, check_spkg_solvable->name);
414 if (sname.compare(check_sname) != 0) {
415 Log (LOG_PLAIN) << pkgname << " has spkg mismatch: '" << pkgdata.spkg.packageName()
416 << "' and '" << check_sname << "'" << endLog;
417 }
418 }
419 packagesource *check_archive = sv.source();
420 if (check_archive != psrc)
421 Log (LOG_PLAIN) << pkgname << " has archive mismatch: " << psrc
422 << " and " << check_archive << endLog;
423 package_stability_t check_stability = sv.Stability();
424 if (check_stability != pkgdata.stability) {
425 Log (LOG_PLAIN) << pkgname << " has stability mismatch: " << pkgdata.stability
426 << " and " << check_stability << endLog;
427 }
428#endif
429
430 return SolvableVersion(s, pool);
431}
432
433void
434SolverPool::internalize()
435{
436 /* Make attribute data available to queries */
437 for (RepoList::iterator i = repos.begin();
438 i != repos.end();
439 i++)
440 {
441 repodata_internalize(i->second->data);
442 }
443}
This page took 0.059808 seconds and 5 git commands to generate.