aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Dimitry Ishenko <dimitry.ishenko@gmail.com> 2014-03-18 11:04:50 -0400
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2014-03-20 18:32:14 +0000
commit4a1b5b7509d0faccb32a31f38aa21e6175fd6438 (patch)
tree39fb6df0d083cb58a662122ae86110d1eb96f632
parent12e3419717f48a544b5fe79ab0a166ad0208e778 (diff)
downloadpaludis-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.part5
-rw-r--r--paludis/user_dep_spec.cc72
-rw-r--r--paludis/user_dep_spec.hh39
-rw-r--r--paludis/user_dep_spec_TEST.cc76
4 files changed, 187 insertions, 5 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part
index 05372dc..5a4fdce 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=&lt;cat/pkg-2]</code>.
</ul>
<p>Repository requirements are in the form <code>to</code>, <code>from-&gt;</code> or <code>::from-&gt;to</code>. The
diff --git a/paludis/user_dep_spec.cc b/paludis/user_dep_spec.cc
index 43099c5..a496fbf 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 9624412..8795daf 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 b3bebab..0390f00 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, { }));
+ }
+}
+