summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Burrows <dburrows@debian.org>2008-08-31 19:17:44 -0700
committerDaniel Burrows <dburrows@debian.org>2008-08-31 19:17:44 -0700
commitb15362e3ba1fe8f15ca06c83dcaac5cf1b6d143f (patch)
tree3d7e11e46fd907a3ad4ede8e611b986f8dd53323
parent13d7de96d3586e6d2e0b23b9a6867ea891249145 (diff)
downloadaptitude-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.xml69
-rw-r--r--src/load_grouppolicy.cc96
-rw-r--r--src/pkg_grouppolicy.cc26
-rw-r--r--src/pkg_grouppolicy.h30
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)
{