diff options
author | Daniel Burrows <dburrows@debian.org> | 2008-08-31 19:17:44 -0700 |
---|---|---|
committer | Daniel Burrows <dburrows@debian.org> | 2008-08-31 19:17:44 -0700 |
commit | b15362e3ba1fe8f15ca06c83dcaac5cf1b6d143f (patch) | |
tree | 3d7e11e46fd907a3ad4ede8e611b986f8dd53323 | |
parent | 13d7de96d3586e6d2e0b23b9a6867ea891249145 (diff) | |
download | aptitude-b15362e3ba1fe8f15ca06c83dcaac5cf1b6d143f.tar.gz |
Add support for separately customizing the sub-policies of the branches of a pattern policy.
The syntax looks something like this:
pattern(matcher => title {policy}, matcher {policy}, matcher || {policy})
-rw-r--r-- | doc/en/aptitude.xml | 69 | ||||
-rw-r--r-- | src/load_grouppolicy.cc | 96 | ||||
-rw-r--r-- | src/pkg_grouppolicy.cc | 26 | ||||
-rw-r--r-- | src/pkg_grouppolicy.h | 30 |
4 files changed, 183 insertions, 38 deletions
diff --git a/doc/en/aptitude.xml b/doc/en/aptitude.xml index 7ece47bf..1d9e0c3b 100644 --- a/doc/en/aptitude.xml +++ b/doc/en/aptitude.xml @@ -6422,7 +6422,7 @@ iuAU wesnoth-data +930kB 0.8.7-1 0.8.8-1.0w </varlistentry> <varlistentry> - <term><synopsis>pattern(<replaceable>pattern</replaceable> <optional>=> <replaceable>title</replaceable></optional><optional>, ...</optional>)</synopsis></term> + <term><synopsis>pattern(<replaceable>pattern</replaceable> <optional>=> <replaceable>title</replaceable></optional> <optional>{ <replaceable>policy</replaceable> }</optional> <optional>, ...</optional>)</synopsis></term> <listitem> <para> @@ -6437,7 +6437,10 @@ iuAU wesnoth-data +930kB 0.8.7-1 0.8.8-1.0w <replaceable>title</replaceable> will be replaced by the Nth result of the match. If <replaceable>title</replaceable> is not present, it - is assumed to be <literal>\1</literal>. + is assumed to be <literal>\1</literal>. Note that + packages which do not match any + <replaceable>pattern</replaceable>s will not appear + in the tree at all. </para> <para> @@ -6462,12 +6465,68 @@ iuAU wesnoth-data +930kB 0.8.7-1 0.8.8-1.0w <literal>pattern(&Saction;(remove) => Packages Being Removed, &Strue; ||)</literal> will place packages that are being removed into a subtree, and place all - the other packages at the current level. Any later - grouping policies will apply to both sets of - packages, of course. + the other packages at the current level, grouped + according to the policies that follow + <literal>pattern</literal>. </para> <para> + By default, all the packages that match each pattern + are grouped according to the rules that follow the + <literal>pattern</literal> policy. To specify a + different policy for some packages, write the policy + in braces (<literal>{}</literal>) after the title of + the group, after the <literal>||</literal>, or after + the pattern if neither is present. For instance: + </para> + + <example id='examplePatternGroupingPolicyWithSubPolicies'> + <title> + Use of the <literal>pattern</literal> grouping policy with sub-policies + </title> + + <para> + <literal>pattern(&Saction;(remove) => Packages + Being Removed {}, &Saction;(install) => Packages + Being Installed, &Strue; || {status})</literal> + </para> + </example> + + <para> + The policy in the above example has the following + effects: + </para> + + <itemizedlist> + <listitem> + <para> + Packages that are being removed are placed into + a subtree labeled <quote>Packages Being + Removed</quote>; the grouping policy for this + subtree is empty, so the packages are placed + into a flat list. + </para> + </listitem> + + <listitem> + <para> + Packages that are being installed are placed + into a subtree labeled <literal>Packages Being + Installed</literal> and grouped according to the + policies that follow <literal>pattern</literal>. + </para> + </listitem> + + <listitem> + <para> + All remaining packages are placed at the top + level of the tree, grouped according to their + status. + </para> + </listitem> + </itemizedlist> + + <para> See <xref linkend='secSearchPatterns'/> for more information on the format of <replaceable>pattern</replaceable>. diff --git a/src/load_grouppolicy.cc b/src/load_grouppolicy.cc index 8ee6e469..c88ce4c4 100644 --- a/src/load_grouppolicy.cc +++ b/src/load_grouppolicy.cc @@ -107,6 +107,14 @@ public: const string::const_iterator &end)=0; }; +/** \brief A global table of all the parsers of group policies + * according to their names. + * + * Used to parse group policy lists; could actually just as well be a + * member of the list parser. + */ +static map<string, group_policy_parser *> parse_types; + template<class F> @@ -222,8 +230,14 @@ public: /** Parse a grouping policy based on a list. Looks for policy names, * then starts parsing their parameters as necessary according to a - * table of parsers. Names must be alphanumeric; the occurance - * of a nonalphanumeric at the top level will terminate the parse. + * table of parsers. Names must be alphanumeric; the occurance of a + * nonalphanumeric other than the terminator (see below) at the top + * level will terminate the parse. + * + * The list can be terminated by a distinguished character (typically + * something like ")" or "}"); if this appears where a policy name + * would normally start, it will be consumed and the parser will + * return. */ class list_policy_parser : public group_policy_parser { @@ -232,9 +246,17 @@ public: private: const parsemap &parsers; + const bool allow_terminator; + const char terminator; public: list_policy_parser(const parsemap &_parsers) - :parsers(_parsers) + : parsers(_parsers), allow_terminator(false), terminator(-1) + { + } + + list_policy_parser(const parsemap &_parsers, + char _terminator) + : parsers(_parsers), allow_terminator(true), terminator(_terminator) { } @@ -254,6 +276,14 @@ public: while(begin != end && (isspace(*begin) || *begin == ',')) ++begin; + // If we hit the terminator (e.g., "}" for pattern policies), + // eat it and stop. + if(allow_terminator && begin != end && *begin == terminator) + { + ++begin; + break; + } + if(begin != end && !isalnum(*begin)) throw GroupParseException(_("Expected policy identifier, got '%c'"), *begin); @@ -267,7 +297,16 @@ public: ++begin; if(begin != end && *begin != ',' && *begin != '(') - throw GroupParseException(_("Expected ',' or '(', got '%c'"), *begin); + { + if(allow_terminator) + { + if(*begin != terminator) + throw GroupParseException(_("Expected ',', '%c', or '('; got '%c'"), + terminator, *begin); + } + else + throw GroupParseException(_("Expected ',' or '(', got '%c'"), *begin); + } if(!name.empty()) { @@ -590,7 +629,7 @@ class pattern_policy_parser : public group_policy_parser if(begin == end || *begin == ')') throw GroupParseException(_("Missing arguments to 'pattern'")); - vector<pkg_grouppolicy_matchers_factory::match_pair> subgroups; + vector<pkg_grouppolicy_matchers_factory::match_entry> subgroups; vector<const char *> terminators; terminators.push_back(","); @@ -610,6 +649,7 @@ class pattern_policy_parser : public group_policy_parser false, true, false)); bool passthrough = false; + std::auto_ptr<pkg_grouppolicy_factory> chain; if(matcher.get() == NULL) throw GroupParseException(_("Unable to parse pattern after \"%s\""), @@ -625,10 +665,26 @@ class pattern_policy_parser : public group_policy_parser format.clear(); - while(begin != end && *begin != ',' && *begin != ')') + while(begin != end && *begin != ',' && *begin != ')' && *begin != '{') { format += *begin; - ++begin; + // Allow the user to backslash-escape terminating + // characters. The backslashes are preserved so + // that they can be used to detect substitutions + // (the pattern group policy will handle + // backslashed non-numbers by dropping the + // backslash). + if(*begin == '\\') + { + ++begin; + if(begin != end) + { + format += *begin; + ++begin; + } + } + else + ++begin; } stripws(format); @@ -652,13 +708,27 @@ class pattern_policy_parser : public group_policy_parser if(begin != end) { - if(*begin != ',' && *begin != ')') - throw GroupParseException(_("Expected ',' or ')' following '||', got '%s'"), + if(*begin != ',' && *begin != ')' && *begin != '{') + throw GroupParseException(_("Expected '{', ')', or ',' following '||', got '%s'"), string(begin, begin + 1).c_str()); } } - subgroups.push_back(pkg_grouppolicy_matchers_factory::match_pair(matcher.release(), cw::util::transcode(format), passthrough)); + // A brace-delimited list gives the sub-policy for this + // particular branch. + if(begin != end && *begin == '{') + { + ++begin; + + list_policy_parser subpolicy_tail_parser(parse_types, '}'); + + std::auto_ptr<group_policy_parse_node> + sub_parse_node(subpolicy_tail_parser.parse(begin, end)); + + chain.reset(sub_parse_node->instantiate(NULL)); + } + + subgroups.push_back(pkg_grouppolicy_matchers_factory::match_entry(matcher.release(), chain.release(), cw::util::transcode(format), passthrough)); if(begin != end && *begin == ',') ++begin; @@ -672,11 +742,11 @@ class pattern_policy_parser : public group_policy_parser ++begin; } - return new policy_node1<pkg_grouppolicy_matchers_factory, vector<pkg_grouppolicy_matchers_factory::match_pair> >(subgroups); + return new policy_node1<pkg_grouppolicy_matchers_factory, vector<pkg_grouppolicy_matchers_factory::match_entry> >(subgroups); } catch(...) { - for(vector<pkg_grouppolicy_matchers_factory::match_pair>::const_iterator i = subgroups.begin(); + for(vector<pkg_grouppolicy_matchers_factory::match_entry>::const_iterator i = subgroups.begin(); i != subgroups.end(); ++i) delete i->matcher; @@ -685,8 +755,6 @@ class pattern_policy_parser : public group_policy_parser } }; -static map<string, group_policy_parser *> parse_types; - static void init_parse_types() { static bool initted_parse_types=false; diff --git a/src/pkg_grouppolicy.cc b/src/pkg_grouppolicy.cc index fc4178e5..09bfe2aa 100644 --- a/src/pkg_grouppolicy.cc +++ b/src/pkg_grouppolicy.cc @@ -1135,7 +1135,7 @@ pkg_grouppolicy_task_factory::~pkg_grouppolicy_task_factory() class pkg_grouppolicy_matchers : public pkg_grouppolicy { public: - typedef pkg_grouppolicy_matchers_factory::match_pair match_pair; + typedef pkg_grouppolicy_matchers_factory::match_entry match_entry; struct subtree_pair { @@ -1154,7 +1154,7 @@ public: private: pkg_grouppolicy_factory *chain; pkg_grouppolicy *passthrough_policy; - const vector<match_pair> &subgroups; + const vector<match_entry> &subgroups; typedef map<wstring, subtree_pair> subtree_map; subtree_map subtrees; @@ -1242,7 +1242,7 @@ private: public: pkg_grouppolicy_matchers(pkg_grouppolicy_factory *_chain, pkg_signal *_sig, desc_signal *_desc_sig, - const vector<match_pair> &_subgroups) + const vector<match_entry> &_subgroups) :pkg_grouppolicy(_sig, _desc_sig), chain(_chain), passthrough_policy(NULL), subgroups(_subgroups) @@ -1260,17 +1260,20 @@ public: void add_package(const pkgCache::PkgIterator &pkg, pkg_subtree *root) { - for(vector<match_pair>::const_iterator i = subgroups.begin(); + for(vector<match_entry>::const_iterator i = subgroups.begin(); i != subgroups.end(); ++i) { match::pkg_match_result *res = match::get_match(i->matcher, pkg, *apt_cache_file, *apt_package_records); if(res != NULL) { + pkg_grouppolicy_factory * const local_chain = + i->chain != NULL ? i->chain : chain; + if(i->passthrough) { if(passthrough_policy == NULL) - passthrough_policy = chain->instantiate(get_sig(), - get_desc_sig()); + passthrough_policy = local_chain->instantiate(get_sig(), + get_desc_sig()); passthrough_policy->add_package(pkg, root); break; } @@ -1286,8 +1289,8 @@ public: else { pkg_subtree *tree = new pkg_subtree(title, L"", get_desc_sig()); - pkg_grouppolicy *policy = chain->instantiate(get_sig(), - get_desc_sig()); + pkg_grouppolicy *policy = local_chain->instantiate(get_sig(), + get_desc_sig()); root->add_child(tree); tree->set_num_packages_parent(root); @@ -1310,9 +1313,12 @@ pkg_grouppolicy *pkg_grouppolicy_matchers_factory :: instantiate(pkg_signal *sig pkg_grouppolicy_matchers_factory :: ~pkg_grouppolicy_matchers_factory() { - for(std::vector<match_pair>::const_iterator i = subgroups.begin(); + for(std::vector<match_entry>::const_iterator i = subgroups.begin(); i != subgroups.end(); ++i) - delete i->matcher; + { + delete i->matcher; + delete i->chain; + } delete chain; } diff --git a/src/pkg_grouppolicy.h b/src/pkg_grouppolicy.h index 055a743a..ac595604 100644 --- a/src/pkg_grouppolicy.h +++ b/src/pkg_grouppolicy.h @@ -298,21 +298,33 @@ public: virtual ~pkg_grouppolicy_task_factory(); }; -// Groups packages using the given list of matchers/tree names. Match -// results can be substituted into tree names using \N notation. +/** \brief Groups packages using the given list of matchers/tree names. + * + * Match results can be substituted into tree names using \N + * notation. Each branch of the tree can have its own policy chain; + * if none is specified, the default chain will be used. + */ class pkg_grouppolicy_matchers_factory:public pkg_grouppolicy_factory { public: - struct match_pair + struct match_entry { aptitude::matching::pkg_matcher *matcher; + /** \brief A pointer to the specialized sub-factory for + * this entry, or NULL to use the default chain. + */ + pkg_grouppolicy_factory *chain; std::wstring tree_name; bool passthrough; - match_pair(aptitude::matching::pkg_matcher *_matcher, - const std::wstring &_tree_name, - bool _passthrough) - :matcher(_matcher), tree_name(_tree_name), passthrough(_passthrough) + match_entry(aptitude::matching::pkg_matcher *_matcher, + pkg_grouppolicy_factory *_chain, + const std::wstring &_tree_name, + bool _passthrough) + : matcher(_matcher), + chain(_chain), + tree_name(_tree_name), + passthrough(_passthrough) { } }; @@ -320,10 +332,10 @@ public: private: pkg_grouppolicy_factory *chain; - std::vector<match_pair> subgroups; + std::vector<match_entry> subgroups; public: - pkg_grouppolicy_matchers_factory(const std::vector<match_pair> &_subgroups, + pkg_grouppolicy_matchers_factory(const std::vector<match_entry> &_subgroups, pkg_grouppolicy_factory *_chain) :chain(_chain), subgroups(_subgroups) { |