aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-09-05 16:12:31 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-09-05 16:12:31 +0100
commit3d3f7de28d545a9199adb7e953b5a0ced2b01701 (patch)
tree9946d328b1e1a553429a7982b36647c301dbc7e6
parent91a77a7156f6a730097393abae5a43b11f8a7e5a (diff)
parenta4cb561d69f5f6f9e464e78f5b82ba829ecaa32f (diff)
downloadpaludis-3d3f7de28d545a9199adb7e953b5a0ced2b01701.tar.gz
paludis-3d3f7de28d545a9199adb7e953b5a0ced2b01701.tar.xz
Merge branch 'user-dep-spec-qmark'
-rw-r--r--doc/configuration/specs.html.part14
-rw-r--r--paludis/user_dep_spec.cc106
-rw-r--r--paludis/user_dep_spec_TEST.cc31
3 files changed, 141 insertions, 10 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part
index 9903a35..ed37606 100644
--- a/doc/configuration/specs.html.part
+++ b/doc/configuration/specs.html.part
@@ -25,18 +25,30 @@ the following order:</p>
<ul>
<li><code>:slot</code>: Match only in that slot.</li>
+
<li><code>::repo-&gt;repo</code>: Repository requirements, described below.</li>
+
<li><code>::something</code>: like <code>::-&gt;something</code>, for all legal values of something.</li>
+
<li><code>[use]</code> and <code>[-use]</code>: Match only if the named USE flag is enabled / disabled for this
package. May be specified multiple times with different USE flag names.</li>
+
<li><code>[=1.23]</code>: Match a particular version. Any operator described below
can be used. May be extended to ranged dependencies, using either <code>[=1.23|=1.24|=1.25]</code> for an or
dependency or <code>[&gt;=1.2&amp;&lt;2]</code> for an and dependency.</li>
+
+ <li><code>[.key?]</code>: Match only if the specified metadata key exists. <code>key</code> may be a key's raw
+ name (e.g. <code>DESCRIPTION</code>, <code>DEPEND</code>) or a role prefixed with a dollar sign (e.g.
+ <code>$short_description</code>, <code>$build_dependencies</code>). If the key's name is prefixed with
+ <code>::</code>, metadata from the repository rather than the package ID is checked.</li>
+
<li><code>[.key=value]</code>: Match only if the specified metadata key has a particular exact value. Only works for
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.</li>
+ 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>
</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 ed516e0..61ec80d 100644
--- a/paludis/user_dep_spec.cc
+++ b/paludis/user_dep_spec.cc
@@ -356,13 +356,16 @@ namespace paludis
Imp(const std::string & s)
{
- std::string::size_type p(s.find_first_of("=<>"));
+ std::string::size_type p(s.find_first_of("=<>?"));
if (std::string::npos == p)
- throw PackageDepSpecError("Expected an =, a < or a > inside '[." + s + "]'");
+ throw PackageDepSpecError("Expected an =, a <, a > or a ? inside '[." + s + "]'");
key = s.substr(0, p);
value = s.substr(p + 1);
op = s.at(p);
+
+ if (op == '?' && ! value.empty())
+ throw PackageDepSpecError("Operator '?' takes no value inside '[." + s + "]'");
}
};
}
@@ -755,25 +758,110 @@ UserKeyRequirement::requirement_met(const Environment * const, const ChangedChoi
{
Context context("When working out whether '" + stringify(id) + "' matches " + as_raw_string() + ":");
- PackageID::MetadataConstIterator m(id.find_metadata(_imp->key));
- if (m == id.end_metadata())
+ const MetadataKey * key(0);
+
+ if (0 == _imp->key.compare(0, 3, "::$"))
+ {
+ if (_imp->key == "::$format")
+ key = id.repository()->format_key().get();
+ else if (_imp->key == "::$location")
+ key = id.repository()->location_key().get();
+ else if (_imp->key == "::$installed_root")
+ key = id.repository()->installed_root_key().get();
+ else if (_imp->key == "::$accept_keywords")
+ key = id.repository()->accept_keywords_key().get();
+ else if (_imp->key == "::$sync_host")
+ key = id.repository()->sync_host_key().get();
+ }
+ else if (0 == _imp->key.compare(0, 1, "$"))
+ {
+ if (_imp->key == "$behaviours")
+ key = id.behaviours_key().get();
+ else if (_imp->key == "$build_dependencies")
+ key = id.build_dependencies_key().get();
+ else if (_imp->key == "$choices")
+ key = id.choices_key().get();
+ else if (_imp->key == "$contained_in")
+ key = id.contained_in_key().get();
+ else if (_imp->key == "$contains")
+ key = id.contains_key().get();
+ else if (_imp->key == "$contents")
+ key = id.contents_key().get();
+ else if (_imp->key == "$dependencies")
+ key = id.dependencies_key().get();
+ else if (_imp->key == "$fetches")
+ key = id.fetches_key().get();
+ else if (_imp->key == "$from_repositories")
+ key = id.from_repositories_key().get();
+ else if (_imp->key == "$fs_location")
+ key = id.fs_location_key().get();
+ else if (_imp->key == "$homepage")
+ key = id.homepage_key().get();
+ else if (_imp->key == "$installed_time")
+ key = id.installed_time_key().get();
+ else if (_imp->key == "$keywords")
+ key = id.keywords_key().get();
+ else if (_imp->key == "$long_description")
+ key = id.long_description_key().get();
+ else if (_imp->key == "$post_dependencies")
+ key = id.post_dependencies_key().get();
+ else if (_imp->key == "$provide")
+ key = id.provide_key().get();
+ else if (_imp->key == "$run_dependencies")
+ key = id.run_dependencies_key().get();
+ else if (_imp->key == "$short_description")
+ key = id.short_description_key().get();
+ else if (_imp->key == "$slot")
+ key = id.slot_key().get();
+ else if (_imp->key == "$suggested_dependencies")
+ key = id.suggested_dependencies_key().get();
+ else if (_imp->key == "$virtual_for")
+ key = id.virtual_for_key().get();
+ }
+ else if (0 == _imp->key.compare(0, 2, "::"))
+ {
+ Repository::MetadataConstIterator m(id.repository()->find_metadata(_imp->key.substr(2)));
+ if (m != id.repository()->end_metadata())
+ key = m->get();
+ }
+ else
+ {
+ PackageID::MetadataConstIterator m(id.find_metadata(_imp->key));
+ if (m != id.end_metadata())
+ key = m->get();
+ }
+
+ if (! key)
return std::make_pair(false, as_human_string());
- KeyComparator c(_imp->value, _imp->op);
- return std::make_pair((*m)->accept_returning<bool>(c), as_human_string());
+ if (_imp->op == '?')
+ return std::make_pair(true, as_human_string());
+ else
+ {
+ KeyComparator c(_imp->value, _imp->op);
+ return std::make_pair(key->accept_returning<bool>(c), as_human_string());
+ }
}
const std::string
UserKeyRequirement::as_human_string() const
{
+ std::string key_str;
+ if ((! _imp->key.empty()) && (_imp->key.at(0) == '$'))
+ key_str = "with role '" + _imp->key.substr(1) + "'";
+ else
+ key_str = "'" + _imp->key + "'";
+
switch (_imp->op)
{
case '=':
- return "Key '" + _imp->key + "' has simple string value '" + _imp->value + "'";
+ return "Key " + key_str + " has simple string value '" + _imp->value + "'";
case '<':
- return "Key '" + _imp->key + "' contains or is less than '" + _imp->value + "'";
+ return "Key " + key_str + " contains or is less than '" + _imp->value + "'";
case '>':
- return "Key '" + _imp->key + "' is greater than '" + _imp->value + "'";
+ return "Key " + key_str + " is greater than '" + _imp->value + "'";
+ case '?':
+ return "Key " + key_str + " exists";
}
throw InternalError(PALUDIS_HERE, "unknown op");
diff --git a/paludis/user_dep_spec_TEST.cc b/paludis/user_dep_spec_TEST.cc
index 5d02404..dff1e3d 100644
--- a/paludis/user_dep_spec_TEST.cc
+++ b/paludis/user_dep_spec_TEST.cc
@@ -225,6 +225,14 @@ namespace test_cases
PackageDepSpec p(parse_user_package_dep_spec("foo/bar[.key=value]", &env, { }));
check_spec(p, "foo/bar", "", "", "", "", "", "", "", "[.key=value]");
+
+ TEST_CHECK_THROWS(parse_user_package_dep_spec("=foo/bar[.foo?q]", &env, { }), PackageDepSpecError);
+
+ PackageDepSpec q(parse_user_package_dep_spec("foo/bar[.foo?]", &env, { }));
+ check_spec(q, "foo/bar", "", "", "", "", "", "", "", "[.foo?]");
+
+ PackageDepSpec r(parse_user_package_dep_spec("foo/bar[.$short_description=value]", &env, { }));
+ check_spec(r, "foo/bar", "", "", "", "", "", "", "", "[.$short_description=value]");
}
} test_user_package_dep_spec;
@@ -468,6 +476,29 @@ namespace test_cases
PackageDepSpec l(parse_user_package_dep_spec("cat/pkg1[.HITCHHIKER>41]", &env, { }));
TEST_CHECK(match_package(env, l, *pkg1, { }));
+
+ PackageDepSpec m(parse_user_package_dep_spec("cat/pkg1[.HITCHHIKER?]", &env, { }));
+ TEST_CHECK(match_package(env, m, *pkg1, { }));
+
+ PackageDepSpec n(parse_user_package_dep_spec("cat/pkg1[.SPOON?]", &env, { }));
+ TEST_CHECK(! match_package(env, n, *pkg1, { }));
+
+ PackageDepSpec o(parse_user_package_dep_spec("cat/pkg1[.$keywords<~a]", &env, { }));
+ TEST_CHECK(match_package(env, o, *pkg1, { }));
+ TEST_CHECK(match_package(env, o, *pkg2, { }));
+ TEST_CHECK(! match_package(env, o, *pkg3, { }));
+
+ PackageDepSpec p(parse_user_package_dep_spec("cat/pkg1[.::$format=fake]", &env, { }));
+ TEST_CHECK(match_package(env, p, *pkg1, { }));
+
+ PackageDepSpec q(parse_user_package_dep_spec("cat/pkg1[.::$format=e]", &env, { }));
+ TEST_CHECK(! match_package(env, q, *pkg1, { }));
+
+ PackageDepSpec r(parse_user_package_dep_spec("cat/pkg1[.::format=fake]", &env, { }));
+ TEST_CHECK(match_package(env, r, *pkg1, { }));
+
+ PackageDepSpec s(parse_user_package_dep_spec("cat/pkg1[.::format=e]", &env, { }));
+ TEST_CHECK(! match_package(env, s, *pkg1, { }));
}
} test_user_package_dep_spec_user_key_req;
}