summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/generic/apt/aptitude_resolver.cc113
-rw-r--r--src/generic/apt/aptitude_resolver.h202
2 files changed, 295 insertions, 20 deletions
diff --git a/src/generic/apt/aptitude_resolver.cc b/src/generic/apt/aptitude_resolver.cc
index 63750930..8242a2a6 100644
--- a/src/generic/apt/aptitude_resolver.cc
+++ b/src/generic/apt/aptitude_resolver.cc
@@ -1,6 +1,6 @@
// aptitude_resolver.cc
//
-// Copyright (C) 2005, 2008 Daniel Burrows
+// Copyright (C) 2005, 2008-2009 Daniel Burrows
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -24,8 +24,119 @@
#include <apt-pkg/error.h>
#include <aptitude.h>
+#include <generic/apt/matching/compare_patterns.h>
#include <generic/apt/matching/pattern.h>
+int aptitude_resolver::resolver_hint::version_selection::compare(const version_selection &other) const
+{
+ if(type < other.type)
+ return -1;
+ else if(type > other.type)
+ return 1;
+ else switch(type)
+ {
+ case select_by_archive:
+ return version_selection_string.compare(other.version_selection_string);
+
+ case select_uninst:
+ return 0;
+
+ case select_by_version:
+ if(compare_op < other.compare_op)
+ return -1;
+ else if(compare_op > other.compare_op)
+ return 1;
+ else
+ return version_selection_string.compare(other.version_selection_string);
+
+ default:
+ eassert(!"Internal error: we should never get here.");
+ return 0;
+ }
+}
+
+bool aptitude_resolver::resolver_hint::version_selection::matches(const aptitude_resolver_version &ver) const
+{
+ switch(type)
+ {
+ case select_by_archive:
+ if(ver.get_ver().end())
+ return false;
+
+ for(pkgCache::VerFileIterator vf = ver.get_ver().FileList();
+ !vf.end(); ++vf)
+ {
+ for(pkgCache::PkgFileIterator pf = vf.File();
+ !pf.end(); ++pf)
+ {
+ if(pf.Archive() == version_selection_string)
+ return true;
+ }
+ }
+
+ return false;
+
+ case select_uninst:
+ return ver.get_ver().end();
+
+ case select_by_version:
+ {
+ pkgCache::VerIterator real_ver(ver.get_ver());
+ if(real_ver.end())
+ return false;
+
+ int comparison =
+ _system->VS->CmpVersion(real_ver.VerStr(), version_selection_string);
+
+ switch(compare_op)
+ {
+ case less_than:
+ return comparison < 0;
+
+ case less_than_or_equal:
+ return comparison <= 0;
+
+ case equal:
+ return comparison == 0;
+
+ case greater_than:
+ return comparison > 0;
+
+ case greater_than_or_equal:
+ return comparison >= 0;
+
+ default:
+ eassert(!"Internal error: we should never get here.");
+ return 0;
+ }
+ }
+
+ default:
+ eassert(!"Internal error: we should never get here.");
+ return 0;
+ }
+}
+
+int aptitude_resolver::resolver_hint::compare(const resolver_hint &other) const
+{
+ if(type < other.type)
+ return -1;
+ else if(type > other.type)
+ return 1;
+ else if(score < other.score)
+ return -1;
+ else if(score > other.score)
+ return 1;
+ else
+ {
+ const int selection_compare = selection.compare(other.selection);
+ if(selection_compare != 0)
+ return selection_compare;
+
+ return aptitude::matching::compare_patterns(target, other.target);
+ }
+}
+
aptitude_resolver::resolver_hint aptitude_resolver::resolver_hint::parse(const std::string &hint)
{
std::string action;
diff --git a/src/generic/apt/aptitude_resolver.h b/src/generic/apt/aptitude_resolver.h
index a15502a7..e6d1d688 100644
--- a/src/generic/apt/aptitude_resolver.h
+++ b/src/generic/apt/aptitude_resolver.h
@@ -1,7 +1,7 @@
// aptitude_resolver.h -*-c++-*-
//
//
-// Copyright (C) 2005, 2008 Daniel Burrows
+// Copyright (C) 2005, 2008-2009 Daniel Burrows
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -86,22 +86,169 @@ public:
tweak_score
};
+ /** \brief Describes which versions are selected by a hint. */
+ class version_selection
+ {
+ public:
+ /** \brief Describes what sort of version selection is in use. */
+ enum version_selection_type
+ {
+ /** \brief Versions are selected by archive.
+ *
+ * Any version contained in an archive that equals the
+ * version selection string will be selected.
+ */
+ select_by_archive,
+
+ /** \brief The non-installed version of the package will be
+ * matched.
+ */
+ select_uninst,
+
+ /** \brief Versions are selected by version string.
+ *
+ * Any version contained in an archive that compares
+ * correctly to the version selection string (according to
+ * the comparison operator) will be selected.
+ */
+ select_by_version
+ };
+
+ /** \brief Lists the comparison operations that are allowed. */
+ enum compare_op_type
+ {
+ less_than,
+ less_than_or_equal,
+ equal,
+ greater_than,
+ greater_than_or_equal
+ };
+
+ private:
+ version_selection_type type;
+ compare_op_type compare_op;
+ std::string version_selection_string;
+
+ version_selection(version_selection_type _type,
+ compare_op_type _compare_op,
+ const std::string &_version_selection_string)
+ : type(_type), compare_op(_compare_op),
+ version_selection_string(_version_selection_string)
+ {
+ }
+
+ public:
+ version_selection()
+ : type((version_selection_type)-1),
+ compare_op((compare_op_type)-1),
+ version_selection_string()
+ {
+ }
+
+ /** \brief Create a version selection that selects versions by
+ * their archive.
+ *
+ * \param archive The archive to match; only versions that are
+ * contained in this archive will be selected.
+ */
+ static version_selection make_archive(const std::string &archive)
+ {
+ return version_selection(select_by_archive, (compare_op_type)-1, archive);
+ }
+
+ /** \brief Create a version selection that selects not-installed
+ * versions.
+ */
+ static version_selection make_uninst()
+ {
+ return version_selection(select_uninst, (compare_op_type)-1, std::string());
+ }
+
+ /** \brief Create a version selection that selects versions by
+ * version number.
+ *
+ * \param The version number to compare against.
+ * \param The operation to use in comparison. For instance,
+ * use pkgCache::Dep::Less to select only versions
+ * less than the given version.
+ */
+ static version_selection make_version(const std::string &version,
+ compare_op_type compare_op)
+ {
+ return version_selection(select_by_version, compare_op, version);
+ }
+
+ /** \brief Test a version against this selector.
+ *
+ * \param v The version to test.
+ *
+ * \return \b true if v is matched by this selector.
+ */
+ bool matches(const aptitude_resolver_version &v) const;
+
+ /** \brief Compare two version selectors.
+ *
+ * \param other The version selector to compare against.
+ *
+ * Selectors are arbitrarily arranged in a total ordering.
+ *
+ * \return a number less than zero if this selector is less
+ * than the other selector, a number greater than zero if the
+ * other selector is greater than this selector, and zero if
+ * the two selectors are equal.
+ */
+ int compare(const version_selection &other) const;
+
+ bool operator<(const version_selection &other) const { return compare(other) < 0; }
+ bool operator<=(const version_selection &other) const { return compare(other) <= 0; }
+ bool operator==(const version_selection &other) const { return compare(other) == 0; }
+ bool operator>=(const version_selection &other) const { return compare(other) >= 0; }
+ bool operator>(const version_selection &other) const { return compare(other) > 0; }
+
+ /** \brief Get the type of this selection. */
+ version_selection_type get_type() const { return type; }
+
+ /** \brief Get the version selection string of this selection.
+ *
+ * Only valid for select_by_archive and select_by_version
+ * selections.
+ */
+ const std::string &get_version_selection_string() const
+ {
+ eassert(type == select_by_archive || type == select_by_version);
+
+ return version_selection_string;
+ }
+
+ /** \brief Get the comparison operation of this selection.
+ *
+ * Only valid for select_by_version selections.
+ */
+ compare_op_type get_version_comparison_operator() const
+ {
+ eassert(type == select_by_version);
+
+ return compare_op;
+ }
+ };
+
private:
hint_type type;
int score;
cwidget::util::ref_ptr<aptitude::matching::pattern> target;
- std::string version;
+ version_selection selection;
resolver_hint(hint_type _type, int _score,
const cwidget::util::ref_ptr<aptitude::matching::pattern> &_target,
- const std::string &_version)
- : type(_type), score(_score), target(_target), version(_version)
+ version_selection _selection)
+ : type(_type), score(_score), target(_target),
+ selection(_selection)
{
}
public:
resolver_hint()
- : type((hint_type)-1), score(-1), target(NULL), version()
+ : type((hint_type)-1), score(-1), target(NULL), selection()
{
}
@@ -109,24 +256,24 @@ public:
/** \brief Create a hint that rejects a version or versions of a package. */
static resolver_hint make_reject(const cwidget::util::ref_ptr<aptitude::matching::pattern> &target,
- const std::string &version)
+ const version_selection &selection)
{
- return resolver_hint(reject, 0, target, version);
+ return resolver_hint(reject, 0, target, selection);
}
/** \brief Create a hint that mandates a version or versions of a package. */
static resolver_hint make_mandate(const cwidget::util::ref_ptr<aptitude::matching::pattern> &target,
- const std::string &version)
+ const version_selection &selection)
{
- return resolver_hint(mandate, 0, target, version);
+ return resolver_hint(mandate, 0, target, selection);
}
/** \brief Create a hint that adjust the score of a package. */
static resolver_hint make_tweak_score(const cwidget::util::ref_ptr<aptitude::matching::pattern> &target,
- const std::string &version,
+ const version_selection &selection,
int score)
{
- return resolver_hint(tweak_score, score, target, version);
+ return resolver_hint(tweak_score, score, target, selection);
}
/** \brief Parse a resolver hint definition.
@@ -143,11 +290,32 @@ public:
* the removal version) that match TARGET will be selected. If
* VERSION has the form "/<archive>" then the version of the
* package from that archive will be selected. If VERSION is
- * ":UNINST" then the not-installed version of the package will be
- * selected.
+ * ":UNINST" then the not-installed version of the package will
+ * be selected. Finally, VERSION may be ">VERSION2",
+ * "=VERSION2", ">=VERSION2", "<VERSION2", "<=VERSION2", or
+ * "<>VERSION2" to only apply the hint to versions of the package
+ * that compare accordingly to the version string. (obviously
+ * "=VERSION2" is redundant, but it is included for completeness)
*/
static resolver_hint parse(const std::string &definition);
+ /** \brief Compare this hint to another hint.
+ *
+ * \param other The hint to which this is to be compared.
+ *
+ * \return -1 if this is less than other, 0 if the two hints are
+ * equal, and 1 if this is more than other.
+ *
+ * Hints exist in an arbitrary total ordering.
+ */
+ int compare(const resolver_hint &other) const;
+
+ bool operator<(const resolver_hint &other) const { return compare(other) < 0; }
+ bool operator<=(const resolver_hint &other) const { return compare(other) <= 0; }
+ bool operator==(const resolver_hint &other) const { return compare(other) == 0; }
+ bool operator>=(const resolver_hint &other) const { return compare(other) >= 0; }
+ bool operator>(const resolver_hint &other) const { return compare(other) > 0; }
+
/** \brief Get the type of this hint.
*
* \sa hint_type
@@ -165,12 +333,8 @@ public:
const cwidget::util::ref_ptr<aptitude::matching::pattern> &
get_target() const { return target; }
- /** \brief Return the version selected by this hint.
- *
- * \todo Perhaps this should just test whether a version matches
- * instead?
- */
- const std::string &get_version() const { return version; }
+ /** \brief Return the version selection rule for this hint. */
+ const version_selection &get_version_selection() const { return selection; }
};
aptitude_resolver(int step_score, int broken_score,