[Aptitude-svn-commit] r3671 - in branches/aptitude-0.3/aptitude: . doc/en src src/generic

Daniel Burrows dburrows at costa.debian.org
Mon Jul 25 17:37:27 UTC 2005


Author: dburrows
Date: Mon Jul 25 17:37:23 2005
New Revision: 3671

Added:
   branches/aptitude-0.3/aptitude/src/generic/util.cc
   branches/aptitude-0.3/aptitude/src/generic/util.h
Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/doc/en/aptitude.xml
   branches/aptitude-0.3/aptitude/src/generic/Makefile.am
   branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc
   branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.cc
   branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h
Log:
Implement generic grouping policy magic (first cut).

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Mon Jul 25 17:37:23 2005
@@ -1,5 +1,11 @@
 2005-07-25  Daniel Burrows  <dburrows at debian.org>
 
+	* doc/en/aptitude.xml, src/load_grouppolicy.cc, src/pkg_grouppolicy.cc, src/pkg_grouppolicy.h, src/generic/Makefile.am, src/generic/util.cc, src/generic/util.h:
+
+	  Add a "patterns" grouping policy and start a long-overdue
+	  collection of generic utility routines to kill off some of my
+	  duplication of code. (Closes: #156065)
+
 	* src/generic/matchers.cc:
 
 	  Match anything with an empty pattern.

Modified: branches/aptitude-0.3/aptitude/doc/en/aptitude.xml
==============================================================================
--- branches/aptitude-0.3/aptitude/doc/en/aptitude.xml	(original)
+++ branches/aptitude-0.3/aptitude/doc/en/aptitude.xml	Mon Jul 25 17:37:23 2005
@@ -4295,6 +4295,42 @@
 	    </varlistentry>
 
 	    <varlistentry>
+	      <term><synopsis>pattern(<replaceable>pattern</replaceable> <optional>=> <replaceable>title</replaceable></optional><optional>, ...</optional>)</synopsis></term>
+
+	      <listitem>
+		<para>
+		  A customizable grouping policy.  Each version of
+		  every package is matched against the given
+		  <replaceable>pattern</replaceable>s.  The first
+		  match found is used to assign a
+		  <replaceable>title</replaceable> to the package;
+		  packages are then grouped by their
+		  <replaceable>title</replaceable>.  Strings of the
+		  form <literal>\N</literal> that occur in
+		  <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>.
+		</para>
+
+		<para>
+		  For instance, <literal>pattern(~m => \1)</literal>
+		  will group packages according to their Maintainer
+		  field.  The policy <literal>pattern(~m)</literal>
+		  will do the same thing, as the absent
+		  <replaceable>title</replaceable> defaults to
+		  <literal>\1</literal>.
+		</para>
+
+		<para>
+		  See the section <xref linkend='secSearchPatterns'/>
+		  for more information on the format of
+		  <replaceable>pattern</replaceable>.
+		</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
 	      <term><synopsis>priority</synopsis></term>
 
 	      <listitem>
@@ -4305,7 +4341,7 @@
 	    </varlistentry>
 
 	    <varlistentry>
-	      <term><synopsis>section[(<replaceable>mode</replaceable>[,passthrough])]</synopsis></term>
+	      <term><synopsis>section<optional>(<replaceable>mode</replaceable><optional>,passthrough</optional>)</optional></synopsis></term>
 
 	      <listitem>
 		<para>

Modified: branches/aptitude-0.3/aptitude/src/generic/Makefile.am
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/Makefile.am	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/Makefile.am	Mon Jul 25 17:37:23 2005
@@ -45,7 +45,9 @@
 	tasks.h		\
 	tasks.cc	\
 	undo.h		\
-	undo.cc
+	undo.cc		\
+	util.h		\
+	util.cc
 
 pkg_hier_dump_SOURCES=	\
 	pkg_hier_dump.cc

Added: branches/aptitude-0.3/aptitude/src/generic/util.cc
==============================================================================
--- (empty file)
+++ branches/aptitude-0.3/aptitude/src/generic/util.cc	Mon Jul 25 17:37:23 2005
@@ -0,0 +1,41 @@
+// util.cc
+//
+//   Copyright (C) 2005 Daniel Burrows
+//
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of the GNU General Public License as
+//   published by the Free Software Foundation; either version 2 of
+//   the License, or (at your option) any later version.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//   General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public License
+//   along with this program; see the file COPYING.  If not, write to
+//   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+//   Boston, MA 02111-1307, USA.
+
+#include "util.h"
+
+#include <ctype.h>
+
+using namespace std;
+
+void stripws(string &s)
+{
+  size_t start = 0;
+  while(start < s.size() && isspace(s[start]))
+    ++start;
+
+  size_t end = s.size();
+  while(end > 0 && isspace(s[end-1]))
+    --end;
+
+  if(start >= end)
+    s.clear();
+  else
+    s.assign(s, start, end-start);
+}
+

Added: branches/aptitude-0.3/aptitude/src/generic/util.h
==============================================================================
--- (empty file)
+++ branches/aptitude-0.3/aptitude/src/generic/util.h	Mon Jul 25 17:37:23 2005
@@ -0,0 +1,28 @@
+// Random utility functions that have nothing to do with apt. -*-c++-*-
+//
+//   Copyright (C) 2005 Daniel Burrows
+//
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of the GNU General Public License as
+//   published by the Free Software Foundation; either version 2 of
+//   the License, or (at your option) any later version.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//   General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public License
+//   along with this program; see the file COPYING.  If not, write to
+//   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+//   Boston, MA 02111-1307, USA.
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <string>
+
+// Strip whitespace from the beginning and end of a string.
+void stripws(std::string &s);
+
+#endif

Modified: branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/load_grouppolicy.cc	Mon Jul 25 17:37:23 2005
@@ -9,11 +9,11 @@
 // The parsers take an arglist and a chain argument, and return either a
 // new pkg_grouppolicy_factory, or (if an error was encountered) NULL.
 // (note: the chain argument will be NULL if the policy is the tail of a list)
-// Yes, I don't believe in C++ exceptions.
 
 #include "load_grouppolicy.h"
 
 #include <generic/pkg_hier.h>
+#include <generic/util.h>
 
 #include "aptitude.h"
 
@@ -237,6 +237,86 @@
   return new pkg_grouppolicy_task_factory(chain);
 }
 
+static pkg_grouppolicy_factory *parse_matchers_policy(const arglist &args,
+						      pkg_grouppolicy_factory *chain)
+{
+  if(args.size() == 0)
+    {
+      _error->Error(_("Match-based grouping policies require at least one parameter"));
+      return NULL;
+    }
+
+  vector<pkg_grouppolicy_matchers_factory :: match_pair> subgroups;
+
+  for(arglist::const_iterator i = args.begin();
+      i != args.end(); ++i)
+    {
+      // Split each argument at the first occurance of "=>".
+      string matcher, format="\\1";
+      bool in_matcher=true;
+
+      string::const_iterator j = i->begin();
+
+      while(j != i->end() && in_matcher)
+	{
+	  while(j != i->end() && *j != '=')
+	    {
+	      matcher+=*j;
+	      ++j;
+	    }
+
+	  if(j != i->end())
+	    {
+	      assert((*j) == '=');
+
+	      ++j;
+
+	      if(j == i->end() || *j != '>')
+		matcher += '=';
+	      else
+		{
+		  ++j;
+		  in_matcher = false;
+		}
+	    }
+	}
+
+      if(!in_matcher)
+	{
+	  format.clear();
+
+	  while(j != i->end())
+	    {
+	      format += *j;
+	      ++j;
+	    }
+	}
+
+      assert(j == i->end());
+
+      stripws(format);
+      stripws(matcher);
+
+      pkg_matcher *m = parse_pattern(matcher);
+
+      if(m == NULL)
+	{
+	  for(vector<pkg_grouppolicy_matchers_factory :: match_pair> :: const_iterator i = subgroups.begin();
+	      i != subgroups.end(); ++i)
+	    delete i->matcher;
+
+	  return NULL;
+	}
+
+      subgroups.push_back(pkg_grouppolicy_matchers_factory :: match_pair(m, transcode(format)));
+    }
+
+  if(!chain)
+    chain = new pkg_grouppolicy_end_factory;
+
+  return new pkg_grouppolicy_matchers_factory(chain, subgroups);
+}
+
 static parser_map parse_types;
 
 static void init_parse_types()
@@ -257,6 +337,8 @@
       parse_types["hier"]=parse_hier_policy;
       parse_types["task"]=parse_task_policy;
 
+      parse_types["pattern"]=parse_matchers_policy;
+
       initted_parse_types=true;
     }
 }
@@ -307,8 +389,6 @@
 	}
 
       parsed.push_back(current);
-      // Ew, takes kinda long.  Probably not an issue now, but creating current
-      // as a new item in parsed would be faster.
 
       if(i<s.size() && s[i]==',')
 	i++; // Clear out trailing commas.

Modified: branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.cc	Mon Jul 25 17:37:23 2005
@@ -28,6 +28,7 @@
 #include <vscreen/transcode.h>
 
 #include "generic/apt.h"
+#include "generic/matchers.h"
 #include "generic/pkg_hier.h"
 #include "generic/tasks.h"
 
@@ -999,3 +1000,170 @@
 {
   delete chain;
 }
+
+
+class pkg_grouppolicy_matchers : public pkg_grouppolicy
+{
+public:
+  typedef pkg_grouppolicy_matchers_factory::match_pair match_pair;
+
+  struct subtree_pair
+  {
+    pkg_grouppolicy *policy;
+    pkg_subtree *tree;
+
+    subtree_pair():policy(NULL), tree(NULL)
+    {
+    }
+
+    subtree_pair(pkg_grouppolicy *_policy, pkg_subtree *_tree)
+      :policy(_policy), tree(_tree)
+    {
+    }
+  };
+private:
+  pkg_grouppolicy_factory *chain;
+  const vector<match_pair> &subgroups;
+  typedef map<wstring, subtree_pair> subtree_map;
+  subtree_map subtrees;
+
+  wstring substitute(const wstring &s,
+		     pkg_match_result *res)
+  {
+    wstring rval;
+
+    wstring::const_iterator i = s.begin();
+    while(i != s.end())
+      {
+	while(i != s.end() && *i != L'\\')
+	  {
+	    rval += *i;
+	    ++i;
+	  }
+
+	if(i != s.end())
+	  {
+	    ++i;
+	    if(i == s.end())
+	      rval += L'\\';
+	    else if(*i == L'\\')
+	      {
+		rval += L'\\';
+		++i;
+	      }
+	    else if(iswdigit(*i))
+	      {
+		wstring tocvt;
+
+		while(i != s.end() && iswdigit(*i))
+		  {
+		    tocvt += *i;
+		    ++i;
+		  }
+
+		wchar_t *endptr = NULL;
+		unsigned long val = wcstoul(tocvt.c_str(), &endptr, 0);
+
+		if(endptr && (*endptr) != L'\0')
+		  {
+		    wchar_t buf[512];
+
+		    swprintf(buf, 512, transcode(_("Bad number in format string: %ls")).c_str(),
+			     tocvt.c_str());
+
+		    return buf;
+		  }
+
+		if(val < 1)
+		  {
+		    wchar_t buf[512];
+		    swprintf(buf, 512, transcode(_("Match indices must be 1 or greater, not \"%s\"")).c_str(),
+			     tocvt.c_str());
+		    return buf;
+		  }
+
+		--val;
+
+		if(val >= res->num_groups())
+		  {
+		    string group_values;
+		    for(unsigned int i = 0; i<res->num_groups(); ++i)
+		      {
+			if(i > 0)
+			  group_values += ",";
+			group_values += res->group(i);
+		      }
+
+		    wchar_t buf[1024];
+		    swprintf(buf, 1024, transcode(_("Match index %ls is too large; available groups are (%s)")).c_str(),
+			     tocvt.c_str(), group_values.c_str());
+
+		    return buf;
+		  }
+
+		rval += transcode(res->group(val));
+	      }
+	  }
+      }
+
+    return rval;
+  }
+public:
+  pkg_grouppolicy_matchers(pkg_grouppolicy_factory *_chain,
+			   pkg_signal *_sig, desc_signal *_desc_sig,
+			   const vector<match_pair> &_subgroups)
+        :pkg_grouppolicy(_sig, _desc_sig),
+	 chain(_chain), subgroups(_subgroups)
+  {
+  }
+
+  ~pkg_grouppolicy_matchers()
+  {
+    for(subtree_map::const_iterator i = subtrees.begin();
+	i != subtrees.end(); ++i)
+      delete i->second.policy;
+  }
+
+  void add_package(const pkgCache::PkgIterator &pkg,
+		   pkg_subtree *root)
+  {
+    for(vector<match_pair>::const_iterator i = subgroups.begin();
+	i != subgroups.end(); ++i)
+      for(pkgCache::VerIterator ver = pkg.VersionList(); !ver.end();
+	  ++ver)
+	{
+	  pkg_match_result *res = i->matcher->get_match(pkg, ver);
+	  if(res != NULL)
+	    {
+	      wstring title = substitute(i->tree_name, res);
+	      delete res;
+
+	      subtree_map::const_iterator found =
+		subtrees.find(title);
+
+	      if(found != subtrees.end())
+		found->second.policy->add_package(pkg, found->second.tree);
+	      else
+		{
+		  pkg_subtree *tree = new pkg_subtree(title);
+		  pkg_grouppolicy *policy = chain->instantiate(get_sig(),
+							       get_desc_sig());
+		  root->add_child(tree);
+
+		  subtrees[title]=subtree_pair(policy, tree);
+		}
+	    }
+	}
+  }
+};
+
+pkg_grouppolicy *pkg_grouppolicy_matchers_factory :: instantiate(pkg_signal *sig,
+								 desc_signal *_desc_sig)
+{
+  return new pkg_grouppolicy_matchers(chain, sig, _desc_sig, subgroups);
+}
+
+pkg_grouppolicy_matchers_factory :: ~pkg_grouppolicy_matchers_factory()
+{
+  delete chain;
+}

Modified: branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h	(original)
+++ branches/aptitude-0.3/aptitude/src/pkg_grouppolicy.h	Mon Jul 25 17:37:23 2005
@@ -50,6 +50,8 @@
 #include <apt-pkg/pkgcache.h>
 #include <sigc++/signal.h>
 
+#include <vector>
+
 // Used to set the visible status if a package is available.
 typedef sigc::signal2<void,
 		      const pkgCache::PkgIterator &,
@@ -258,4 +260,40 @@
   virtual ~pkg_grouppolicy_task_factory();
 };
 
+class pkg_matcher;
+
+// Groups packages using the given list of matchers/tree names.  Match
+// results can be substituted into tree names using \N notation.
+class pkg_grouppolicy_matchers_factory:public pkg_grouppolicy_factory
+{
+public:
+  struct match_pair
+  {
+    pkg_matcher *matcher;
+    std::wstring tree_name;
+
+    match_pair(pkg_matcher *_matcher, const std::wstring &_tree_name)
+      :matcher(_matcher), tree_name(_tree_name)
+    {
+    }
+  };
+
+private:
+  pkg_grouppolicy_factory *chain;
+
+  std::vector<match_pair> subgroups;
+public:
+
+  pkg_grouppolicy_matchers_factory(pkg_grouppolicy_factory *_chain,
+				   const std::vector<match_pair> &_subgroups)
+    :chain(_chain), subgroups(_subgroups)
+  {
+  }
+
+  pkg_grouppolicy *instantiate(pkg_signal *sig,
+			       desc_signal *_desc_sig);
+
+  ~pkg_grouppolicy_matchers_factory();
+};
+
 #endif



More information about the Aptitude-svn-commit mailing list