diff options
-rw-r--r-- | doc/configuration/specs.html.part | 6 | ||||
-rw-r--r-- | paludis/user_dep_spec.cc | 175 | ||||
-rw-r--r-- | paludis/user_dep_spec.se | 20 | ||||
-rw-r--r-- | paludis/user_dep_spec_TEST.cc | 21 |
4 files changed, 169 insertions, 53 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part index ad3758eca..05372dcc6 100644 --- a/doc/configuration/specs.html.part +++ b/doc/configuration/specs.html.part @@ -47,9 +47,9 @@ the following order:</p> simple values, sets and sequences, not spec trees and other complex compound keys. If <code><</code> is used in place of <code>=</code>, for numeric values a less-than comparison is used, and for sets, sequences and spec trees, a match occurs if any member of the set or sequence is equal to the value. Similarly if <code>></code> is used, - for numeric values a greater-than comparison is used; it does not match for other types of values. 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> + 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> </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 028101694..322db4ee9 100644 --- a/paludis/user_dep_spec.cc +++ b/paludis/user_dep_spec.cc @@ -454,19 +454,33 @@ namespace paludis { std::string key; std::string value; - char op; + UserKeyRequirementOperator op; Imp(const std::string & s) { - std::string::size_type p(s.find_first_of("=<>?")); - if (std::string::npos == p) - throw PackageDepSpecError("Expected an =, a <, a > or a ? inside '[." + s + "]'"); + int op_size = 1; + std::string::size_type p = std::string::npos; + + if (std::string::npos != (p = s.find("!="))) + { + op_size = 2; + op = ukro_not_equal; + } + else if (std::string::npos != (p = s.find("="))) + op = ukro_equal; + else if (std::string::npos != (p = s.find(">"))) + op = ukro_greater; + else if (std::string::npos != (p = s.find("<"))) + op = ukro_less_or_subset; + else if (std::string::npos != (p = s.find("?"))) + op = ukro_exists; + else + throw PackageDepSpecError("Expected an =, an !=, a <, a > or a ? inside '[." + s + "]'"); key = s.substr(0, p); - value = s.substr(p + 1); - op = s.at(p); + value = s.substr(p + op_size); - if (op == '?' && ! value.empty()) + if (op == ukro_exists && ! value.empty()) throw PackageDepSpecError("Operator '?' takes no value inside '[." + s + "]'"); } }; @@ -633,11 +647,13 @@ namespace { switch (op) { - case '=': + case ukro_equal: return pattern == stringify(k.parse_value().seconds()); - case '<': + case ukro_not_equal: + return pattern != stringify(k.parse_value().seconds()); + case ukro_less_or_subset: return k.parse_value().seconds() < destringify<time_t>(pattern); - case '>': + case ukro_greater: return k.parse_value().seconds() > destringify<time_t>(pattern); } @@ -646,33 +662,67 @@ namespace bool visit(const MetadataValueKey<std::string> & k) const { - return pattern == stringify(k.parse_value()); + switch (op) + { + case ukro_equal: + return pattern == stringify(k.parse_value()); + case ukro_not_equal: + return pattern != stringify(k.parse_value()); + } + + return false; } bool visit(const MetadataValueKey<Slot> & k) const { - return pattern == stringify(k.parse_value().raw_value()); + switch (op) + { + case ukro_equal: + return pattern == stringify(k.parse_value().raw_value()); + case ukro_not_equal: + return pattern != stringify(k.parse_value().raw_value()); + } + + return false; } bool visit(const MetadataValueKey<FSPath> & k) const { - return pattern == stringify(k.parse_value()); + switch (op) + { + case ukro_equal: + return pattern == stringify(k.parse_value()); + case ukro_not_equal: + return pattern != stringify(k.parse_value()); + } + + return false; } bool visit(const MetadataValueKey<bool> & k) const { - return pattern == stringify(k.parse_value()); + switch (op) + { + case ukro_equal: + return pattern == stringify(k.parse_value()); + case ukro_not_equal: + return pattern != stringify(k.parse_value()); + } + + return false; } bool visit(const MetadataValueKey<long> & k) const { switch (op) { - case '=': + case ukro_equal: return pattern == stringify(k.parse_value()); - case '<': + case ukro_not_equal: + return pattern != stringify(k.parse_value()); + case ukro_less_or_subset: return k.parse_value() < destringify<long>(pattern); - case '>': + case ukro_greater: return k.parse_value() > destringify<long>(pattern); } @@ -686,16 +736,24 @@ namespace bool visit(const MetadataValueKey<std::shared_ptr<const PackageID> > & k) const { - return pattern == stringify(*k.parse_value()); + switch (op) + { + case ukro_equal: + return pattern == stringify(*k.parse_value()); + case ukro_not_equal: + return pattern != stringify(*k.parse_value()); + } + + return false; } bool visit(const MetadataSpecTreeKey<DependencySpecTree> & s) const { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -706,9 +764,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -719,9 +777,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -732,9 +790,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -745,9 +803,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -758,9 +816,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -771,9 +829,9 @@ namespace { switch (op) { - case '=': + case ukro_equal: return false; - case '<': + case ukro_less_or_subset: return s.parse_value()->top()->accept_returning<bool>(SpecTreeSearcher(env, id, pattern)); } @@ -785,9 +843,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(v->begin(), v->end(), " "); - case '<': + case ukro_less_or_subset: return v->end() != std::find_if(v->begin(), v->end(), StringifyEqual(pattern)); } @@ -800,9 +858,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(indirect_iterator(v->begin()), indirect_iterator(v->end()), " "); - case '<': + case ukro_less_or_subset: return indirect_iterator(v->end()) != std::find_if( indirect_iterator(v->begin()), indirect_iterator(v->end()), @@ -817,9 +875,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(v->begin(), v->end(), " "); - case '<': + case ukro_less_or_subset: return v->end() != std::find_if(v->begin(), v->end(), StringifyEqual(pattern)); } @@ -832,9 +890,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(v->begin(), v->end(), " "); - case '<': + case ukro_less_or_subset: return v->end() != std::find_if(v->begin(), v->end(), StringifyEqual(pattern)); } @@ -852,9 +910,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(v->begin(), v->end(), " "); - case '<': + case ukro_less_or_subset: return v->end() != std::find_if(v->begin(), v->end(), StringifyEqual(pattern)); } @@ -867,9 +925,9 @@ namespace auto v(s.parse_value()); switch (op) { - case '=': + case ukro_equal: return pattern == join(v->begin(), v->end(), " "); - case '<': + case ukro_less_or_subset: return v->end() != std::find_if(v->begin(), v->end(), StringifyEqual(pattern)); } @@ -1019,7 +1077,7 @@ UserKeyRequirement::requirement_met( if ((! key) && (! mask)) return std::make_pair(false, as_human_string(from_id)); - if (_imp->op == '?') + if (_imp->op == ukro_exists) return std::make_pair(true, as_human_string(from_id)); if (mask && ! key) @@ -1045,13 +1103,15 @@ UserKeyRequirement::as_human_string(const std::shared_ptr<const PackageID> &) co switch (_imp->op) { - case '=': + case ukro_equal: return "Key " + key_str + " has simple string value '" + _imp->value + "'"; - case '<': + case ukro_not_equal: + return "Key " + key_str + " has a different string value than'" + _imp->value + "'"; + case ukro_less_or_subset: return "Key " + key_str + " contains or is less than '" + _imp->value + "'"; - case '>': + case ukro_greater: return "Key " + key_str + " is greater than '" + _imp->value + "'"; - case '?': + case ukro_exists: return "Key " + key_str + " exists"; } @@ -1061,7 +1121,22 @@ UserKeyRequirement::as_human_string(const std::shared_ptr<const PackageID> &) co const std::string UserKeyRequirement::as_raw_string() const { - return "[." + _imp->key + std::string(1, _imp->op) + _imp->value + "]"; + std::string op_string = ""; + switch (_imp->op) + { + case ukro_equal: + return "[." + _imp->key + "=" + _imp->value + "]"; + case ukro_not_equal: + return "[." + _imp->key + "!=" + _imp->value + "]"; + case ukro_less_or_subset: + return "[." + _imp->key + "<" + _imp->value + "]"; + case ukro_greater: + return "[." + _imp->key + ">" + _imp->value + "]"; + case ukro_exists: + return "[." + _imp->key + "?" + _imp->value + "]"; + } + + throw InternalError(PALUDIS_HERE, "unknown op"); } Tribool diff --git a/paludis/user_dep_spec.se b/paludis/user_dep_spec.se index a48f5ba5d..568fd6794 100644 --- a/paludis/user_dep_spec.se +++ b/paludis/user_dep_spec.se @@ -1,6 +1,26 @@ #!/usr/bin/env bash # vim: set sw=4 sts=4 et ft=sh : +make_enum_UserKeyRequirementOperator() +{ + prefix ukro + + key ukro_equal "'=' : Matches if key is equal to value, only ever matches for simple values, sets and sequences" + key ukro_not_equal "'!=' : Matches if key is not equal to value, only ever matches for simple values, sets and sequences" + key ukro_greater "'>' : Matches if key is greater-than value, only ever matches for numeric values" + key ukro_less_or_subset "'<' : Matches if key is less-than value for numeric values or if values is part-of key for sets, sequences and spec trees" + key ukro_exists "'?' : Matches only if the specified key exists, takes no value" + + doxygen_comment << "END" + /** + * Comparators for UserKeyRequirement. + * + * \ingroup g_dep_spec + * \since 1.0.1 + */ +END +} + make_enum_UserPackageDepSpecOption() { prefix updso diff --git a/paludis/user_dep_spec_TEST.cc b/paludis/user_dep_spec_TEST.cc index a5fbf9ea5..7b3cc6352 100644 --- a/paludis/user_dep_spec_TEST.cc +++ b/paludis/user_dep_spec_TEST.cc @@ -244,6 +244,12 @@ TEST_F(UserDepSpecTest, Parsing) PackageDepSpec r(parse_user_package_dep_spec("foo/bar[.$short_description=value]", &env, { })); check_spec(r, "foo/bar", "", "", "", "", "", "", "", "[.$short_description=value]"); + + PackageDepSpec s(parse_user_package_dep_spec("foo/bar[.key!=value]", &env, { })); + check_spec(s, "foo/bar", "", "", "", "", "", "", "", "[.key!=value]"); + + PackageDepSpec t(parse_user_package_dep_spec("foo/bar[.$short_description!=value]", &env, { })); + check_spec(t, "foo/bar", "", "", "", "", "", "", "", "[.$short_description!=value]"); } TEST_F(UserDepSpecTest, Unspecified) @@ -485,5 +491,20 @@ TEST_F(UserDepSpecTest, Keys) PackageDepSpec s(parse_user_package_dep_spec("cat/pkg1[.::format=e]", &env, { })); EXPECT_TRUE(! match_package(env, s, pkg1, make_null_shared_ptr(), { })); + + PackageDepSpec t(parse_user_package_dep_spec("cat/pkg1[.HITCHHIKER!=42]", &env, { })); + EXPECT_TRUE(! match_package(env, t, pkg1, make_null_shared_ptr(), { })); + + PackageDepSpec u(parse_user_package_dep_spec("cat/pkg1[.::$format!=fake]", &env, { })); + EXPECT_TRUE(! match_package(env, u, pkg1, make_null_shared_ptr(), { })); + + PackageDepSpec v(parse_user_package_dep_spec("cat/pkg1[.::$format!=e]", &env, { })); + EXPECT_TRUE(match_package(env, v, pkg1, make_null_shared_ptr(), { })); + + PackageDepSpec w(parse_user_package_dep_spec("cat/pkg1[.::format!=fake]", &env, { })); + EXPECT_TRUE(! match_package(env, w, pkg1, make_null_shared_ptr(), { })); + + PackageDepSpec x(parse_user_package_dep_spec("cat/pkg1[.::format!=e]", &env, { })); + EXPECT_TRUE(match_package(env, x, pkg1, make_null_shared_ptr(), { })); } |