[Debtags-commits] [SCM] Command line debtags tool. branch, master, updated. 6bec300233262477fa1463a3ae0c30d18f1bdd2c

Enrico Zini enrico at enricozini.org
Mon May 10 11:39:40 UTC 2010


The following commit has been merged in the master branch:
commit 6bec300233262477fa1463a3ae0c30d18f1bdd2c
Author: Enrico Zini <enrico at enricozini.org>
Date:   Mon May 10 12:39:30 2010 +0100

    Build with new libept
    
    Build with new libept
    No more debtags smartsearch, which has been obsoleted by axi-search

diff --git a/debian/changelog b/debian/changelog
index 599cbe5..db8f893 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+debtags (1.7.10) unstable; urgency=low
+
+  * Build with new libept
+  * No more debtags smartsearch, which has been obsoleted by axi-search
+
+ -- Enrico Zini <enrico at debian.org>  Mon, 10 May 2010 12:37:33 +0100
+
 debtags (1.7.9) unstable; urgency=low
 
   * Build with new libept
diff --git a/debian/control b/debian/control
index 86bd6e2..4dd4b6f 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: admin
 Priority: optional
 Maintainer: Enrico Zini <enrico at debian.org>
 Uploaders: Arnaud Fontaine <arnaud at andesi.org>
-Build-Depends: c++abi2-dev, cdbs, debhelper (>> 4.1), dh-buildinfo, pkg-config, apt, libept-dev (>= 0.5.26), libept-dev (<< 0.6), zlib1g-dev, python-dev, python-docutils, libtagcoll2-dev (>= 2.0.4), libtagcoll2-dev (<<2.1), libwibble-dev (>= 0.1.15), libwibble-dev (<< 0.2)
+Build-Depends: c++abi2-dev, cdbs, debhelper (>> 4.1), dh-buildinfo, pkg-config, apt, libept-dev (>= 0.6.0), libept-dev (<< 0.7), zlib1g-dev, python-dev, python-docutils, libtagcoll2-dev (>= 2.0.4), libtagcoll2-dev (<<2.1), libwibble-dev (>= 0.1.15), libwibble-dev (<< 0.2)
 Standards-Version: 3.8.0.0
 Vcs-Svn: svn://svn.debian.org/svn/debtags/debtags/1.7
 Vcs-Browser: http://svn.debian.org/wsvn/debtags/debtags/1.7
diff --git a/tools/Environment.cc b/tools/Environment.cc
index ee70354..54b94e1 100644
--- a/tools/Environment.cc
+++ b/tools/Environment.cc
@@ -21,6 +21,8 @@
 #include "Environment.h"
 
 #include <ept/apt/apt.h>
+#include <ept/debtags/debtags.h>
+#include <ept/debtags/vocabulary.h>
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -42,12 +44,32 @@ Environment& Environment::get() throw ()
 
 // Initialize the environment with default values
 Environment::Environment() throw ()
-	: m_apt(0), m_debtags(0), _verbose(false), _debug(false) {}
+	: m_apt(0), m_debtags(0), m_vocabulary(0), _verbose(false), _debug(false), _editable(false) {}
 
 void Environment::init(bool editable)
 {
-	m_apt = new ept::apt::Apt;
-	m_debtags = new ept::debtags::Debtags(editable);
+	_editable = editable;
+}
+
+/// Access the apt data provider
+ept::apt::Apt& Environment::apt()
+{
+	if (!m_apt) m_apt = new ept::apt::Apt;
+	return *m_apt;
+}
+
+/// Access the debtags data provider
+ept::debtags::Debtags& Environment::debtags()
+{
+	if (!m_debtags) m_debtags = new ept::debtags::Debtags(_editable);
+	return *m_debtags;
+}
+
+/// Access the tag vocabulary
+ept::debtags::Vocabulary& Environment::voc()
+{
+	if (!m_vocabulary) m_vocabulary = new ept::debtags::Vocabulary;
+	return *m_vocabulary;
 }
 
 void fatal_error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
diff --git a/tools/Environment.h b/tools/Environment.h
index 7a5a5eb..801c8ba 100644
--- a/tools/Environment.h
+++ b/tools/Environment.h
@@ -21,13 +21,19 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <ept/debtags/debtags.h>
 #include <string>
 
 namespace ept {
+
 namespace apt {
 class Apt;
 }
+
+namespace debtags {
+class Debtags;
+class Vocabulary;
+}
+
 }
 
 class Environment
@@ -39,12 +45,18 @@ protected:
 	/// Debtags data provider
 	ept::debtags::Debtags* m_debtags;
 
+	/// Vocabulary data provider
+	ept::debtags::Vocabulary* m_vocabulary;
+
 	// True when operations should be verbose
 	bool _verbose;
 
 	// True when operations should be very verbose
 	bool _debug;
 
+	// Whether the debtags database is open editable
+	bool _editable;
+
 	Environment() throw ();
 		
 public:
@@ -58,13 +70,13 @@ public:
 	void init(bool editable = false);
 
 	/// Access the apt data provider
-	ept::apt::Apt& apt() { return *m_apt; }
+	ept::apt::Apt& apt();
 
 	/// Access the debtags data provider
-	ept::debtags::Debtags& debtags() { return *m_debtags; }
+	ept::debtags::Debtags& debtags();
 
 	/// Access the tag vocabulary
-	ept::debtags::Vocabulary& voc() { return m_debtags->vocabulary(); }
+	ept::debtags::Vocabulary& voc();
 
 	// Accessor methods
 
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 68fb8d6..4961cb7 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -6,10 +6,9 @@ pkgdata_SCRIPTS = fetch
 
 debtags_SOURCES = \
 	Environment.cc \
-	SmartSearcher.cc \
 	debtags.cc
 debtags_LDADD = $(LIBEPT_LIBS)
 
 INCLUDES = -I.. $(LIBEPT_CFLAGS) -DSCRIPTDIR=\"$(pkgdatadir)\"
 
-EXTRA_DIST = DebtagsOptions.h Environment.h Printer.h SmartSearcher.h nullstream.h fetch debtags-updatecontrol
+EXTRA_DIST = DebtagsOptions.h Environment.h Printer.h nullstream.h fetch debtags-updatecontrol
diff --git a/tools/Printer.h b/tools/Printer.h
index 6726638..e7d8e3a 100644
--- a/tools/Printer.h
+++ b/tools/Printer.h
@@ -34,6 +34,8 @@
 
 #include <ept/apt/apt.h>
 #include <ept/apt/packagerecord.h>
+#include <ept/debtags/debtags.h>
+#include <ept/debtags/vocabulary.h>
 #include <ept/debtags/maint/debdbparser.h>
 #if 0
 #include <ept/forward.h>
@@ -57,7 +59,7 @@ public:
 
 protected:
 	typedef std::string Package;
-	typedef ept::debtags::Tag Tag;
+	typedef std::string Tag;
 
 	Type m_type;
 	int* count;
@@ -86,7 +88,7 @@ public:
 					std::set<std::string> facets;
 					for (typename TTAGS::const_iterator j = data.second.begin();
 						   j != data.second.end(); ++j)
-						facets.insert(j->facet().name());
+						facets.insert(ept::debtags::voc::getfacet(*j));
 
 					for (std::set<std::string>::const_iterator j = facets.begin();
 						   j != facets.end(); ++j)
@@ -106,10 +108,10 @@ public:
 					   if (j == data.second.begin())
 					   {
 						   std::cout << ": ";
-						   std::cout << j->fullname();
+						   std::cout << *j;
 					   } else {
 						   std::cout << ", ";
-						   std::cout << j->fullname();
+						   std::cout << *j;
 					   }
 					break;
 				case QUIET:
@@ -131,15 +133,15 @@ public:
 	{
 		for (typename TTAGS::const_iterator i = tags.begin(); i != tags.end(); ++i)
 			if (i == tags.begin())
-				std::cout << i->fullname();
+				std::cout << *i;
 			else
-				std::cout << ", " + i->fullname();
+				std::cout << ", " + *i;
 	}
 
 protected:
 	typedef std::string Package;
 	typedef ept::apt::Version Version;
-	typedef ept::debtags::Tag Tag;
+	typedef std::string Tag;
 
 	ept::apt::Apt& apt;
 	ept::debtags::Debtags& debtags;
diff --git a/tools/SmartSearcher.cc b/tools/SmartSearcher.cc
deleted file mode 100644
index 64a488d..0000000
--- a/tools/SmartSearcher.cc
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * debtags - Implement package tags support for Debian
- *
- * Copyright (C) 2003--2006  Enrico Zini <enrico at debian.org>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include "SmartSearcher.h"
-#include "Printer.h"
-#include <ept/apt/apt.h>
-#include <ept/apt/packagerecord.h>
-#include <tagcoll/utils/set.h>
-#include <wibble/regexp.h>
-
-using namespace std;
-using namespace ept::apt;
-using namespace tagcoll;
-
-static string toLower(const std::string& s)
-{
-	string res;
-	for (string::const_iterator i = s.begin(); i != s.end(); ++i)
-		res += tolower(*i);
-	return res;
-}
-
-void SmartSearcher::splitPattern(const std::string& pattern)
-{
-	patterns.clear();
-
-	wibble::Tokenizer tok(pattern, "[^[:blank:]]+", REG_EXTENDED);
-	for (wibble::Tokenizer::const_iterator i = tok.begin();
-			i != tok.end(); ++i)
-		patterns.push_back(toLower(*i));
-}
-
-bool SmartSearcher::patternMatch(const Package& pkg)
-{
-	using namespace ept;
-
-	std::string name = toLower(pkg);
-	std::string desc;
-	PackageRecord record(apt.rawRecord(pkg));
-	desc = toLower(record.description());
-
-	for (std::vector<std::string>::const_iterator i = patterns.begin();
-			i != patterns.end(); ++i)
-		if (name.find(*i) == string::npos
-				&& desc.find(*i) == string::npos)
-			return false;
-	return true;
-}
-
-bool SmartSearcher::tagMatch(const Package& pkg)
-{
-	using namespace wibble::operators;
-	std::set<Tag> tags = debtags.getTagsOfItem(pkg);
-
-	if (!wanted.empty() && !utils::set_contains(tags, wanted))
-		return false;
-
-	if (!unwanted.empty() && !(tags & unwanted).empty())
-		return false;
-
-	return true;
-}
-
-void SmartSearcher::showSet(const std::set<Tag>& tags, const std::string& type)
-{
-	for (std::set<Tag>::const_iterator i = tags.begin();
-			i != tags.end(); ++i)
-	{
-		tagsInMenu.push_back(*i);
-		cout << tagsInMenu.size() << ") " << i->fullname() << " (" << type << ")" << endl;
-	}
-}
-
-void SmartSearcher::showInteresting(int max)
-{
-	for (std::vector<Tag>::const_reverse_iterator i = interesting.rbegin();
-			i != interesting.rend() && max > 0; ++i)
-	{
-		using namespace wibble::operators;
-		if (utils::set_contains(wanted, *i)
-			|| utils::set_contains(unwanted, *i)
-			|| utils::set_contains(ignored, *i)
-			|| coll.getCardinality(*i) == 0)
-			continue;
-		tagsInMenu.push_back(*i);
-		cout << tagsInMenu.size() << ") " << i->fullname()
-			 << " (" << coll.getCardinality(*i) << "/" << coll.itemCount() << ")" << endl;
-		--max;
-	}
-}
-
-void SmartSearcher::showDiscriminant(int max)
-{
-	// Compute the most interesting tags by discriminance
-	vector<Tag> discr = coll.tagsInDiscriminanceOrder();
-
-	for (std::vector<Tag>::const_reverse_iterator i = discr.rbegin();
-			i != discr.rend() && max > 0; ++i)
-	{
-		using namespace wibble::operators;
-		if (utils::set_contains(wanted, *i)
-			|| utils::set_contains(unwanted, *i)
-			|| utils::set_contains(ignored, *i))
-			continue;
-		tagsInMenu.push_back(*i);
-		cout << tagsInMenu.size() << ") " << i->fullname()
-			 << " (" << coll.getCardinality(*i) << "/" << coll.itemCount() << ")" << endl;
-		--max;
-	}
-}
-
-void SmartSearcher::showTags()
-{
-	tagsInMenu.clear();
-
-	showSet(wanted, "wanted");
-	showSet(unwanted, "unwanted");
-	showSet(ignored, "ignored");
-	cout << endl;
-	showInteresting();
-	cout << endl;
-	showDiscriminant();
-}
-
-void SmartSearcher::refilter()
-{
-	// Regenerate coll
-	coll = coll::Fast<Package, Tag>();
-	fullColl.output(filter(inserter(coll)));
-}
-
-void SmartSearcher::computeInteresting(const std::string& pattern)
-{
-	splitPattern(pattern);
-
-	coll::Fast<Package, Tag> filtered;
-	for (coll::Fast<Package, Tag>::const_iterator i = fullColl.begin();
-			i != fullColl.end(); ++i)
-		if (patternMatch(i->first))
-			filtered.insert(wibble::singleton(i->first), i->second);
-
-	interesting = filtered.tagsInRelevanceOrder(fullColl);
-#if 0
-	// Compute the set of tags that better represent the keyword search
-	TagMetrics<Tag, int> metrics1 = TagMetrics<Tag, int>::computeFromTags(fullColl);
-	TagMetrics<Tag, int> metrics2 = TagMetrics<Tag, int>::computeFromTags(filtered);
-#if 0
-	// Use the jump algorithm
-	TagMetrics<Tag, double> jumps = metrics2.jumpsFrom(metrics1);
-	interesting = jumps.tagsSortedByMetrics();
-#else
-	// Use the reduction percentage algorithm (a bit faster, and more
-	// optimizable)
-	interesting = metrics2.tagsSortedByRelevance(metrics1);
-#endif
-#endif
-}
-
-SmartSearcher::SmartSearcher(const std::string& pattern)
-	: apt(env().apt()), debtags(env().debtags())
-{
-	// Perform the initial filtering using the keyword search
-	Apt& apt = env().apt();
-	for (Apt::iterator i = apt.begin(); i != apt.end(); ++i)
-		fullColl.insert(wibble::singleton(*i), debtags.getTagsOfItem(*i));
-
-	computeInteresting(pattern);
-
-	coll = fullColl;
-}
-
-void SmartSearcher::interact()
-{
-	bool done = false;
-	while (!done)
-	{
-		cout << "Tag selection:" << endl;
-		showTags();
-		cout << coll.itemCount() << " packages selected so far." << endl;
-		string ans;
-		bool changed = false;
-
-		// TODO: allow to add tags based on a keyword search on coll
-		cout << "Your choice (+#, -#, =#, K word, View, Done, Quit, ?): ";
-		if (!getline(cin, ans))
-		{
-			cout << endl;
-			done = true;
-		}
-
-		while (ans != "")
-		{
-			// If we're setting a new keyword search, process now and skip
-			// processing as a list
-			if (ans[0] == '?')
-			{
-				cout << "+ number  select the tag with the given number as a tag you want" << endl
-					 << "- number  select the tag with the given number as a tag you do not want" << endl
-					 << "= number  select the tag with the given number as a tag you don't care about" << endl
-					 << "K word    recompute the set of interesting tags from a full-text search using the given word" << endl
-					 << "V         view the packages selected so far" << endl
-					 << "D         print the packages selected so far and exit" << endl
-					 << "Q         quit debtags smart search" << endl
-					 << "?         print this help information" << endl;
-				ans.clear();
-			}
-			else if (ans[0] == 'k' || ans[0] == 'K')
-			{
-				// Strip initial command and empty spaces
-				ans = ans.substr(1);
-				while (!ans.empty() && isspace(ans[0]))
-					ans = ans.substr(1);
-				if (ans == "")
-					cout << "The 'k' command needs a keyword to use for finding new interesting tags." << endl;
-				else
-					computeInteresting(ans);
-				ans.clear();
-			} else {
-				// Split the answer by spaces
-				string rest;
-				size_t pos = ans.find(" ");
-				if (pos != string::npos)
-				{
-					// Skip spaces
-					for ( ; pos < ans.size() && isspace(ans[pos]); ++pos)
-						;
-					rest = ans.substr(pos);
-					ans = ans.substr(0, pos);
-				}
-				if (ans[0] == '+' || ans[0] == '-' || ans[0] == '=') {
-					int idx = strtoul(ans.substr(1).c_str(), NULL, 10);
-					if (idx <= 0 || (unsigned)idx > tagsInMenu.size())
-						cout << "Tag " << idx << " was not on the menu." << endl;
-					else
-					{
-						Tag tag = tagsInMenu[idx - 1];
-						//cout << "Understood " << ans << " as " << ans[0] << tag.fullname() << endl;
-
-						switch (ans[0])
-						{
-							case '+':
-								wanted.insert(tag);
-								unwanted.erase(tag);
-								ignored.erase(tag);
-								break;
-							case '-':
-								wanted.erase(tag);
-								unwanted.insert(tag);
-								ignored.erase(tag);
-								break;
-							case '=':
-								wanted.erase(tag);
-								unwanted.erase(tag);
-								ignored.insert(tag);
-								break;
-						}
-						changed = true;
-					}
-				} else if (ans == "V" || ans == "v") {
-					coll.output(PackagePrinter(PackagePrinter::SHORT));
-				} else if (ans == "D" || ans == "d") {
-					coll.output(PackagePrinter(PackagePrinter::SHORT));
-					done = true;
-				} else if (ans == "Q" || ans == "q") {
-					done = true;
-				} else {
-					cout << "Ignoring command \"" << ans << "\"" << endl;
-				}
-				ans = rest;
-			}
-		}
-		if (changed)
-			refilter();
-	}
-}
-
-void SmartSearcher::outputRelevantTags()
-{
-	for (std::vector<Tag>::const_iterator i = interesting.begin();
-			i != interesting.end(); ++i)
-	{
-		using namespace wibble::operators;
-		if (utils::set_contains(wanted, *i)
-			|| utils::set_contains(unwanted, *i)
-			|| utils::set_contains(ignored, *i)
-			|| coll.getCardinality(*i) == 0)
-			continue;
-		cout << i->fullname() << " - " << i->shortDescription() << endl;
-	}
-}
-
-void SmartSearcher::outputDiscriminantTags()
-{
-	// Compute the most interesting tags by discriminance
-	coll::Fast<Package, Tag> filtered;
-	for (coll::Fast<Package, Tag>::const_iterator i = fullColl.begin();
-			i != fullColl.end(); ++i)
-		if (patternMatch(i->first))
-			filtered.insert(wibble::singleton(i->first), i->second);
-
-	vector<Tag> discr = filtered.tagsInDiscriminanceOrder();
-
-	for (std::vector<Tag>::const_iterator i = discr.begin();
-			i != discr.end(); ++i)
-	{
-		using namespace wibble::operators;
-		if (utils::set_contains(wanted, *i)
-			|| utils::set_contains(unwanted, *i)
-			|| utils::set_contains(ignored, *i))
-			continue;
-		cout << i->fullname() << " - " << i->shortDescription()
-			 << " (" << filtered.getDiscriminance(*i) * 200 /filtered.itemCount() << "%)" << endl;
-	}
-}
-
-#include <tagcoll/coll/fast.tcc>
-
-// vim:set ts=4 sw=4:
diff --git a/tools/SmartSearcher.h b/tools/SmartSearcher.h
deleted file mode 100644
index 3f1b2a2..0000000
--- a/tools/SmartSearcher.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * debtags - Implement package tags support for Debian
- *
- * Copyright (C) 2003--2006  Enrico Zini <enrico at debian.org>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef DEBTAGS_SMARTSEARCHER_H
-#define DEBTAGS_SMARTSEARCHER_H
-
-#include "Environment.h"
-#include <tagcoll/coll/fast.h>
-
-#include <vector>
-
-#if 0
-template<typename Tag, typename Number = int>
-class TagMetrics : public std::map<Tag, Number>
-{
-	class MetricsOrder
-	{
-		const TagMetrics& metric;
-	public:
-		MetricsOrder(const TagMetrics& metric) : metric(metric) {}
-		bool operator()(const Tag& t1, const Tag& t2)
-		{
-			// Returns true if t1 precedes t2, and false otherwise
-			return metric.get(t1) < metric.get(t2);
-		}
-	};
-	class DiscriminanceOrder
-	{
-		const TagMetrics& metric;
-		int itemCount;
-	public:
-		DiscriminanceOrder(const TagMetrics& metric, int itemCount)
-			: metric(metric), itemCount(itemCount) {}
-		bool operator()(const Tag& t1, const Tag& t2)
-		{
-			// Returns true if t1 precedes t2, and false otherwise
-			return metric.discriminance(t1, itemCount) < metric.discriminance(t2, itemCount);
-		}
-	};
-	class RelevanceOrder
-	{
-		const TagMetrics& first;
-		const TagMetrics& second;
-	public:
-		RelevanceOrder(const TagMetrics& first, const TagMetrics& second)
-			: first(first), second(second) {}
-		bool operator()(const Tag& t1, const Tag& t2)
-		{
-			// Replace 10000* with (double) to be formally precise but
-			// use floating point aritmetics
-			return 10000 * second.get(t1) / first.get(t1) < 10000 * second.get(t2) / first.get(t2);
-		}
-	};
-
-	#if 0
-	TagMetrics<Tag, double> jumpsFrom(const TagMetrics<Tag, Number>& other) const
-	{
-		TagMetrics<Tag, double> res;
-		for (typename TagMetrics<Tag, Number>::const_iterator i = this->begin(); i != this->end(); ++i)
-		{
-			//cout << i->first.fullname() << " was " << other.get(i->first) << " is " << i->second << " kept " << i->second * 100 / other.get(i->first) << "%" << endl;
-			res.add(i->first, (double)i->second / other.get(i->first));
-		}
-		return res;
-	}
-	#endif
-
-public:
-	void add(const Tag& tag, const Number& val)
-	{
-		typename TagMetrics::iterator i = this->find(tag);
-		if (i == this->end())
-			insert(make_pair(tag, val));
-		else
-			i->second += val;
-	}
-
-	Number get(const Tag& tag) const
-	{
-		typename TagMetrics::const_iterator i = this->find(tag);
-		if (i == this->end())
-			return 0;
-		else
-			return i->second;
-	}
-
-	// Get the minimum number of packages that would be eliminated by choosing
-	// this tag either as 'wanted' or as 'unwanted'
-	Number discriminance(const Tag& tag, Number itemCount) const
-	{
-		return get(tag) < itemCount - get(tag) ? get(tag) : itemCount - get(tag);
-	}
-
-	TagMetrics<Tag, Number> rankMetrics() const
-	{
-		vector<Tag> sorted = tagsSortedByMetrics();
-		TagMetrics<Tag, Number> res;
-		for (size_t i = 0; i < sorted.size(); ++i)
-			res.add(sorted[i], sorted.size() - i);
-		return res;
-	}
-
-	TagMetrics<Tag, double> jumpsFrom(const TagMetrics<Tag, Number>& other) const
-	{
-		// Compute rank metrics
-		TagMetrics<Tag, Number> rank1 = other.rankMetrics();
-		TagMetrics<Tag, Number> rank2 = rankMetrics();
-
-		TagMetrics<Tag, double> res;
-		typename TagMetrics::const_iterator i1 = rank1.begin();
-		typename TagMetrics::const_iterator i2 = rank2.begin();
-		while (i1 != rank1.end() || i2 != rank2.end())
-		{
-			if (i1->first == i2->first)
-			{
-				res.add(i1->first, (i1->second - i2->second) / i2->second);
-				++i1;
-				++i2;
-			} else if (i1 == rank1.end() || (i2 != rank2.end() && i2->first < i1->first)) {
-				++i2;
-			} else {
-				++i1;
-			}
-		}
-		return res;
-	}
-
-
-	vector<Tag> tagsSortedByMetrics() const
-	{
-		vector<Tag> res;
-		for (typename TagMetrics::const_iterator i = this->begin(); i != this->end(); ++i)
-			res.push_back(i->first);
-		std::sort(res.begin(), res.end(), MetricsOrder(*this));
-		return res;
-	}
-
-	vector<Tag> tagsSortedByDiscriminance(int itemCount) const
-	{
-		vector<Tag> res;
-		for (typename TagMetrics::const_iterator i = this->begin(); i != this->end(); ++i)
-			res.push_back(i->first);
-		std::sort(res.begin(), res.end(), DiscriminanceOrder(*this, itemCount));
-		return res;
-	}
-
-	vector<Tag> tagsSortedByRelevance(const TagMetrics<Tag, Number>& other)
-	{
-		vector<Tag> res;
-		for (typename TagMetrics::const_iterator i = this->begin(); i != this->end(); ++i)
-			res.push_back(i->first);
-		std::sort(res.begin(), res.end(), RelevanceOrder(other, *this));
-		return res;
-	}
-
-	template<typename COLL>
-	static TagMetrics<Tag, Number> computeFromTags(const COLL& coll)
-	{
-		TagMetrics<Tag, Number> res;
-		for (typename COLL::const_tag_iterator i = coll.tagBegin();
-				i != coll.tagEnd(); ++i)
-			res.add(i->first, i->second.size());
-		return res;
-	}
-
-	void dump(const std::string& prefix, ostream& out)
-	{
-		TagMetrics<Tag, Number> rm = rankMetrics();
-		vector<Tag> tags = tagsSortedByMetrics();
-		int rank = 0;
-		for (typename vector<Tag>::const_iterator i = tags.begin(); i != tags.end(); ++i, ++rank)
-			out << prefix << tags.size() - rank << ":" << rm.get(*i) << ") " << i->fullname() << ": " << this->get(*i) << std::endl;
-	}
-};
-
-template<typename Metrics>
-class TagMetricsInserter : public wibble::mixin::OutputIterator< TagMetricsInserter<Metrics> >
-{
-	Metrics& m;
-
-public:
-	TagMetricsInserter(Metrics& m) : m(m) {}
-
-	template<typename Items, typename Tags>
-	TagMetricsInserter<Metrics>& operator=(const std::pair<Items, Tags>& data)
-	{
-		int size = data.first.size();
-		for (typename Tags::const_iterator i = data.second.begin();
-				i != data.second.end(); ++i)
-			m.add(*i, size);
-		return *this;
-	}
-};
-
-template<typename Tag, typename Number>
-TagMetricsInserter< TagMetrics<Tag, Number> > tagMetricsInserter(TagMetrics<Tag, Number>& out)
-{
-	return TagMetricsInserter< TagMetrics<Tag, Number> >(out);
-}
-#endif
-
-
-class SmartSearcher
-{
-protected:
-	typedef std::string Package;
-	typedef ept::debtags::Tag Tag;
-
-	ept::apt::Apt& apt;
-	ept::debtags::Debtags& debtags;
-
-	// TODO:
-	//  1) funzione di ranking dei tag che calcola, sul subset indotto da
-	//     {wanted, unwanted}, la rilevanza dei tag dopo il filtraggio con la
-	//     keyword
-	//	2) iterare usando la nuova funzione di ranking
-	tagcoll::coll::Fast<Package, Tag> fullColl;
-	tagcoll::coll::Fast<Package, Tag> coll;
-
-	std::vector<std::string> patterns;
-	std::set<Tag> wanted;
-	std::set<Tag> unwanted;
-	std::set<Tag> ignored;
-	std::vector<Tag> interesting;
-
-	std::vector<Tag> tagsInMenu;
-
-	void splitPattern(const std::string& pattern);
-	bool patternMatch(const Package& pkg);
-	bool tagMatch(const Package& pkg);
-
-	template<typename OUT>
-	class Filter : public wibble::mixin::OutputIterator< Filter<OUT> >
-	{
-		SmartSearcher& s;
-		OUT out;
-
-	public:
-		Filter(SmartSearcher& s, const OUT& out) : s(s), out(out) {}
-
-		template<typename ITEMS, typename TAGS>
-		Filter<OUT>& operator=(const std::pair<ITEMS, TAGS>& data)
-		{
-			for (typename ITEMS::const_iterator i = data.first.begin();
-					i != data.first.end(); ++i)
-			{
-				if (!s.tagMatch(*i))
-					continue;
-#if 0
-				bool matches = s.patternMatch(*i);
-				for (typename TAGS::const_iterator t = data.second.begin();
-						t != data.second.end(); ++t)
-				{
-					r.incFull(*t);
-					++r.totalFull;
-					if (matches)
-					{
-						r.incFilt(*t);
-						++r.totalFilt;
-					}
-				}
-#endif
-				*out = data;
-				++out;
-			}
-			return *this;
-		}
-	};
-	template<typename OUT>
-	Filter<OUT> filter(const OUT& out)
-	{
-		return Filter<OUT>(*this, out);
-	}
-
-	#if 0
-	void autoSelect(const std::vector<Tag>& tags, size_t maxAuto = 5, size_t maxUser = 7)
-	{
-		interesting.clear();
-		if (tags.empty())
-			return;
-
-		size_t autoCount = (tags.size() - maxUser) / 2;
-		if (autoCount > maxAuto) autoCount = maxAuto;
-		size_t userCount = tags.size() - (2 * autoCount);
-		if (userCount > maxUser) userCount = maxUser;
-
-		// Use the bottom autoCount tags as unwanted
-		for (size_t i = 0; i < autoCount; ++i)
-			unwanted.insert(tags[i]);
-
-		// Use the top autoCount tags as wanted
-		for (size_t i = tags.size() - 1; i >= tags.size() - autoCount; --i)
-			wanted.insert(tags[i]);
-
-		// Get the next userCount packages as interesting
-		for (size_t i = tags.size() - autoCount - 1; i >= tags.size() - autoCount - userCount; --i)
-			interesting.push_back(tags[i]);
-	}
-	#endif
-
-	void showSet(const std::set<Tag>& tags, const std::string& type);
-	void showInteresting(int max = 7);
-	void showDiscriminant(int max = 7);
-	void showTags();
-	void refilter();
-	void computeInteresting(const std::string& pattern);
-
-public:
-	SmartSearcher(const std::string& pattern);
-
-	void interact();
-	void outputRelevantTags();
-	void outputDiscriminantTags();
-
-
-#if 0
-	component::PackageTags& debtags;
-	Printer<Package, Tag>* printer;
-	map<Tag, size_t> tagCount;
-	OpSet<Tag> m_topTags;
-
-	virtual void consumeItemUntagged(const Package& pkg)
-	{
-		printer->consume(pkg);
-		CardinalityStore<Package, Tag>::consumeItemUntagged(pkg);
-	}
-	virtual void consumeItem(const Package& pkg, const Tagcoll::OpSet<Tag>& tags)
-	{
-		printer->consume(pkg, tags);
-		CardinalityStore<Package, Tag>::consumeItem(pkg, tags);
-		for (OpSet<Tag>::const_iterator i = tags.begin();
-				i != tags.end(); i++)
-			++tagCount[*i];
-	}
-	virtual void consumeItemsUntagged(const Tagcoll::OpSet<Package>& pkgs)
-	{
-		printer->consume(pkgs);
-		CardinalityStore<Package, Tag>::consumeItemsUntagged(pkgs);
-	}
-	virtual void consumeItems(const Tagcoll::OpSet<Package>& pkgs, const Tagcoll::OpSet<Tag>& tags)
-	{
-		printer->consume(pkgs, tags);
-		CardinalityStore<Package, Tag>::consumeItems(pkgs, tags);
-		for (OpSet<Tag>::const_iterator i = tags.begin();
-				i != tags.end(); i++)
-			tagCount[*i] += pkgs.size();
-	}
-
-	vector< pair<Tag, size_t> > getTopTags(size_t count)
-	{
-		vector< pair<Tag, size_t> > res;
-		for (map<Tag, size_t>::const_iterator i = tagCount.begin();
-				i != tagCount.end(); i++)
-		{
-			pair<Tag, size_t> hand = *i;
-			for (size_t j = 0; j < count; j++)
-			{
-				if (j >= res.size())
-				{
-					res.push_back(hand);
-					break;
-				}
-				else if (hand.second > res[j].second)
-				{
-					pair<Tag, size_t> tmp = res[j];
-					res[j] = hand;
-					hand = tmp;
-				}
-			}
-		}
-		return res;
-	}
-
-public:
-	SmartSearcher(component::PackageTags& debtags, Printer<Package, Tag>* printer) :
-		debtags(debtags), printer(printer) {}
-
-	void clear()
-	{
-		CardinalityStore<Package, Tag>::operator=(CardinalityStore<Package, Tag>());
-		tagCount.clear();
-		m_topTags.clear();
-	}
-
-	OpSet<Tag> topTags() { return m_topTags; }
-
-	int outputRelated()
-	{
-		const size_t relevantTags = 5;
-		vector< pair<Tag, size_t> > topTagList = getTopTags(relevantTags);
-		Scores<Tag> scores;
-		vector< OpSet<Tag> > tagsets;
-		float distance = relevantTags;
-		int count = 0;
-
-		m_topTags.clear();
-		for (vector< pair<Tag, size_t> >::const_iterator i = topTagList.begin();
-				i != topTagList.end(); i++)
-			m_topTags += i->first;
-
-		// Get the tagsets that score less in weighted distance from topTags
-		for (tagsets_t::const_iterator i = this->tagsets.begin();
-				i != this->tagsets.end(); i++)
-		{
-			float d = scores.distance(m_topTags, i->first);
-			if (d <= distance)
-			{
-				if (d < distance)
-				{
-					tagsets.clear();
-					distance = d;
-				}
-				tagsets.push_back(i->first);
-			}
-		}
-
-		// print the items they have
-		for (vector< OpSet<Tag> >::const_iterator i = tagsets.begin();
-				i != tagsets.end(); i++)
-		{
-			OpSet<Package> pkgs = debtags.tagdb().getItems(*i);
-			printer->consume(pkgs, *i);
-			count += pkgs.size();
-		}
-		return count;
-	}
-
-	virtual void flush()
-	{
-		printer->flush();
-	}
-#endif
-};
-
-#endif
-// vim:set ts=4 sw=4:
diff --git a/tools/debtags.cc b/tools/debtags.cc
index 7ab1c4d..4ec2ea0 100644
--- a/tools/debtags.cc
+++ b/tools/debtags.cc
@@ -34,19 +34,17 @@
 #include <tagcoll/SmartHierarchy.h>
 #include <tagcoll/coll/simple.h>
 #include <tagcoll/utils/set.h>
+#include <tagcoll/patch.h>
 
 #include "Environment.h"
 #include "DebtagsOptions.h"
 #include "Printer.h"
 #include "nullstream.h"
-#include "SmartSearcher.h"
 
 #include <ept/apt/packagerecord.h>
-#include <ept/debtags/expression.h>
-#include <ept/debtags/maint/vocabularymerger.h>
+#include <ept/debtags/debtags.h>
+#include <ept/debtags/vocabulary.h>
 #include <ept/debtags/maint/path.h>
-#include <ept/debtags/maint/vocabularyindexer.h>
-#include <ept/debtags/maint/debtagsindexer.h>
 
 #include <wibble/sys/fs.h>
 
@@ -107,11 +105,7 @@ public:
 	template<typename ITEMS, typename TAGS>
 	ExpressionFilter<OUT>& operator=(const std::pair<ITEMS, TAGS>& data)
 	{
-		std::set<std::string> tags;
-		for (typename TAGS::const_iterator i = data.second.begin();
-				i != data.second.end(); ++i)
-			tags.insert(i->fullname());
-		bool matched = expr(tags);
+		bool matched = expr(data.second);
 		if (invert)
 			matched = !matched;
 		if (matched)
@@ -151,12 +145,12 @@ protected:
 public:
 	void add(const std::string& pattern) { patterns.push_back(pattern); }
 	
-	bool operator()(const Facet& item)
+	bool operator()(const voc::Data& item)
 	{
 		for (vector<string>::const_iterator i = patterns.begin();
 				i != patterns.end(); i++)
 		{
-			if (strcasestr(item.name().c_str(), i->c_str()))
+			if (strcasestr(item.name.c_str(), i->c_str()))
 				return true;
 			if (strcasestr(item.shortDescription().c_str(), i->c_str()))
 				return true;
@@ -165,22 +159,6 @@ public:
 		}
 		return false;
 	}
-	bool operator()(const Tag& item)
-	{
-		//cerr << "Testing: " << item.fullname() << endl;
-		for (vector<string>::const_iterator i = patterns.begin();
-				i != patterns.end(); i++)
-		{
-			if (strcasestr(item.fullname().c_str(), i->c_str()))
-				return true;
-			if (strcasestr(item.shortDescription().c_str(), i->c_str()))
-				return true;
-			if (strcasestr(item.longDescription().c_str(), i->c_str()))
-				return true;
-		}
-		//cerr << "  not passed." << endl;
-		return false;
-	}
 };
 
 template<class OUT>
@@ -231,13 +209,7 @@ public:
 			PackageState s = env().apt().state(*i);
 			if (!(s.isInstalled() || s.upgradable() || s.nowBroken()))
 				continue;
-			std::set<string> tags;
-			for (typename TAGS::const_iterator j = data.second.begin();
-					j != data.second.end(); ++j)
-			{
-				tags.insert(j->fullname());
-			}
-			if (nyt(tags))
+			if (nyt(data.second))
 			{
 				*out = make_pair(wibble::singleton(*i), data.second);
 				++out;
@@ -286,15 +258,10 @@ public:
 		if (data.second.empty())
 			++stats.notags;
 		else {
-			std::set<string> tags;
-			for (typename TAGS::const_iterator i = data.second.begin();
-					i != data.second.end(); ++i)
-				tags.insert(i->fullname());
-
-			if (has_nyt(tags)) {
+			if (has_nyt(data.second)) {
 				++stats.nyt;
 				++stats.onlynyt;
-				for (set<string>::const_iterator i = tags.begin(); i != tags.end(); ++i)
+				for (set<string>::const_iterator i = data.second.begin(); i != data.second.end(); ++i)
 					if (i->substr(0, 23) != "special::not-yet-tagged")
 					{
 						--stats.onlynyt;
@@ -302,7 +269,7 @@ public:
 					}
 			} else {
 				++stats.tagged;
-				if (is_ct(tags))
+				if (is_ct(data.second))
 					++stats.complete;
 			}
 		}
@@ -406,29 +373,29 @@ VocabularyFilter<VOC, OUT> vocabularyFilter(const VOC& voc, const OUT& out)
 	return VocabularyFilter<VOC, OUT>(voc, out);
 }
 
-static void printShortVocabularyItem(const Facet& facet)
+static void printShortVocabularyItem(const voc::FacetData& facet)
 {
-	cout << facet.name() << " (facet) - " << facet.shortDescription() << endl;
+	cout << facet.name << " (facet) - " << facet.shortDescription() << endl;
 }
 
-static void printShortVocabularyItem(const Tag& tag)
+static void printShortVocabularyItem(const voc::TagData& tag)
 {
-	cout << tag.fullname() << " - " << tag.shortDescription() << endl;
+	cout << tag.name << " - " << tag.shortDescription() << endl;
 }
 
-static void printVocabularyItem(const Facet& tag)
+static void printVocabularyItem(const voc::FacetData& tag)
 {
 	string ld = tag.longDescription();
-	cout << "Facet: " << tag.name() << endl;
+	cout << "Facet: " << tag.name << endl;
 	cout << "Description: " << tag.shortDescription() << endl;
 	cout << " " << ld << endl;
 	if (ld[ld.size() - 1] != '\n')
 		cout << endl;
 }
-static void printVocabularyItem(const Tag& tag)
+static void printVocabularyItem(const voc::TagData& tag)
 {
 	string ld = tag.longDescription();
-	cout << "Tag: " << tag.fullname() << endl;
+	cout << "Tag: " << tag.name << endl;
 	cout << "Description: " << tag.shortDescription() << endl;
 	cout << " " << ld << endl;
 	if (ld[ld.size() - 1] != '\n')
@@ -459,8 +426,8 @@ public:
 		}
 		for (typename TAGS::const_iterator i = data.second.begin();
 				i != data.second.end(); ++i)
-			if (i->valid())
-				tags.insert(i->fullname());
+			if (env().voc().hasTag(*i))
+				tags.insert(*i);
 		if (!items.empty())
 		{
 			*out = make_pair(items, tags);
@@ -479,7 +446,7 @@ PackageToMaint<OUT> packageToMaint(const OUT& out)
 struct PackageScore
 {
 	// tag -> (installed, total)
-	map<Tag, pair<int, int> > tagScore;
+	map<std::string, pair<int, int> > tagScore;
 	set<string> uninstalled;
 
 	void output(Debtags& debtags, ostream& out)
@@ -490,13 +457,13 @@ struct PackageScore
 				i != uninstalled.end(); ++i)
 		{
 			// Compute package score
-			set<Tag> tags = debtags.getTagsOfItem(*i);
+			set<std::string> tags = debtags.getTagsOfItem(*i);
 			int score = 0;
 			int ntags = 0;
-			for (set<Tag>::const_iterator t = tags.begin();
+			for (set<std::string>::const_iterator t = tags.begin();
 					t != tags.end(); ++t)
 			{
-				map<Tag, pair<int, int> >::const_iterator j = tagScore.find(*t);
+				map<std::string, pair<int, int> >::const_iterator j = tagScore.find(*t);
 				if (j != tagScore.end())
 				{
 					score += 100 * j->second.first / j->second.second;
@@ -556,12 +523,12 @@ public:
 			for (typename TAGS::const_iterator t = data.second.begin();
 					t != data.second.end(); ++t)
 			{
-				std::set<Tag> it;
+				std::set<std::string> it;
 				it.insert(*t);
 				if (!avoidTag(it))
 				{
 					//cerr << "Count " << t->fullname() << endl;
-					map<Tag, pair<int, int> >::iterator j = res.tagScore.find(*t);
+					map<std::string, pair<int, int> >::iterator j = res.tagScore.find(*t);
 					if (j == res.tagScore.end())
 						res.tagScore.insert(make_pair(*t, make_pair(installed ? 1 : 0, 1)));
 					else
@@ -577,13 +544,6 @@ public:
 	}
 };
 
-struct PackageToString {
-	string operator()(const string& pkg) { return pkg; }
-} serPackage;
-struct TagToString {
-	string operator()(const Tag& tag) { return tag.fullname(); }
-} serTag;
-
 int main(int argc, const char* argv[])
 {
 	wibble::commandline::DebtagsOptions opts;
@@ -608,25 +568,21 @@ int main(int argc, const char* argv[])
 			Apt& apt = env().apt();
 
 			// ensure that all facets are readable
-			std::set<Facet> facets = voc.facets();
-			for (std::set<Facet>::const_iterator i = facets.begin(); i != facets.end(); i++)
+			std::set<std::string> facets = voc.facets();
+			for (std::set<std::string>::const_iterator i = facets.begin(); i != facets.end(); i++)
 			{
-				cout << "Checking facet " << i->name(string("<invalid name>")) << "..." << endl;
-				i->name(string("foo"));
-				i->shortDescription(string("foo"));
-				i->longDescription(string("foo"));
-				i->tags();
+				cout << "Checking facet " << *i << "..." << endl;
+				if (voc.facetData(*i) == 0)
+					cerr << "No data for facet " << *i << endl;
 			}
 
 			// ensure that all tags are readable
-			std::set<Tag> tags = voc.tags();
-			for (std::set<Tag>::const_iterator i = tags.begin(); i != tags.end(); i++)
+			std::set<std::string> tags = voc.tags();
+			for (std::set<std::string>::const_iterator i = tags.begin(); i != tags.end(); i++)
 			{
-				cout << "Checking tag " << i->fullname(string("<invalid name>")) << "..." << endl;
-				i->name(string("foo"));
-				i->fullname(string("foo"));
-				i->shortDescription(string("foo"));
-				i->longDescription(string("foo"));
+				cout << "Checking tag " << *i << "..." << endl;
+				if (voc.tagData(*i) == 0)
+					cerr << "No data for tag " << *i << endl;
 			}
 
 			// ensure that all packages that declare they are readable, are readable
@@ -641,17 +597,25 @@ int main(int argc, const char* argv[])
 				//}
 			}
 			
-			for (std::set<Facet>::const_iterator i = facets.begin();
+			for (std::set<std::string>::const_iterator i = facets.begin();
 					i != facets.end(); i++)
 			{
-				if (!voc.hasFacet(i->name()))
-					cerr << "Vocabulary is not sure about having facet " << i->name() << endl;
-
-				std::set<Tag> tags = i->tags();
-				for (std::set<Tag>::const_iterator j = tags.begin();
+				if (!voc.hasFacet(*i))
+					cerr << "Vocabulary is not sure about having facet " << *i << endl;
+				const voc::FacetData* f = voc.facetData(*i);
+				if (!f)
+					cerr << "Vocabulary is really not sure about having facet " << *i << endl;
+
+				std::set<std::string> tags = f->tags();
+				for (std::set<std::string>::const_iterator j = tags.begin();
 						j != tags.end(); j++)
-					if (!voc.hasTag(j->fullname()))
-						cerr << "Vocabulary is not sure about having tag " << j->fullname() << endl;
+				{
+					if (!voc.hasTag(*j))
+						cerr << "Vocabulary is not sure about having tag " << *j << endl;
+					const voc::TagData* t = voc.tagData(*j);
+					if (!t)
+						cerr << "Vocabulary is really not sure about having tag " << *j << endl;
+				}
 			}
 			return 0;
 		}
@@ -777,16 +741,22 @@ int main(int argc, const char* argv[])
 			env().init();
 			Vocabulary& voc = env().voc();
 
-			std::set<Facet> facets = voc.facets();
-			for (std::set<Facet>::const_iterator i = facets.begin();
+			std::set<std::string> facets = voc.facets();
+			for (std::set<std::string>::const_iterator i = facets.begin();
 					i != facets.end(); i++)
 			{
-				printVocabularyItem(*i);
+				const voc::FacetData* f = voc.facetData(*i);
+				if (!f) continue;
+				printVocabularyItem(*f);
 
-				std::set<Tag> tags = i->tags();
-				for (std::set<Tag>::const_iterator j = tags.begin();
+				std::set<std::string> tags = f->tags();
+				for (std::set<std::string>::const_iterator j = tags.begin();
 						j != tags.end(); j++)
-					printVocabularyItem(*j);
+				{
+					const voc::TagData* t = voc.tagData(*i);
+					if (!t) continue;
+					printVocabularyItem(*t);
+				}
 			}
 			return 0;
 		}
@@ -797,15 +767,15 @@ int main(int argc, const char* argv[])
 			env().init();
 			string tag = opts.next();
 
-			Tag t = env().voc().tagByName(tag);
-			if (!t.valid())
+			const voc::TagData* t = env().voc().tagData(tag);
+			if (!t)
 			{
 				verbose("Tag `%s' was not found in tag vocabulary\n", tag.c_str());
 				return 1;
 			}
 			else
 			{
-				printVocabularyItem(t);
+				printVocabularyItem(*t);
 				return 0;
 			}
 		}
@@ -833,24 +803,30 @@ int main(int argc, const char* argv[])
 
 			int matched = 0;
 
-			std::set<Facet> facets = env().voc().facets();
-			for (std::set<Facet>::const_iterator i = facets.begin();
+			std::set<std::string> facets = env().voc().facets();
+			for (std::set<std::string>::const_iterator i = facets.begin();
 					i != facets.end(); i++)
 			{
-				if (match(*i))
+				const voc::FacetData* f = env().voc().facetData(*i);
+				if (!f) continue;
+				if (match(*f))
 				{
 					matched++;
-					printShortVocabularyItem(*i);
+					printShortVocabularyItem(*f);
 				}
 
-				std::set<Tag> tags = i->tags();
-				for (std::set<Tag>::const_iterator j = tags.begin();
+				std::set<std::string> tags = f->tags();
+				for (std::set<std::string>::const_iterator j = tags.begin();
 						j != tags.end(); j++)
-					if (match(*j))
+				{
+					const voc::TagData* t = env().voc().tagData(*j);
+					if (!t) continue;
+					if (match(*t))
 					{
 						matched++;
-						printShortVocabularyItem(*j);
+						printShortVocabularyItem(*t);
 					}
+				}
 			}
 
 			return matched > 0 ? 0 : 1;
@@ -912,8 +888,8 @@ int main(int argc, const char* argv[])
 			}
 
 			// Get the tagset as the intersection of the tagsets of all input items
-			std::set<string>::const_iterator i = splititems.begin();
-			std::set<Tag> ts = env().debtags().getTagsOfItem(*i);
+			std::set<std::string>::const_iterator i = splititems.begin();
+			std::set<std::string> ts = env().debtags().getTagsOfItem(*i);
 			for (++i; i != splititems.end(); i++)
 				ts &= env().debtags().getTagsOfItem(*i);
 
@@ -950,12 +926,12 @@ int main(int argc, const char* argv[])
 			if (count > 50 && maxdist == 0 && isatty(1))
 			{
 				string tags;
-				for (std::set<Tag>::const_iterator i = ts.begin();
+				for (std::set<std::string>::const_iterator i = ts.begin();
 						i != ts.end(); i++)
 					if (i == ts.begin())
-						tags += i->fullname();
+						tags += *i;
 					else
-						tags += "%2C" + i->fullname();
+						tags += "%2C" + *i;
 				feedback("\nIt seems that this set of packages lacks tag information that could help to better distinguish package similarities.\nYou can help providing better tagging: just point your browser to http://debian.vitavonni.de/packagebrowser/?tags=%s\n", tags.c_str());
 			}
 			return 0;
@@ -993,24 +969,23 @@ int main(int argc, const char* argv[])
 					return 1;
 				}
 
-				std::set<Tag> tagset;
+				std::set<std::string> tagset;
 				while (opts.hasNext())
 				{
 					string tag = opts.next();
-					Tag t = env().voc().tagByName(tag);
-					if (t)
-						tagset.insert(t);
+					if (env().voc().hasTag(tag))
+						tagset.insert(tag);
 					else
 						error("Tag '%s' not found: ignored\n", tag.c_str());
 				}
 
 				if (!tagset.empty())
 				{
-					PatchList<string, Tag> change;
+					PatchList<string, std::string> change;
 					if (cmd == "add")
-						change.addPatch(Patch<string, Tag>(pkg, tagset, std::set<Tag>()));
+						change.addPatch(Patch<string, std::string>(pkg, tagset, std::set<std::string>()));
 					else
-						change.addPatch(Patch<string, Tag>(pkg, std::set<Tag>(), tagset));
+						change.addPatch(Patch<string, std::string>(pkg, std::set<std::string>(), tagset));
 					env().debtags().applyChange(change);
 					env().debtags().savePatch();
 				} else
@@ -1022,10 +997,10 @@ int main(int argc, const char* argv[])
 				string pkg = opts.next();
 				if (env().apt().isValid(pkg))
 				{
-					std::set<Tag> ts = env().debtags().getTagsOfItem(pkg);
-					for (std::set<Tag>::const_iterator i = ts.begin();
+					std::set<std::string> ts = env().debtags().getTagsOfItem(pkg);
+					for (std::set<std::string>::const_iterator i = ts.begin();
 							i != ts.end(); i++)
-						cout << i->fullname() << endl;
+						cout << *i << endl;
 					return 0;
 				} else {
 					verbose("Package %s not found", pkg.c_str());
@@ -1156,38 +1131,13 @@ int main(int argc, const char* argv[])
 			env().init();
 			string file = opts.next();
 
-			coll::Simple<string, Tag> coll;
+			coll::Simple<string, std::string> coll;
 			env().debtags().outputSystem(file, inserter(coll));
 
-			PatchList<string, Tag> newpatches;
+			PatchList<string, std::string> newpatches;
 			newpatches.addPatch(env().debtags(), coll);
 
-			textformat::outputPatch(serPackage, serTag, newpatches, stdout);
-		}
-		// ssearch <word [word1 [word2 ...]]>
-		// Perform a keyword search integrated with related packages
-		else if (opts.foundCommand() == opts.smartsearch)
-		{
-			env().init();
-			if (!opts.hasNext())
-				throw wibble::exception::BadOption("you should specify one pattern to search");
-
-			string keywords;
-			while (opts.hasNext())
-				if (keywords.empty())
-					keywords = opts.next();
-				else
-					keywords += " " + opts.next();
-
-			SmartSearcher searcher(keywords);
-
-			if (opts.smse_reltags->boolValue())
-				searcher.outputRelevantTags();
-			else if (opts.smse_disctags->boolValue())
-				searcher.outputDiscriminantTags();
-			else {
-				searcher.interact();
-			}
+			textformat::outputPatch(newpatches, stdout);
 		}
 		// update
 		// Updates the package tag database (requires root)
@@ -1214,24 +1164,14 @@ int main(int argc, const char* argv[])
 				}
 			}
 
+			// Skip env, so we don't load the tag database if we
+			// don't need it
 
-			// Access the indexes to trigger a rebuild
-			//typedef ept::t::cache::debtags::IndexManager<> IndexManager;
-			std::string a, b;
-
-			//auto_ptr<Ept> ept = debtagsInit();
-			env().init();
-
-			VocabularyIndexer::obtainWorkingVocabulary(a, b);
-			verbose("Vocabulary: %s\n", a.c_str());
-			verbose("Vocabulary index: %s\n", b.c_str());
-
-			DebtagsIndexer::obtainWorkingDebtags(env().voc(), a, b);
-			verbose("Tag database: %s\n", a.c_str());
-			verbose("Tag database index: %s\n", b.c_str());
+			// Read new vocabulary data
+			Vocabulary voc;
 
-			//mode_t prev_umask = umask(022);
-			//umask(prev_umask);
+			// Write out the merged, updated vocabulary
+			voc.write();
 		}
 		else if (opts.foundCommand() == opts.vocfilter)
 		{
@@ -1243,7 +1183,7 @@ int main(int argc, const char* argv[])
 
 			if (opts.misc_vocfile->boolValue())
 			{
-				VocabularyMerger vm;
+				Vocabulary vm(true);
 				input::Stdio input(opts.misc_vocfile->stringValue());
 				vm.read(input);
 				readCollection(file, vocabularyFilter(vm, textformat::OstreamWriter(cout)));

-- 
Command line debtags tool.



More information about the Debtags-commits mailing list