2 * Copyright (c) 2001, 2003 Robert Collins.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by Robert Collins <rbtcollins@hotmail.com>
16 /* this is the parent class for all package operations.
19 #include "package_version.h"
20 #include "package_db.h"
21 #include "package_meta.h"
22 #include "LogSingleton.h"
27 #include "Exception.h"
28 #include "csu_util/version_compare.h"
32 /* a default class to avoid special casing empty packageversions */
34 /* TODO place into the class header */
35 class _defaultversion
: public _packageversion
40 // never try to free me!
43 const std::string
Name(){return std::string();}
44 const std::string
Vendor_version() {return std::string();}
45 const std::string
Package_version() {return std::string();}
46 const std::string
Canonical_version() {return std::string();}
47 void setCanonicalVersion (const std::string
& ) {}
48 package_type_t
Type () {return package_binary
;}
49 const std::string
getfirstfile () {return std::string();}
50 const std::string
getnextfile () {return std::string();}
51 const std::string
SDesc () {return std::string();}
52 void set_sdesc (const std::string
& ) {}
53 const std::string
LDesc () {return std::string();}
54 void set_ldesc (const std::string
& ) {}
56 void pick(bool const &newValue
){/* Ignore attempts to pick this!. Throw an exception here if you want to detect such attemtps instead */}
57 virtual void addScript(Script
const &) {}
58 virtual std::vector
<Script
> &scripts() { scripts_
.clear(); return scripts_
;}
59 virtual bool accessible () const {return false;}
61 std::vector
<Script
> scripts_
;
63 static _defaultversion defaultversion
;
65 /* the wrapper class */
66 packageversion::packageversion() : data (&defaultversion
)
71 /* Create from an actual package */
72 packageversion::packageversion (_packageversion
*pkg
)
77 data
= &defaultversion
;
81 packageversion::packageversion (packageversion
const &existing
) :
87 packageversion::~packageversion()
89 if (--data
->references
== 0)
94 packageversion::operator= (packageversion
const &rhs
)
96 ++rhs
.data
->references
;
97 if (--data
->references
== 0)
104 packageversion::operator ! () const
106 return !data
->Name().size();
109 packageversion::operator bool () const
111 return data
->Name().size();
115 packageversion::operator == (packageversion
const &rhs
) const
117 if (this == &rhs
|| data
== rhs
.data
)
120 return data
->Name () == rhs
.data
->Name() && data
->Canonical_version () == rhs
.data
->Canonical_version();
124 packageversion::operator != (packageversion
const &rhs
) const
126 return ! (*this == rhs
);
130 packageversion::operator < (packageversion
const &rhs
) const
132 int t
= casecompare(data
->Name(), rhs
.data
->Name());
137 else if (casecompare (data
->Canonical_version(), rhs
.data
->Canonical_version()) < 0)
143 packageversion::Name () const
145 return data
->Name ();
149 packageversion::Vendor_version() const
151 return data
->Vendor_version();
155 packageversion::Package_version() const
157 return data
->Package_version();
161 packageversion::Canonical_version() const
163 return data
->Canonical_version();
167 packageversion::setCanonicalVersion (const std::string
& ver
)
169 data
->setCanonicalVersion (ver
);
173 packageversion::Type () const
175 return data
->Type ();
179 packageversion::getfirstfile ()
181 return data
->getfirstfile ();
185 packageversion::getnextfile ()
187 return data
->getnextfile ();
191 packageversion::SDesc () const
193 return data
->SDesc ();
197 packageversion::set_sdesc (const std::string
& sdesc
)
199 data
->set_sdesc (sdesc
);
203 packageversion::LDesc () const
205 return data
->LDesc ();
209 packageversion::set_ldesc (const std::string
& ldesc
)
211 data
->set_ldesc (ldesc
);
215 packageversion::sourcePackage() const
217 return data
->sourcePackage();
220 PackageSpecification
&
221 packageversion::sourcePackageSpecification ()
223 return data
->sourcePackageSpecification ();
227 packageversion::setSourcePackageSpecification (PackageSpecification
const &spec
)
229 data
->setSourcePackageSpecification(spec
);
232 vector
<vector
<PackageSpecification
*> *> *
233 packageversion::depends()
235 return &data
->depends
;
238 const vector
<vector
<PackageSpecification
*> *> *
239 packageversion::depends() const
241 return &data
->depends
;
245 packageversion::picked () const
251 packageversion::pick (bool aBool
, packagemeta
*pkg
)
255 pkg
->message
.display ();
259 packageversion::uninstall ()
265 packageversion::source ()
267 if (!data
->sources
.size())
268 data
->sources
.push_back (packagesource());
269 return &data
->sources
[0];
272 vector
<packagesource
> *
273 packageversion::sources ()
275 return &data
->sources
;
279 packageversion::accessible() const
281 return data
->accessible();
285 packageversion::scan (bool mirror_mode
)
289 /* Remove mirror sites.
290 * FIXME: This is a bit of a hack. a better way is to abstract
291 * the availability logic to the package
295 if (!check_for_cached (*(source ()), mirror_mode
)
296 && ::source
== IDC_SOURCE_LOCALDIR
)
297 source ()->sites
.clear ();
299 catch (Exception
* e
)
301 // We can ignore these, since we're clearing the source list anyway
302 if (e
->errNo () == APPERR_CORRUPT_PACKAGE
)
304 source ()->sites
.clear ();
307 // Unexpected exception.
313 checkForInstalled (PackageSpecification
*spec
)
316 packagemeta
*required
= db
.findBinary (*spec
);
319 if (spec
->satisfies (required
->installed
)
320 && required
->desired
== required
->installed
)
321 /* done, found a satisfactory installed version that will remain
328 checkForUpgradeable (PackageSpecification
*spec
)
331 packagemeta
*required
= db
.findBinary (*spec
);
332 if (!required
|| !required
->installed
)
334 for (set
<packageversion
>::iterator i
= required
->versions
.begin();
335 i
!= required
->versions
.end(); ++i
)
336 if (spec
->satisfies (*i
))
342 checkForSatisfiable (PackageSpecification
*spec
)
345 packagemeta
*required
= db
.findBinary (*spec
);
348 for (set
<packageversion
>::iterator i
= required
->versions
.begin();
349 i
!= required
->versions
.end(); ++i
)
350 if (spec
->satisfies (*i
))
356 select (trusts deftrust
, size_t depth
, packagemeta
*required
,
357 const packageversion
&aVersion
)
359 /* preserve source */
360 bool sourceticked
= required
->desired
.sourcePackage ().picked();
361 /* install this version */
362 required
->desired
= aVersion
;
363 required
->desired
.pick (required
->installed
!= required
->desired
, required
);
364 required
->desired
.sourcePackage ().pick (sourceticked
, NULL
);
365 /* does this requirement have requirements? */
366 return required
->set_requirements (deftrust
, depth
+ 1);
370 processOneDependency (trusts deftrust
, size_t depth
,
371 PackageSpecification
*spec
)
373 /* TODO: add this to a set of packages to be offered to meet the
374 requirement. For now, simply set the install to the first
375 satisfactory version. The user can step through the list if
378 packagemeta
*required
= db
.findBinary (*spec
);
380 packageversion trusted
= required
->trustp(false, deftrust
);
381 if (spec
->satisfies (trusted
)) {
382 return select (deftrust
, depth
, required
, trusted
);
385 Log (LOG_TIMESTAMP
) << "Warning, the default trust level for package "
386 << trusted
.Name() << " does not meet this specification " << *spec
389 set
<packageversion
>::iterator v
;
390 for (v
= required
->versions
.begin();
391 v
!= required
->versions
.end() && !spec
->satisfies (*v
); ++v
);
393 if (v
== required
->versions
.end())
397 return select (deftrust
, depth
, required
, *v
);
401 packageversion::set_requirements (trusts deftrust
, size_t depth
)
404 vector
<vector
<PackageSpecification
*> *>::iterator dp
= depends ()->begin();
405 /* cheap test for too much recursion */
408 /* walk through each and clause */
409 while (dp
!= depends ()->end())
412 1) is a satisfactory or clause installed?
413 2) is an unsatisfactory version of an or clause which has
414 a satisfactory version available installed?
415 3) is a satisfactory package available?
417 /* check each or clause for an installed match */
418 vector
<PackageSpecification
*>::iterator i
=
419 find_if ((*dp
)->begin(), (*dp
)->end(), checkForInstalled
);
420 if (i
!= (*dp
)->end())
422 /* we found an installed ok package */
423 /* next and clause */
427 /* check each or clause for an upgradeable version */
428 i
= find_if ((*dp
)->begin(), (*dp
)->end(), checkForUpgradeable
);
429 if (i
!= (*dp
)->end())
431 /* we found a package that can be up/downgraded to meet the
432 requirement. (*i is the packagespec that can be satisfied.)
435 changed
+= processOneDependency (deftrust
, depth
, *i
) + 1;
438 /* check each or clause for an installable version */
439 i
= find_if ((*dp
)->begin(), (*dp
)->end(), checkForSatisfiable
);
440 if (i
!= (*dp
)->end())
442 /* we found a package that can be installed to meet the requirement */
444 changed
+= processOneDependency (deftrust
, depth
, *i
) + 1;
453 packageversion::addScript(Script
const &aScript
)
455 return data
->addScript (aScript
);
458 std::vector
<Script
> &
459 packageversion::scripts()
461 return data
->scripts();
465 packageversion::compareVersions(const packageversion
&a
, const packageversion
&b
)
467 /* Compare Vendor_version */
468 int comparison
= version_compare(a
.Vendor_version(), b
.Vendor_version());
471 Log (LOG_BABBLE
) << "vendor version comparison " << a
.Vendor_version() << " and " << b
.Vendor_version() << ", result was " << comparison
<< endLog
;
479 /* Vendor_version are tied, compare Package_version */
481 Log (LOG_BABBLE
) << "package version comparison " << a
.Package_version() << " and " << b
.Package_version() << ", result was " << comparison
<< endLog
;
484 comparison
= version_compare(a
.Package_version(), b
.Package_version());
488 /* the parent data class */
490 _packageversion::_packageversion ():picked (false), references (0)
494 _packageversion::~_packageversion ()
498 PackageSpecification
&
499 _packageversion::sourcePackageSpecification ()
501 return _sourcePackage
;
505 _packageversion::setSourcePackageSpecification (PackageSpecification
const &spec
)
507 _sourcePackage
= spec
;
511 _packageversion::sourcePackage ()
517 pkg
= db
.findSource (_sourcePackage
);
518 /* no valid source meta available, just return the default
519 (blank) package version
522 return sourceVersion
;
523 set
<packageversion
>::iterator i
=pkg
->versions
.begin();
524 while (i
!= pkg
->versions
.end())
526 packageversion
const & ver
= * i
;
527 if (_sourcePackage
.satisfies (ver
))
532 return sourceVersion
;
536 _packageversion::accessible() const
538 bool cached (sources
.size() > 0);
539 for (vector
<packagesource
>::const_iterator i
= sources
.begin();
540 i
!=sources
.end(); ++i
)
545 if (::source
== IDC_SOURCE_LOCALDIR
)
547 unsigned int retrievable
= 0;
548 for (vector
<packagesource
>::const_iterator i
= sources
.begin();
549 i
!=sources
.end(); ++i
)
550 if (i
->sites
.size() || i
->Cached ())
552 return retrievable
> 0;
556 _packageversion::addScript(Script
const &aScript
)
558 scripts().push_back(aScript
);
561 std::vector
<Script
> &
562 _packageversion::scripts()
568 dumpAndList (vector
<vector
<PackageSpecification
*> *> const *currentAndList
,
569 std::ostream
&logger
)
574 vector
<vector
<PackageSpecification
*> *>::const_iterator iAnd
=
575 currentAndList
->begin();
578 if ((*iAnd
)->size() > 1) Log (LOG_BABBLE
) << "( ";
579 vector
<PackageSpecification
*>::const_iterator i
= (*iAnd
)->begin();
582 Log (LOG_BABBLE
) << **i
;
583 if (++i
== (*iAnd
)->end()) break;
584 Log (LOG_BABBLE
) << " | ";
586 if ((*iAnd
)->size() > 1) Log (LOG_BABBLE
) << " )";
587 if (++iAnd
== currentAndList
->end()) break;
588 Log (LOG_BABBLE
) << " & ";