aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Benedikt Morbach <moben@exherbo.org> 2013-03-05 02:29:11 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2013-03-08 12:53:36 +0000
commit26c5ed12c5067a5d83437197379f65dfc4a06fcc (patch)
treee75ddf436c24efe12cdd08291056a12b5cb0da5a
parentcab157fad7e41ec29d3989d3aebaefbf202de6bd (diff)
downloadpaludis-26c5ed12c5067a5d83437197379f65dfc4a06fcc.tar.gz
paludis-26c5ed12c5067a5d83437197379f65dfc4a06fcc.tar.xz
UserKeyRequirement: allow matching metadata for inequality
only for simple values. Note that this changes behaviour in the following way: Previously, any of '><=' would be treated as '='. Now, only '=' and '!' are respected and '<' and '>' always return false. The only simple value key which still takes all operators is <long> because there it makes sense.
-rw-r--r--doc/configuration/specs.html.part6
-rw-r--r--paludis/user_dep_spec.cc175
-rw-r--r--paludis/user_dep_spec.se20
-rw-r--r--paludis/user_dep_spec_TEST.cc21
4 files changed, 169 insertions, 53 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part
index ad3758e..05372dc 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>&lt;</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>&gt;</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-&gt;</code> or <code>::from-&gt;to</code>. The
diff --git a/paludis/user_dep_spec.cc b/paludis/user_dep_spec.cc
index 0281016..322db4e 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 a48f5ba..568fd67 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 a5fbf9e..7b3cc63 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(), { }));
}