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_status_t
Status (){return package_notinstalled
;}
49 package_type_t
Type () {return package_binary
;}
50 const std::string
getfirstfile () {return std::string();}
51 const std::string
getnextfile () {return std::string();}
52 const std::string
SDesc () {return std::string();}
53 void set_sdesc (const std::string
& ) {}
54 const std::string
LDesc () {return std::string();}
55 void set_ldesc (const std::string
& ) {}
57 void pick(bool const &newValue
){/* Ignore attempts to pick this!. Throw an exception here if you want to detect such attemtps instead */}
58 virtual void addScript(Script
const &) {}
59 virtual std::vector
<Script
> &scripts() { scripts_
.clear(); return scripts_
;}
60 virtual bool accessible () const {return false;}
62 std::vector
<Script
> scripts_
;
64 static _defaultversion defaultversion
;
66 /* the wrapper class */
67 packageversion::packageversion() : data (&defaultversion
)
72 /* Create from an actual package */
73 packageversion::packageversion (_packageversion
*pkg
)
78 data
= &defaultversion
;
82 packageversion::packageversion (packageversion
const &existing
) :
88 packageversion::~packageversion()
90 if (--data
->references
== 0)
95 packageversion::operator= (packageversion
const &rhs
)
97 ++rhs
.data
->references
;
98 if (--data
->references
== 0)
105 packageversion::operator ! () const
107 return !data
->Name().size();
110 packageversion::operator bool () const
112 return data
->Name().size();
116 packageversion::operator == (packageversion
const &rhs
) const
118 if (this == &rhs
|| data
== rhs
.data
)
121 return data
->Name () == rhs
.data
->Name() && data
->Canonical_version () == rhs
.data
->Canonical_version();
125 packageversion::operator != (packageversion
const &rhs
) const
127 return ! (*this == rhs
);
131 packageversion::operator < (packageversion
const &rhs
) const
133 int t
= casecompare(data
->Name(), rhs
.data
->Name());
138 else if (casecompare (data
->Canonical_version(), rhs
.data
->Canonical_version()) < 0)
144 packageversion::Name () const
146 return data
->Name ();
150 packageversion::Vendor_version() const
152 return data
->Vendor_version();
156 packageversion::Package_version() const
158 return data
->Package_version();
162 packageversion::Canonical_version() const
164 return data
->Canonical_version();
168 packageversion::setCanonicalVersion (const std::string
& ver
)
170 data
->setCanonicalVersion (ver
);
174 packageversion::Type () const
176 return data
->Type ();
180 packageversion::getfirstfile ()
182 return data
->getfirstfile ();
186 packageversion::getnextfile ()
188 return data
->getnextfile ();
192 packageversion::SDesc () const
194 return data
->SDesc ();
198 packageversion::set_sdesc (const std::string
& sdesc
)
200 data
->set_sdesc (sdesc
);
204 packageversion::LDesc () const
206 return data
->LDesc ();
210 packageversion::set_ldesc (const std::string
& ldesc
)
212 data
->set_ldesc (ldesc
);
216 packageversion::sourcePackage() const
218 return data
->sourcePackage();
221 PackageSpecification
&
222 packageversion::sourcePackageSpecification ()
224 return data
->sourcePackageSpecification ();
228 packageversion::setSourcePackageSpecification (PackageSpecification
const &spec
)
230 data
->setSourcePackageSpecification(spec
);
233 vector
<vector
<PackageSpecification
*> *> *
234 packageversion::depends()
236 return &data
->depends
;
239 const vector
<vector
<PackageSpecification
*> *> *
240 packageversion::depends() const
242 return &data
->depends
;
246 packageversion::picked () const
252 packageversion::pick (bool aBool
, packagemeta
*pkg
)
256 pkg
->message
.display ();
260 packageversion::uninstall ()
266 packageversion::source ()
268 if (!data
->sources
.size())
269 data
->sources
.push_back (packagesource());
270 return &data
->sources
[0];
273 vector
<packagesource
> *
274 packageversion::sources ()
276 return &data
->sources
;
280 packageversion::accessible() const
282 return data
->accessible();
286 packageversion::scan (bool mirror_mode
)
290 /* Remove mirror sites.
291 * FIXME: This is a bit of a hack. a better way is to abstract
292 * the availability logic to the package
296 if (!check_for_cached (*(source ()), mirror_mode
)
297 && ::source
== IDC_SOURCE_LOCALDIR
)
298 source ()->sites
.clear ();
300 catch (Exception
* e
)
302 // We can ignore these, since we're clearing the source list anyway
303 if (e
->errNo () == APPERR_CORRUPT_PACKAGE
)
305 source ()->sites
.clear ();
308 // Unexpected exception.
314 checkForInstalled (PackageSpecification
*spec
)
317 packagemeta
*required
= db
.findBinary (*spec
);
320 if (spec
->satisfies (required
->installed
)
321 && required
->desired
== required
->installed
)
322 /* done, found a satisfactory installed version that will remain
329 checkForUpgradeable (PackageSpecification
*spec
)
332 packagemeta
*required
= db
.findBinary (*spec
);
333 if (!required
|| !required
->installed
)
335 for (set
<packageversion
>::iterator i
= required
->versions
.begin();
336 i
!= required
->versions
.end(); ++i
)
337 if (spec
->satisfies (*i
))
343 checkForSatisfiable (PackageSpecification
*spec
)
346 packagemeta
*required
= db
.findBinary (*spec
);
349 for (set
<packageversion
>::iterator i
= required
->versions
.begin();
350 i
!= required
->versions
.end(); ++i
)
351 if (spec
->satisfies (*i
))
357 select (trusts deftrust
, size_t depth
, packagemeta
*required
,
358 const packageversion
&aVersion
)
360 /* preserve source */
361 bool sourceticked
= required
->desired
.sourcePackage ().picked();
362 /* install this version */
363 required
->desired
= aVersion
;
364 required
->desired
.pick (required
->installed
!= required
->desired
, required
);
365 required
->desired
.sourcePackage ().pick (sourceticked
, NULL
);
366 /* does this requirement have requirements? */
367 return required
->set_requirements (deftrust
, depth
+ 1);
371 processOneDependency (trusts deftrust
, size_t depth
,
372 PackageSpecification
*spec
)
374 /* TODO: add this to a set of packages to be offered to meet the
375 requirement. For now, simply set the install to the first
376 satisfactory version. The user can step through the list if
379 packagemeta
*required
= db
.findBinary (*spec
);
381 packageversion trusted
= required
->trustp(false, deftrust
);
382 if (spec
->satisfies (trusted
)) {
383 return select (deftrust
, depth
, required
, trusted
);
386 Log (LOG_TIMESTAMP
) << "Warning, the default trust level for package "
387 << trusted
.Name() << " does not meet this specification " << *spec
390 set
<packageversion
>::iterator v
;
391 for (v
= required
->versions
.begin();
392 v
!= required
->versions
.end() && !spec
->satisfies (*v
); ++v
);
394 if (v
== required
->versions
.end())
398 return select (deftrust
, depth
, required
, *v
);
402 packageversion::set_requirements (trusts deftrust
, size_t depth
)
405 vector
<vector
<PackageSpecification
*> *>::iterator dp
= depends ()->begin();
406 /* cheap test for too much recursion */
409 /* walk through each and clause */
410 while (dp
!= depends ()->end())
413 1) is a satisfactory or clause installed?
414 2) is an unsatisfactory version of an or clause which has
415 a satisfactory version available installed?
416 3) is a satisfactory package available?
418 /* check each or clause for an installed match */
419 vector
<PackageSpecification
*>::iterator i
=
420 find_if ((*dp
)->begin(), (*dp
)->end(), checkForInstalled
);
421 if (i
!= (*dp
)->end())
423 /* we found an installed ok package */
424 /* next and clause */
428 /* check each or clause for an upgradeable version */
429 i
= find_if ((*dp
)->begin(), (*dp
)->end(), checkForUpgradeable
);
430 if (i
!= (*dp
)->end())
432 /* we found a package that can be up/downgraded to meet the
433 requirement. (*i is the packagespec that can be satisfied.)
436 changed
+= processOneDependency (deftrust
, depth
, *i
) + 1;
439 /* check each or clause for an installable version */
440 i
= find_if ((*dp
)->begin(), (*dp
)->end(), checkForSatisfiable
);
441 if (i
!= (*dp
)->end())
443 /* we found a package that can be installed to meet the requirement */
445 changed
+= processOneDependency (deftrust
, depth
, *i
) + 1;
454 packageversion::addScript(Script
const &aScript
)
456 return data
->addScript (aScript
);
459 std::vector
<Script
> &
460 packageversion::scripts()
462 return data
->scripts();
466 packageversion::compareVersions(const packageversion
&a
, const packageversion
&b
)
468 /* Compare Vendor_version */
469 int comparison
= version_compare(a
.Vendor_version(), b
.Vendor_version());
472 Log (LOG_BABBLE
) << "vendor version comparison " << a
.Vendor_version() << " and " << b
.Vendor_version() << ", result was " << comparison
<< endLog
;
480 /* Vendor_version are tied, compare Package_version */
482 Log (LOG_BABBLE
) << "package version comparison " << a
.Package_version() << " and " << b
.Package_version() << ", result was " << comparison
<< endLog
;
485 comparison
= version_compare(a
.Package_version(), b
.Package_version());
489 /* the parent data class */
491 _packageversion::_packageversion ():picked (false), references (0)
495 _packageversion::~_packageversion ()
499 PackageSpecification
&
500 _packageversion::sourcePackageSpecification ()
502 return _sourcePackage
;
506 _packageversion::setSourcePackageSpecification (PackageSpecification
const &spec
)
508 _sourcePackage
= spec
;
512 _packageversion::sourcePackage ()
518 pkg
= db
.findSource (_sourcePackage
);
519 /* no valid source meta available, just return the default
520 (blank) package version
523 return sourceVersion
;
524 set
<packageversion
>::iterator i
=pkg
->versions
.begin();
525 while (i
!= pkg
->versions
.end())
527 packageversion
const & ver
= * i
;
528 if (_sourcePackage
.satisfies (ver
))
533 return sourceVersion
;
537 _packageversion::accessible() const
539 bool cached (sources
.size() > 0);
540 for (vector
<packagesource
>::const_iterator i
= sources
.begin();
541 i
!=sources
.end(); ++i
)
546 if (::source
== IDC_SOURCE_LOCALDIR
)
548 unsigned int retrievable
= 0;
549 for (vector
<packagesource
>::const_iterator i
= sources
.begin();
550 i
!=sources
.end(); ++i
)
551 if (i
->sites
.size() || i
->Cached ())
553 return retrievable
> 0;
557 _packageversion::addScript(Script
const &aScript
)
559 scripts().push_back(aScript
);
562 std::vector
<Script
> &
563 _packageversion::scripts()
569 dumpAndList (vector
<vector
<PackageSpecification
*> *> const *currentAndList
,
570 std::ostream
&logger
)
575 vector
<vector
<PackageSpecification
*> *>::const_iterator iAnd
=
576 currentAndList
->begin();
579 if ((*iAnd
)->size() > 1) Log (LOG_BABBLE
) << "( ";
580 vector
<PackageSpecification
*>::const_iterator i
= (*iAnd
)->begin();
583 Log (LOG_BABBLE
) << **i
;
584 if (++i
== (*iAnd
)->end()) break;
585 Log (LOG_BABBLE
) << " | ";
587 if ((*iAnd
)->size() > 1) Log (LOG_BABBLE
) << " )";
588 if (++iAnd
== currentAndList
->end()) break;
589 Log (LOG_BABBLE
) << " & ";