aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-11-27 21:58:43 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-11-27 21:58:43 +0000
commitc32e10adf99213afbc64dc418df38c7a6bee57fd (patch)
treeede32b8f39058dff9a008c9426eccd597f23a71c
parent6f6efa6972d22378c01fbf07bdbaf33bcf66287f (diff)
downloadpaludis-c32e10adf99213afbc64dc418df38c7a6bee57fd.tar.gz
paludis-c32e10adf99213afbc64dc418df38c7a6bee57fd.tar.xz
Add finer grained control over when paludis falls back to using an installed package to resolve a dependency.
-rw-r--r--paludis/dep_list.cc146
-rw-r--r--paludis/dep_list.hh13
-rw-r--r--paludis/dep_list.sr1
-rw-r--r--paludis/dep_list_TEST.cc128
-rw-r--r--src/paludis/command_line.cc7
-rw-r--r--src/paludis/command_line.hh2
-rw-r--r--src/paludis/install.cc12
7 files changed, 302 insertions, 7 deletions
diff --git a/paludis/dep_list.cc b/paludis/dep_list.cc
index eb7bd50..818c71d 100644
--- a/paludis/dep_list.cc
+++ b/paludis/dep_list.cc
@@ -70,6 +70,7 @@ DepListOptions::DepListOptions() :
reinstall_scm(dl_reinstall_scm_never),
target_type(dl_target_package),
upgrade(dl_upgrade_always),
+ fall_back(dl_fall_back_as_needed_except_targets),
installed_deps_pre(dl_deps_discard),
installed_deps_runtime(dl_deps_try_post),
installed_deps_post(dl_deps_try_post),
@@ -98,6 +99,8 @@ namespace paludis
MergeList::iterator merge_list_insert_position;
long merge_list_generation;
+ DepAtom::ConstPointer current_top_level_target;
+
const PackageDatabaseEntry * current_pde() const
{
if (current_merge_list_entry != merge_list.end())
@@ -110,7 +113,8 @@ namespace paludis
opts(o),
current_merge_list_entry(merge_list.end()),
merge_list_insert_position(merge_list.end()),
- merge_list_generation(0)
+ merge_list_generation(0),
+ current_top_level_target(0)
{
}
};
@@ -416,7 +420,34 @@ DepList::AddVisitor::visit(const PackageDepAtom * const a)
* package targets), otherwise error. */
if (! best_visible_candidate)
{
- if (already_installed->empty())
+ bool can_fall_back;
+ do
+ {
+ switch (d->_imp->opts.fall_back)
+ {
+ case dl_fall_back_never:
+ can_fall_back = false;
+ continue;
+
+ case dl_fall_back_as_needed_except_targets:
+ if (! d->_imp->current_pde())
+ can_fall_back = false;
+ else if (already_installed->empty())
+ can_fall_back = true;
+ else
+ can_fall_back = ! d->is_top_level_target(*already_installed->last());
+
+ continue;
+
+ case dl_fall_back_as_needed:
+ can_fall_back = true;
+ continue;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad fall_back value '" + stringify(d->_imp->opts.fall_back) + "'");
+ } while (false);
+
+ if (already_installed->empty() || ! can_fall_back)
{
if (a->use_requirements_ptr() && d->_imp->env->package_database()->query(
a->without_use_requirements(), is_either))
@@ -426,7 +457,6 @@ DepList::AddVisitor::visit(const PackageDepAtom * const a)
}
else
{
- // todo: top level
Log::get_instance()->message(ll_warning, lc_context, "No visible packages matching '"
+ stringify(*a) + "', falling back to installed package '"
+ stringify(*already_installed->last()) + "'");
@@ -579,7 +609,8 @@ DepList::~DepList()
void
DepList::clear()
{
- _imp.assign(new Implementation<DepList>(_imp->env, _imp->opts));
+ DepListOptions o(options);
+ _imp.assign(new Implementation<DepList>(_imp->env, o));
}
void
@@ -593,6 +624,10 @@ void
DepList::add(DepAtom::ConstPointer atom)
{
DepListTransaction transaction(_imp->merge_list, _imp->merge_list_generation);
+
+ Save<DepAtom::ConstPointer> save_current_top_level_target(&_imp->current_top_level_target,
+ _imp->current_top_level_target ? _imp->current_top_level_target : atom);
+
AddVisitor visitor(this);
atom->accept(&visitor);
transaction.commit();
@@ -776,9 +811,25 @@ bool
DepList::prefer_installed_over_uninstalled(const PackageDatabaseEntry & installed,
const PackageDatabaseEntry & uninstalled)
{
- if (dl_target_package == _imp->opts.target_type)
- if (! _imp->current_pde())
- return false;
+ do
+ {
+ switch (_imp->opts.target_type)
+ {
+ case dl_target_package:
+ if (! _imp->current_pde())
+ return false;
+
+ if (is_top_level_target(uninstalled))
+ return false;
+
+ continue;
+
+ case dl_target_set:
+ continue;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad target_type value '" + stringify(_imp->opts.target_type) + "'");
+ } while (false);
if (dl_reinstall_always == _imp->opts.reinstall)
return false;
@@ -873,3 +924,84 @@ DepList::end() const
return Iterator(_imp->merge_list.end());
}
+namespace
+{
+ struct IsTopLevelTarget :
+ DepAtomVisitorTypes::ConstVisitor,
+ std::unary_function<PackageDatabaseEntry, bool>
+ {
+ const Environment * const env;
+ DepAtom::ConstPointer target;
+ const PackageDatabaseEntry * dbe;
+ bool matched;
+
+ IsTopLevelTarget(const Environment * const e, DepAtom::ConstPointer t) :
+ env(e),
+ target(t),
+ matched(false)
+ {
+ }
+
+ bool operator() (const PackageDatabaseEntry & e)
+ {
+ dbe = &e;
+ matched = false;
+ target->accept(this);
+ return matched;
+ }
+
+ void visit(const AllDepAtom * const a)
+ {
+ if (matched)
+ return;
+
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const PackageDepAtom * const a)
+ {
+ if (matched)
+ return;
+
+ if (match_package(env, a, *dbe))
+ matched = true;
+ }
+
+ void visit(const UseDepAtom * const u)
+ {
+ if (matched)
+ return;
+
+ std::for_each(u->begin(), u->end(), accept_visitor(this));
+ }
+
+ void visit(const AnyDepAtom * const a)
+ {
+ if (matched)
+ return;
+
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const BlockDepAtom * const)
+ {
+ }
+
+ void visit(const PlainTextDepAtom * const) PALUDIS_ATTRIBUTE((noreturn))
+ {
+ throw InternalError(PALUDIS_HERE, "Got PlainTextDepAtom?");
+ }
+ };
+
+}
+
+bool
+DepList::is_top_level_target(const PackageDatabaseEntry & e) const
+{
+ if (! _imp->current_top_level_target)
+ throw InternalError(PALUDIS_HERE, "current_top_level_target not set?");
+
+ IsTopLevelTarget t(_imp->env, _imp->current_top_level_target);
+ return t(e);
+}
+
diff --git a/paludis/dep_list.hh b/paludis/dep_list.hh
index 3e9bbee..0071977 100644
--- a/paludis/dep_list.hh
+++ b/paludis/dep_list.hh
@@ -59,6 +59,18 @@ namespace paludis
};
/**
+ * When can we fall back to installed?
+ *
+ * \ingroup grpdepresolver
+ */
+ enum DepListFallBackOption
+ {
+ dl_fall_back_as_needed_except_targets,
+ dl_fall_back_as_needed,
+ dl_fall_back_never
+ };
+
+ /**
* When should we reinstall scm.
*
* \ingroup grpdepresolver
@@ -266,6 +278,7 @@ namespace paludis
void add_already_installed_package(const PackageDatabaseEntry &, DepTag::ConstPointer);
void add_predeps(DepAtom::ConstPointer, const DepListDepsOption, const std::string &);
void add_postdeps(DepAtom::ConstPointer, const DepListDepsOption, const std::string &);
+ bool is_top_level_target(const PackageDatabaseEntry &) const;
public:
///\name Basic operations
diff --git a/paludis/dep_list.sr b/paludis/dep_list.sr
index 9b0c553..691ea4e 100644
--- a/paludis/dep_list.sr
+++ b/paludis/dep_list.sr
@@ -7,6 +7,7 @@ make_class_DepListOptions()
key reinstall_scm DepListReinstallScmOption
key target_type DepListTargetType
key upgrade DepListUpgradeOption
+ key fall_back DepListFallBackOption
key installed_deps_pre DepListDepsOption
key installed_deps_runtime DepListDepsOption
diff --git a/paludis/dep_list_TEST.cc b/paludis/dep_list_TEST.cc
index b5a1057..bb539f6 100644
--- a/paludis/dep_list_TEST.cc
+++ b/paludis/dep_list_TEST.cc
@@ -1489,5 +1489,133 @@ namespace test_cases
TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "), "cat/one-1:0::repo");
}
} test_dep_list_forced_downgrade_of_installed;
+
+ /**
+ * \test Test DepList fall back never.
+ */
+ struct DepListTestCaseFallBackNever : TestCase
+ {
+ DepListTestCaseFallBackNever() : TestCase("dep list fall back never") { }
+
+ void run()
+ {
+ TestEnvironment env;
+
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+ repo->add_version("cat", "one", "1")->deps.build_depend_string = "cat/two";
+
+ FakeInstalledRepository::Pointer installed_repo(
+ new FakeInstalledRepository(RepositoryName("installed_repo")));
+ env.package_database()->add_repository(installed_repo);
+ installed_repo->add_version("cat", "two", "2");
+
+ DepList d(&env, DepListOptions());
+ d.options.fall_back = dl_fall_back_never;
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse("cat/one")), DepListError);
+ }
+ } test_dep_list_fall_back_never;
+
+ /**
+ * \test Test DepList fall back as needed.
+ */
+ struct DepListTestCaseFallBackAsNeeded : TestCase
+ {
+ DepListTestCaseFallBackAsNeeded() : TestCase("dep list fall back as needed") { }
+
+ void run()
+ {
+ TestEnvironment env;
+
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+ repo->add_version("cat", "one", "1")->deps.build_depend_string = "cat/two";
+
+ FakeInstalledRepository::Pointer installed_repo(
+ new FakeInstalledRepository(RepositoryName("installed_repo")));
+ env.package_database()->add_repository(installed_repo);
+ installed_repo->add_version("cat", "two", "2");
+
+ DepList d(&env, DepListOptions());
+ d.options.fall_back = dl_fall_back_as_needed;
+ d.add(PortageDepParser::parse("cat/one"));
+ d.add(PortageDepParser::parse("cat/two"));
+ TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "), "cat/two-2:0::installed_repo cat/one-1:0::repo");
+ }
+ } test_dep_list_fall_back_as_needed;
+
+ /**
+ * \test Test DepList fall back as needed.
+ */
+ struct DepListTestCaseFallBackAsNeededNotTargets : TestCase
+ {
+ DepListTestCaseFallBackAsNeededNotTargets() : TestCase("dep list fall back as needed not targets") { }
+
+ void run()
+ {
+ TestEnvironment env;
+
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+ repo->add_version("cat", "one", "1")->deps.build_depend_string = "cat/two";
+
+ FakeInstalledRepository::Pointer installed_repo(
+ new FakeInstalledRepository(RepositoryName("installed_repo")));
+ env.package_database()->add_repository(installed_repo);
+ installed_repo->add_version("cat", "two", "2");
+ installed_repo->add_version("cat", "three", "3");
+
+ DepList d1(&env, DepListOptions());
+ d1.options.fall_back = dl_fall_back_as_needed_except_targets;
+ d1.add(PortageDepParser::parse("cat/one"));
+ TEST_CHECK_EQUAL(join(d1.begin(), d1.end(), " "), "cat/two-2:0::installed_repo cat/one-1:0::repo");
+ TEST_CHECK_THROWS(d1.add(PortageDepParser::parse("cat/three")), DepListError);
+
+ DepList d2(&env, DepListOptions());
+ d2.options.fall_back = dl_fall_back_as_needed_except_targets;
+ TEST_CHECK_THROWS(d2.add(PortageDepParser::parse("cat/two")), DepListError);
+
+ DepList d3(&env, DepListOptions());
+ d3.options.fall_back = dl_fall_back_as_needed_except_targets;
+ TEST_CHECK_THROWS(d3.add(PortageDepParser::parse("( cat/one cat/two )")), DepListError);
+
+ DepList d4(&env, DepListOptions());
+ d4.options.fall_back = dl_fall_back_as_needed_except_targets;
+ TEST_CHECK_THROWS(d4.add(PortageDepParser::parse("( cat/one cat/three )")), DepListError);
+ }
+ } test_dep_list_fall_back_as_needed_not_targets;
+
+ /**
+ * \test Test DepList upgrade as needed.
+ */
+ struct DepListTestCaseUpgradeAsNeeded : TestCase
+ {
+ DepListTestCaseUpgradeAsNeeded() : TestCase("dep list upgrade as needed") { }
+
+ void run()
+ {
+ TestEnvironment env;
+
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+ repo->add_version("cat", "one", "1")->deps.build_depend_string = "cat/two";
+ repo->add_version("cat", "two", "2");
+
+ FakeInstalledRepository::Pointer installed_repo(
+ new FakeInstalledRepository(RepositoryName("installed_repo")));
+ env.package_database()->add_repository(installed_repo);
+ installed_repo->add_version("cat", "two", "0");
+
+ DepList d1(&env, DepListOptions());
+ d1.options.upgrade = dl_upgrade_as_needed;
+ d1.add(PortageDepParser::parse("cat/one"));
+ TEST_CHECK_EQUAL(join(d1.begin(), d1.end(), " "), "cat/two-0:0::installed_repo cat/one-1:0::repo");
+
+ DepList d2(&env, DepListOptions());
+ d2.options.upgrade = dl_upgrade_as_needed;
+ d2.add(PortageDepParser::parse("( cat/one cat/two )"));
+ TEST_CHECK_EQUAL(join(d2.begin(), d2.end(), " "), "cat/two-2:0::repo cat/one-1:0::repo");
+ }
+ } test_dep_list_upgrade_as_needed;
}
diff --git a/src/paludis/command_line.cc b/src/paludis/command_line.cc
index 1ffbbc6..63ac0b8 100644
--- a/src/paludis/command_line.cc
+++ b/src/paludis/command_line.cc
@@ -173,6 +173,13 @@ CommandLine::CommandLine() :
("discard", "Discard"),
"error"),
+ dl_fall_back(&dl_args, "dl-fall-back", '\0', "When to fall back to installed packages",
+ paludis::args::EnumArg::EnumArgOptions
+ ("as-needed-except-targets", "Where necessary, but not for target packages")
+ ("as-needed", "Where necessary, including for target packages")
+ ("never", "Never"),
+ "as-needed"),
+
list_args(this, "List options",
"Options relevant for one or more of the --list actions."),
a_repository(&list_args, "repository", '\0', "Matches with this repository name only"),
diff --git a/src/paludis/command_line.hh b/src/paludis/command_line.hh
index ffe7a73..81d0f8e 100644
--- a/src/paludis/command_line.hh
+++ b/src/paludis/command_line.hh
@@ -219,6 +219,8 @@ class CommandLine :
paludis::args::EnumArg dl_circular;
+ paludis::args::EnumArg dl_fall_back;
+
/// }
/// \name List arguments
diff --git a/src/paludis/install.cc b/src/paludis/install.cc
index 99fa9cb..1939bb7 100644
--- a/src/paludis/install.cc
+++ b/src/paludis/install.cc
@@ -748,6 +748,18 @@ do_install()
throw DoHelp("bad value for --dl-circular");
}
+ if (CommandLine::get_instance()->dl_fall_back.specified())
+ {
+ if (CommandLine::get_instance()->dl_fall_back.argument() == "as-needed-except-targets")
+ options.fall_back = dl_fall_back_as_needed_except_targets;
+ else if (CommandLine::get_instance()->dl_fall_back.argument() == "as-needed")
+ options.fall_back = dl_fall_back_as_needed;
+ else if (CommandLine::get_instance()->dl_fall_back.argument() == "never")
+ options.fall_back = dl_fall_back_never;
+ else
+ throw DoHelp("bad value for --dl-fall-back");
+ }
+
if (CommandLine::get_instance()->dl_installed_deps_pre.specified())
options.installed_deps_pre = enum_arg_to_dep_list_deps_option(
CommandLine::get_instance()->dl_installed_deps_pre);