diff options
Diffstat (limited to 'paludis')
-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 |
3 files changed, 182 insertions, 5 deletions
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, { })); + } +} + |