diff options
author | 2014-03-18 11:04:50 -0400 | |
---|---|---|
committer | 2014-03-20 18:32:14 +0000 | |
commit | 4a1b5b7509d0faccb32a31f38aa21e6175fd6438 (patch) | |
tree | 39fb6df0d083cb58a662122ae86110d1eb96f632 | |
parent | 12e3419717f48a544b5fe79ab0a166ad0208e778 (diff) | |
download | paludis-4a1b5b7509d0faccb32a31f38aa21e6175fd6438.tar.gz paludis-4a1b5b7509d0faccb32a31f38aa21e6175fd6438.tar.xz |
Add exclude dep spec
The spec is in the form [.!exclude=package-dep-spec].
-rw-r--r-- | doc/configuration/specs.html.part | 5 | ||||
-rw-r--r-- | paludis/user_dep_spec.cc | 72 | ||||
-rw-r--r-- | paludis/user_dep_spec.hh | 39 | ||||
-rw-r--r-- | paludis/user_dep_spec_TEST.cc | 76 |
4 files changed, 187 insertions, 5 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part index 05372dcc6..5a4fdce3b 100644 --- a/doc/configuration/specs.html.part +++ b/doc/configuration/specs.html.part @@ -50,6 +50,11 @@ the following order:</p> for numeric values a greater-than comparison is used; it does not match for other types of values. If <code>!=</code> is used for simple values, a not-equal comparison is used. As above, the key may be a raw name or a dollar-prefixed role name, and may be prefixed with <code>::</code> for checking repository metadata.</li> + + <li><code>[.!exclude=spec]</code>: Exclude packages matching <code>spec</code>. The main restriction on <code>spec</code> + is that it may not include the <code>[]</code> brackets. Following are some of the examples of valid exclude + requirements: <code>[.!exclude=cat/pkg]</code> or <code>[.!exclude=virtual/*]</code> or <code>[.!exclude=*/*::repo]</code> or + <code>[.!exclude=>=cat/pkg-5::repo]</code> or <code>[.!exclude=>=cat/pkg-1][.!exclude=<cat/pkg-2]</code>. </ul> <p>Repository requirements are in the form <code>to</code>, <code>from-></code> or <code>::from->to</code>. The diff --git a/paludis/user_dep_spec.cc b/paludis/user_dep_spec.cc index 43099c596..a496fbf01 100644 --- a/paludis/user_dep_spec.cc +++ b/paludis/user_dep_spec.cc @@ -33,6 +33,7 @@ #include <paludis/repository.hh> #include <paludis/mask.hh> #include <paludis/slot.hh> +#include <paludis/match_package.hh> #include <paludis/util/options.hh> #include <paludis/util/log.hh> @@ -132,7 +133,7 @@ namespace } bool user_remove_trailing_square_bracket_if_exists(std::string & s, PartiallyMadePackageDepSpec & result, - bool & had_bracket_version_requirements) + bool & had_bracket_version_requirements, const Environment * const env) { std::string::size_type use_group_p; if (std::string::npos == ((use_group_p = s.rfind('[')))) @@ -221,8 +222,24 @@ namespace case '.': { - std::shared_ptr<const AdditionalPackageDepSpecRequirement> req(std::make_shared<UserKeyRequirement>(flag.substr(1))); - result.additional_requirement(req); + std::string exclude(".!exclude="); + if (0 == flag.compare(0, exclude.size(), exclude)) + { + flag.erase(0, exclude.size()); + + Context cc("When parsing exclude requirement '" + flag + "':"); + if (!env) throw PackageDepSpecError("Environment is null"); + + std::shared_ptr<const AdditionalPackageDepSpecRequirement> req(std::make_shared<ExcludeRequirement>( + parse_user_package_dep_spec(flag, env, { updso_allow_wildcards }) + )); + result.additional_requirement(req); + } + else + { + std::shared_ptr<const AdditionalPackageDepSpecRequirement> req(std::make_shared<UserKeyRequirement>(flag.substr(1))); + result.additional_requirement(req); + } } break; @@ -362,7 +379,7 @@ paludis::parse_user_package_dep_spec(const std::string & ss, const Environment * n::remove_trailing_repo_if_exists() = std::bind(&user_remove_trailing_repo_if_exists, _1, _2), n::remove_trailing_slot_if_exists() = std::bind(&user_remove_trailing_slot_if_exists, _1, _2), n::remove_trailing_square_bracket_if_exists() = std::bind(&user_remove_trailing_square_bracket_if_exists, - _1, _2, std::ref(had_bracket_version_requirements)) + _1, _2, std::ref(had_bracket_version_requirements), env) )); } @@ -390,7 +407,7 @@ paludis::envless_parse_package_dep_spec_for_tests(const std::string & ss) n::remove_trailing_repo_if_exists() = std::bind(&user_remove_trailing_repo_if_exists, _1, _2), n::remove_trailing_slot_if_exists() = std::bind(&user_remove_trailing_slot_if_exists, _1, _2), n::remove_trailing_square_bracket_if_exists() = std::bind(&user_remove_trailing_square_bracket_if_exists, - _1, _2, std::ref(had_bracket_version_requirements)) + _1, _2, std::ref(had_bracket_version_requirements), nullptr) )); } @@ -1152,6 +1169,51 @@ UserKeyRequirement::accumulate_changes_to_make_met( return false; } +ExcludeRequirement::ExcludeRequirement(const PackageDepSpec & s) : + _s(s) +{ +} + +ExcludeRequirement::~ExcludeRequirement() +{ +} + +const std::pair<bool, std::string> +ExcludeRequirement::requirement_met( + const Environment * const env, + const ChangedChoices * const, + const std::shared_ptr<const PackageID> & id, + const std::shared_ptr<const PackageID> & from_id, + const ChangedChoices * const) const +{ + Context context("When working out whether '" + stringify(*id) + "' matches " + as_raw_string() + ":"); + + return std::make_pair(!match_package(*env, _s, id, from_id, { }), as_human_string(from_id)); +} + +const std::string +ExcludeRequirement::as_human_string(const std::shared_ptr<const PackageID> &) const +{ + return "Exclude packages matching " + stringify(_s); +} + +const std::string +ExcludeRequirement::as_raw_string() const +{ + return "[.!exclude=" + stringify(_s) + "]"; +} + +Tribool +ExcludeRequirement::accumulate_changes_to_make_met( + const Environment * const, + const ChangedChoices * const, + const std::shared_ptr<const PackageID> &, + const std::shared_ptr<const PackageID> &, + ChangedChoices &) const +{ + return false; +} + VersionSpecOptions paludis::user_version_spec_options() { diff --git a/paludis/user_dep_spec.hh b/paludis/user_dep_spec.hh index 9624412e2..8795dafc6 100644 --- a/paludis/user_dep_spec.hh +++ b/paludis/user_dep_spec.hh @@ -127,6 +127,45 @@ namespace paludis }; extern template class Pimp<UserKeyRequirement>; + + /** + * An exclude requirement for a PackageDepSpec. + * + * \ingroup g_dep_spec + */ + class PALUDIS_VISIBLE ExcludeRequirement : + public AdditionalPackageDepSpecRequirement + { + private: + PackageDepSpec _s; + + public: + ///\name Basic operations + ///\{ + + ExcludeRequirement(const PackageDepSpec &); + ~ExcludeRequirement(); + + ///\} + + virtual const std::pair<bool, std::string> requirement_met( + const Environment * const, const ChangedChoices *, + const std::shared_ptr<const PackageID> &, + const std::shared_ptr<const PackageID> &, + const ChangedChoices * const) const PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual const std::string as_human_string( + const std::shared_ptr<const PackageID> &) const PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual const std::string as_raw_string() const PALUDIS_ATTRIBUTE((warn_unused_result)); + + virtual Tribool accumulate_changes_to_make_met( + const Environment * const, + const ChangedChoices * const, + const std::shared_ptr<const PackageID> &, + const std::shared_ptr<const PackageID> &, + ChangedChoices &) const PALUDIS_ATTRIBUTE((warn_unused_result)); + }; } #endif diff --git a/paludis/user_dep_spec_TEST.cc b/paludis/user_dep_spec_TEST.cc index b3bebabc8..0390f0060 100644 --- a/paludis/user_dep_spec_TEST.cc +++ b/paludis/user_dep_spec_TEST.cc @@ -507,3 +507,79 @@ TEST_F(UserDepSpecTest, Keys) EXPECT_TRUE(match_package(env, x, pkg1, nullptr, { })); } +TEST_F(UserDepSpecTest, Exclude) +{ + TestEnvironment env; + std::shared_ptr<FakeRepository> repo1(std::make_shared<FakeRepository>(make_named_values<FakeRepositoryParams>( + n::environment() = &env, + n::name() = RepositoryName("repo1")))); + env.add_repository(1, repo1); + + std::shared_ptr<FakeRepository> repo2(std::make_shared<FakeRepository>(make_named_values<FakeRepositoryParams>( + n::environment() = &env, + n::name() = RepositoryName("repo2")))); + env.add_repository(1, repo2); + + std::shared_ptr<FakePackageID> cat1_pkg1_repo1(repo1->add_version("cat1", "pkg1", "1")); + std::shared_ptr<FakePackageID> cat1_pkg2_repo1(repo1->add_version("cat1", "pkg2", "1")); + std::shared_ptr<FakePackageID> cat2_pkg1_repo1(repo1->add_version("cat2", "pkg1", "1")); + std::shared_ptr<FakePackageID> cat2_pkg2_repo1(repo1->add_version("cat2", "pkg2", "1")); + + std::shared_ptr<FakePackageID> cat1_pkg1_repo2(repo2->add_version("cat1", "pkg1", "2")); + std::shared_ptr<FakePackageID> cat1_pkg2_repo2(repo2->add_version("cat1", "pkg2", "2")); + std::shared_ptr<FakePackageID> cat2_pkg1_repo2(repo2->add_version("cat2", "pkg1", "2")); + std::shared_ptr<FakePackageID> cat2_pkg2_repo2(repo2->add_version("cat2", "pkg2", "2")); + + { + PackageDepSpec spec(parse_user_package_dep_spec("cat1/*[.!exclude=*/pkg1]", &env, { updso_allow_wildcards })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg2_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo1, nullptr, { })); + + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg2_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo2, nullptr, { })); + } + + { + PackageDepSpec spec(parse_user_package_dep_spec("*/*[.!exclude=*/pkg1][.!exclude=*/*::repo1]", &env, { updso_allow_wildcards })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg2_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo1, nullptr, { })); + + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg2_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat2_pkg2_repo2, nullptr, { })); + } + + { + PackageDepSpec spec(parse_user_package_dep_spec("cat1/*[.!exclude=>*/pkg1-1]", &env, { updso_allow_wildcards })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg2_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo1, nullptr, { })); + + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(match_package(env, spec, cat1_pkg2_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo2, nullptr, { })); + } + + { + PackageDepSpec spec(parse_user_package_dep_spec("*/*[.!exclude=*/*]", &env, { updso_allow_wildcards })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg2_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo1, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo1, nullptr, { })); + + EXPECT_TRUE(! match_package(env, spec, cat1_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat1_pkg2_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg1_repo2, nullptr, { })); + EXPECT_TRUE(! match_package(env, spec, cat2_pkg2_repo2, nullptr, { })); + } +} + |