diff options
author | 2010-09-05 16:12:31 +0100 | |
---|---|---|
committer | 2010-09-05 16:12:31 +0100 | |
commit | 3d3f7de28d545a9199adb7e953b5a0ced2b01701 (patch) | |
tree | 9946d328b1e1a553429a7982b36647c301dbc7e6 | |
parent | 91a77a7156f6a730097393abae5a43b11f8a7e5a (diff) | |
parent | a4cb561d69f5f6f9e464e78f5b82ba829ecaa32f (diff) | |
download | paludis-3d3f7de28d545a9199adb7e953b5a0ced2b01701.tar.gz paludis-3d3f7de28d545a9199adb7e953b5a0ced2b01701.tar.xz |
Merge branch 'user-dep-spec-qmark'
-rw-r--r-- | doc/configuration/specs.html.part | 14 | ||||
-rw-r--r-- | paludis/user_dep_spec.cc | 106 | ||||
-rw-r--r-- | paludis/user_dep_spec_TEST.cc | 31 |
3 files changed, 141 insertions, 10 deletions
diff --git a/doc/configuration/specs.html.part b/doc/configuration/specs.html.part index 9903a35a0..ed376066f 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->repo</code>: Repository requirements, described below.</li> + <li><code>::something</code>: like <code>::->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>[>=1.2&<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><</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.</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-></code> or <code>::from->to</code>. The diff --git a/paludis/user_dep_spec.cc b/paludis/user_dep_spec.cc index ed516e064..61ec80d66 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 5d024047e..dff1e3d72 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; } |