diff options
30 files changed, 327 insertions, 2891 deletions
diff --git a/debian/changelog b/debian/changelog index e86d6b8..5826528 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +libept (0.6.0) unstable; urgency=low + + * Big debtags code simplification + - no more indices to maintain, just read the text files + - no more int IDs and conversions to/from strings + + -- Enrico Zini <enrico@debian.org> Mon, 10 May 2010 11:32:31 +0100 + libept (0.5.30) unstable; urgency=low * Priority: important diff --git a/ept/debtags/debtags.cc b/ept/debtags/debtags.cc index 331c132..383bb02 100644 --- a/ept/debtags/debtags.cc +++ b/ept/debtags/debtags.cc @@ -25,9 +25,10 @@ #include <ept/debtags/debtags.h> #include <ept/debtags/maint/path.h> -#include <ept/debtags/maint/serializer.h> -#include <ept/debtags/maint/debtagsindexer.h> +#include <ept/debtags/maint/sourcedir.h> +#include <tagcoll/patch.h> +#include <tagcoll/coll/simple.h> #include <tagcoll/input/stdio.h> #include <tagcoll/TextFormat.h> @@ -52,24 +53,17 @@ namespace ept { namespace debtags { Debtags::Debtags(bool editable) - : m_coll(m_rocoll) { - std::string tagfname; - std::string idxfname; + // Read and merge tag data + SourceDir mainSource(Path::debtagsSourceDir()); + SourceDir userSource(Path::debtagsUserSourceDir()); - if (!DebtagsIndexer::obtainWorkingDebtags(vocabulary(), tagfname, idxfname)) - { - m_timestamp = 0; - return; - } else { - m_timestamp = Path::timestamp(idxfname); - - mastermmap.init(idxfname); + mainSource.readTags(inserter(*this)); + userSource.readTags(inserter(*this)); - // Initialize the readonly index - m_pkgid.init(mastermmap, 0); - m_rocoll.init(mastermmap, 1, 2); - } + time_t ts_main_src = mainSource.tagTimestamp(); + time_t ts_user_src = userSource.tagTimestamp(); + m_timestamp = ts_main_src > ts_user_src ? ts_main_src : ts_user_src; // Initialize the patch collection layer rcdir = Path::debtagsUserSourceDir(); @@ -78,29 +72,23 @@ Debtags::Debtags(bool editable) if (Path::access(patchFile, F_OK) == 0) { input::Stdio in(patchFile); - PatchList<int, int> patch; - textformat::parsePatch(in, patchStringToInt(m_pkgid, vocabulary(), inserter(patch))); - m_coll.setChanges(patch); + PatchList<string, string> patch; + textformat::parsePatch(in, inserter(patch)); + applyChange(patch); } } -tagcoll::PatchList<std::string, Tag> Debtags::changes() const +tagcoll::PatchList<std::string, std::string> Debtags::changes() const { - tagcoll::PatchList<int, int> patches = m_coll.changes(); - tagcoll::PatchList<std::string, Tag> res; - - for (tagcoll::PatchList<int, int>::const_iterator i = patches.begin(); - i != patches.end(); ++i) - { - std::string pkg = packageByID(i->second.item); - if (pkg.empty()) - continue; - - res.addPatch(tagcoll::Patch<std::string, Tag>(pkg, - vocabulary().tagsByID(i->second.added), - vocabulary().tagsByID(i->second.removed))); - } - + // Read original tag data + SourceDir mainSource(Path::debtagsSourceDir()); + SourceDir userSource(Path::debtagsUserSourceDir()); + coll::Simple<string, string> orig; + mainSource.readTags(inserter(orig)); + userSource.readTags(inserter(orig)); + + tagcoll::PatchList<std::string, std::string> res; + res.addPatch(orig, *this); return res; } @@ -136,7 +124,7 @@ bool Debtags::hasTagDatabase() void Debtags::savePatch() { PatchList<std::string, std::string> spatch; - m_coll.changes().output(patchIntToString(m_pkgid, vocabulary(), tagcoll::inserter(spatch))); + changes().output(tagcoll::inserter(spatch)); savePatch(spatch); } @@ -166,30 +154,16 @@ void Debtags::savePatch(const PatchList<std::string, std::string>& patch) } } -void Debtags::savePatch(const PatchList<std::string, Tag>& patch) -{ - PatchList<std::string, std::string> spatch; - // patch.output(patchToString<C>(m_pkgs, m_pkgidx, m_tags, tagcoll::inserter(spatch))); - savePatch(spatch); -} - void Debtags::sendPatch() { PatchList<std::string, std::string> spatch; - m_coll.changes().output(patchIntToString(m_pkgid, vocabulary(), tagcoll::inserter(spatch))); + changes().output(tagcoll::inserter(spatch)); if (!spatch.empty()) { sendPatch(spatch); } } -void Debtags::sendPatch(const PatchList<std::string, Tag>& patch) -{ - PatchList<std::string, std::string> spatch; - // patch.output(patchToString<C>(m_pkgs, m_pkgidx, m_tags, tagcoll::inserter(spatch))); - sendPatch(spatch); -} - void Debtags::sendPatch(const PatchList<std::string, std::string>& patch) { static const char* cmd = "/usr/sbin/sendmail -t"; @@ -226,24 +200,13 @@ void Debtags::sendPatch(const PatchList<std::string, std::string>& patch) } } - -template<typename OUT> -void Debtags::outputSystem(const OUT& cons) -{ - m_rocoll.output(intToPkg(m_pkgid, vocabulary(), cons)); -} - -template<typename OUT> -void Debtags::outputPatched(const OUT& cons) -{ - m_coll.output(intToPkg(m_pkgid, vocabulary(), cons)); -} - } } +#include <ept/debtags/maint/sourcedir.tcc> #include <tagcoll/patch.tcc> -#include <tagcoll/coll/patched.tcc> +#include <tagcoll/coll/simple.tcc> +#include <tagcoll/coll/fast.tcc> #include <tagcoll/TextFormat.tcc> //#include <tagcoll/stream/filters.tcc> diff --git a/ept/debtags/debtags.h b/ept/debtags/debtags.h index c46786e..619cb15 100644 --- a/ept/debtags/debtags.h +++ b/ept/debtags/debtags.h @@ -26,13 +26,10 @@ #ifndef EPT_DEBTAGS_DEBTAGS_H #define EPT_DEBTAGS_DEBTAGS_H -#include <ept/debtags/tag.h> #include <ept/debtags/vocabulary.h> -#include <ept/debtags/maint/pkgid.h> #include <tagcoll/coll/base.h> -#include <tagcoll/coll/intdiskindex.h> -#include <tagcoll/coll/patched.h> +#include <tagcoll/coll/fast.h> namespace ept { namespace debtags { @@ -40,23 +37,6 @@ class Debtags; } } -namespace tagcoll { -template< typename _, typename _1 > class PatchList; - -namespace coll { - -template<> -struct coll_traits< ept::debtags::Debtags > -{ - typedef std::string item_type; - typedef ept::debtags::Tag tag_type; - typedef std::set< ept::debtags::Tag > tagset_type; - typedef std::set< std::string > itemset_type; -}; - -} -} - namespace ept { namespace debtags { @@ -65,26 +45,16 @@ namespace debtags { * * The database is normally found in /var/lib/debtags. * - * Tags and Facets are returned as Tag and Facet objects. The objects follow + * Tags and Facets are returned as std::strings. The objects follow * the flyweight pattern and access the data contained in the Vocabulary * instantiated inside Debtags. * * It is possible to get a reference to the Vocabulary object using the * vocabulary() method. */ -class Debtags : public tagcoll::coll::Collection<Debtags> +class Debtags : public tagcoll::coll::Fast<std::string, std::string> { protected: - // Master mmap index container - tagcoll::diskindex::MasterMMap mastermmap; - - // Debtags database - tagcoll::coll::IntDiskIndex m_rocoll; - tagcoll::coll::Patched< tagcoll::coll::IntDiskIndex > m_coll; - - // Package name to ID mapping - PkgId m_pkgid; - // Tag vocabulary Vocabulary m_voc; @@ -94,93 +64,9 @@ protected: // Last modification timestamp of the index time_t m_timestamp; - std::string packageByID(int id) const - { - return m_pkgid.byID(id); - } - - template<typename IDS> - std::set<std::string> packagesById(const IDS& ids) const - { - std::set<std::string> pkgs; - for (typename IDS::const_iterator i = ids.begin(); - i != ids.end(); ++i) - pkgs.insert(packageByID(*i)); - return pkgs; - } - - int idByPackage(const std::string& pkg) const - { - return m_pkgid.byName(pkg); - } - - template<typename PKGS> - std::set<int> idsByPackages(const PKGS& pkgs) const - { - std::set<int> ids; - for (typename PKGS::const_iterator i = pkgs.begin(); - i != pkgs.end(); ++i) - ids.insert(idByPackage(*i)); - return ids; - } - public: - typedef tagcoll::coll::Patched< tagcoll::coll::IntDiskIndex > coll_type; - typedef std::pair< std::string, std::set<Tag> > value_type; - - class const_iterator - { - const Debtags& coll; - Debtags::coll_type::const_iterator ci; - mutable const Debtags::value_type* cached_val; - - protected: - const_iterator(const Debtags& coll, - const Debtags::coll_type::const_iterator& ci) - : coll(coll), ci(ci), cached_val(0) {} - - public: - ~const_iterator() - { - if (cached_val) - delete cached_val; - } - const Debtags::value_type operator*() const - { - if (cached_val) - return *cached_val; - - return make_pair(coll.packageByID(ci->first), coll.vocabulary().tagsByID(ci->second)); - } - const Debtags::value_type* operator->() const - { - if (cached_val) - return cached_val; - return cached_val = new Debtags::value_type(*(*this)); - } - const_iterator& operator++() - { - ++ci; - if (cached_val) - { - delete cached_val; - cached_val = 0; - } - return *this; - } - bool operator==(const const_iterator& iter) const - { - return ci == iter.ci; - } - bool operator!=(const const_iterator& iter) const - { - return ci != iter.ci; - } - - friend class Debtags; - }; - const_iterator begin() const { return const_iterator(*this, m_coll.begin()); } - const_iterator end() const { return const_iterator(*this, m_coll.end()); } + typedef tagcoll::coll::Fast<std::string, std::string> coll_type; + typedef std::pair< std::string, std::set<std::string> > value_type; /** * Create a new accessor for the on-disk Debtags database @@ -190,8 +76,8 @@ public: * is true, then the local state directory will be created when the object * is instantiated. */ - Debtags(bool editable = false); - ~Debtags() {} + Debtags(bool editable = false); + ~Debtags() {} /// Get the timestamp of when the index was last updated time_t timestamp() const { return m_timestamp; } @@ -199,25 +85,11 @@ public: /// Return true if this data source has data, false if it's empty bool hasData() const { return m_timestamp != 0; } - coll_type& tagdb() { return m_coll; } - const coll_type& tagdb() const { return m_coll; } - tagcoll::PatchList<std::string, Tag> changes() const; + coll_type& tagdb() { return *this; } + const coll_type& tagdb() const { return *this; } + tagcoll::PatchList<std::string, std::string> changes() const; #if 0 - template<typename ITEMS, typename TAGS> - void insert(const ITEMS& items, const TAGS& tags) - { - for (typename ITEMS::const_iterator i = items.begin(); - i != items.end(); ++i) - m_changes.addPatch(Patch(*i, tags, TagSet())); - } - - template<typename ITEMS> - void insert(const ITEMS& items, const wibble::Empty<Tag>& tags) - { - // Nothing to do in this case - } - /** * Get the changes that have been applied to this collection */ @@ -239,84 +111,14 @@ public: void addChanges(const Patches& changes); #endif - bool hasTag(const Tag& tag) const { return m_coll.hasTag(tag.id()); } - - std::set<Tag> getTagsOfItem(const std::string& item) const - { - int id = idByPackage(item); - if (id == -1) return std::set<Tag>(); - return vocabulary().tagsByID(m_coll.getTagsOfItem(id)); - } - - template<typename ITEMS> - std::set<Tag> getTagsOfItems(const ITEMS& items) const - { - return vocabulary().tagsByID(m_coll.getTagsOfItems(idsByPackages(items))); - } - - std::set<std::string> getItemsHavingTag(const Tag& tag) const - { - return packagesById(m_coll.getItemsHavingTag(tag.id())); - } - template<typename TAGS> - std::set<std::string> getItemsHavingTags(const TAGS& tags) const - { - std::set<int> itags; - for (typename TAGS::const_iterator i = tags.begin(); - i != tags.end(); ++i) - itags.insert(i->id()); - return packagesById(m_coll.getItemsHavingTags(itags)); - } - #if 0 ItemSet getTaggedItems() const; #endif - std::set<Tag> getAllTags() const - { - return vocabulary().tagsByID(m_coll.getAllTags()); - } /// Access the vocabulary in use - Vocabulary& vocabulary() { return m_voc; } + Vocabulary& vocabulary() { return m_voc; } /// Access the vocabulary in use - const Vocabulary& vocabulary() const { return m_voc; } - - /** - * Access the PkgId in use. - * - * \note Future implementations may not rely on a PkgId - */ - PkgId& pkgid() { return m_pkgid; } - /** - * Access the PkgId in use. - * - * \note Future implementations may not rely on a PkgId - */ - const PkgId& pkgid() const { return m_pkgid; } - - int getCardinality(const Tag& tag) const - { - return m_coll.getCardinality(tag.id()); - } - - void applyChange(const tagcoll::PatchList<std::string, Tag>& change) - { - using namespace tagcoll; - PatchList<int, int> intp; - for (PatchList<std::string, Tag>::const_iterator i = change.begin(); - i != change.end(); ++i) - { - Patch<int, int> p(idByPackage(i->first)); - for (std::set<Tag>::const_iterator j = i->second.added.begin(); - j != i->second.added.end(); ++j) - p.add(j->id()); - for (std::set<Tag>::const_iterator j = i->second.removed.begin(); - j != i->second.removed.end(); ++j) - p.remove(j->id()); - intp.addPatch(p); - } - m_coll.applyChange(intp); - } + const Vocabulary& vocabulary() const { return m_voc; } #if 0 template<typename OUT> @@ -352,12 +154,6 @@ public: void savePatch(const tagcoll::PatchList<std::string, std::string>& patch); /** - * Save in the state storage directory a patch to turn the system database - * into the collection given - */ - void savePatch(const tagcoll::PatchList<std::string, Tag>& patch); - - /** * Send to the central archive a patch that can be used to turn * the system database into the collection given */ @@ -369,13 +165,7 @@ public: void sendPatch(const tagcoll::PatchList<std::string, std::string>& patch); /** - * Send the given patch to the central archive - */ - void sendPatch(const tagcoll::PatchList<std::string, Tag>& patch); - - - /** - * Output the current Debian tags database to a consumer of <std::string, Tag> + * Output the current Debian tags database to a consumer of <std::string, std::string> * * \note The collection is sent to 'cons' without merging repeated items */ @@ -383,7 +173,7 @@ public: void outputSystem(const OUT& cons); /** - * Output the given tag file to a consumer of <std::string, Tag> + * Output the given tag file to a consumer of <std::string, std::string> * * \note The collection is sent to 'cons' without merging repeated items */ @@ -392,7 +182,7 @@ public: /** * Output the current Debian tags database, patched with local patch, - * to a Consumer of <std::string, Tag> + * to a Consumer of <std::string, std::string> * * \note The collection is sent to 'cons' without merging repeated items */ @@ -401,7 +191,7 @@ public: /** * Output the given tag file, patched with local patch, - * to a Consumer of <std::string, Tag> + * to a Consumer of <std::string, std::string> * * \note The collection is sent to 'cons' without merging repeated items */ diff --git a/ept/debtags/debtags.tcc b/ept/debtags/debtags.tcc index 0963d09..48f80fb 100644 --- a/ept/debtags/debtags.tcc +++ b/ept/debtags/debtags.tcc @@ -27,8 +27,10 @@ #define EPT_DEBTAGS_DEBTAGS_TCC #include <ept/debtags/debtags.h> -#include <ept/debtags/maint/serializer.h> +#include <ept/debtags/maint/path.h> +#include <ept/debtags/maint/sourcedir.h> +#include <tagcoll/coll/simple.h> #include <tagcoll/input/stdio.h> #include <tagcoll/stream/patcher.h> #include <tagcoll/TextFormat.h> @@ -39,50 +41,60 @@ namespace debtags { template<typename OUT> void Debtags::outputSystem(const OUT& cons) { - m_rocoll.output(intToPkg(m_pkgid, vocabulary(), cons)); + // Read and merge tag data + SourceDir mainSource(Path::debtagsSourceDir()); + SourceDir userSource(Path::debtagsUserSourceDir()); + tagcoll::coll::Simple<string, string> merged; + mainSource.readTags(inserter(merged)); + userSource.readTags(inserter(merged)); + merged.output(cons); } + template<typename OUT> void Debtags::outputSystem(const std::string& filename, const OUT& out) { if (filename == "-") { tagcoll::input::Stdio input(stdin, "<stdin>"); - tagcoll::textformat::parse(input, ept::debtags::stringToPkg(m_pkgid, m_voc, out)); + tagcoll::textformat::parse(input, out); } else { tagcoll::input::Stdio input(filename); - tagcoll::textformat::parse(input, ept::debtags::stringToPkg(m_pkgid, m_voc, out)); + tagcoll::textformat::parse(input, out); } } template<typename OUT> void Debtags::outputPatched(const OUT& cons) { - m_coll.output(intToPkg(m_pkgid, vocabulary(), cons)); + output(cons); } template<typename OUT> void Debtags::outputPatched(const std::string& filename, const OUT& out) { - const tagcoll::PatchList<string, Tag>& patch = m_coll.changes(); + const tagcoll::PatchList<string, string>& patch = changes(); if (filename == "-") { tagcoll::input::Stdio input(stdin, "<stdin>"); - tagcoll::textformat::parse(input, ept::debtags::stringToPkg(m_pkgid, m_voc, patcher(patch, out))); + tagcoll::textformat::parse(input, patcher(patch, out)); } else { tagcoll::input::Stdio input(filename); - tagcoll::textformat::parse(input, ept::debtags::stringToPkg(m_pkgid, m_voc, patcher(patch, out))); + tagcoll::textformat::parse(input, patcher(patch, out)); } } } } -#include <tagcoll/coll/patched.tcc> +#include <ept/debtags/maint/sourcedir.tcc> +#include <tagcoll/coll/simple.tcc> +#include <tagcoll/coll/fast.tcc> +#include <tagcoll/patch.tcc> #endif diff --git a/ept/debtags/debtags.test.h b/ept/debtags/debtags.test.h index f360cc6..9f99cd2 100644 --- a/ept/debtags/debtags.test.h +++ b/ept/debtags/debtags.test.h @@ -29,6 +29,7 @@ #include <tagcoll/coll/simple.h> #include <tagcoll/stream/sink.h> +#include <tagcoll/patch.h> #include <wibble/operators.h> @@ -73,8 +74,8 @@ struct TestDebtags : DebtagsTestEnvironment Test _2() { - string p("debtags"); - std::set<Tag> tags = debtags.getTagsOfItem(p); + string p("debtags"); + std::set<std::string> tags = debtags.getTagsOfItem(p); assert( !tags.empty() ); #if 0 @@ -87,26 +88,26 @@ struct TestDebtags : DebtagsTestEnvironment #endif assert_eq( tags.size(), 8u ); - assert( voc().tagByName( "devel::buildtools" ) <= tags ); - assert( voc().tagByName( "implemented-in::c++" ) <= tags ); - assert( voc().tagByName( "interface::commandline" ) <= tags ); - assert( voc().tagByName( "role::program" ) <= tags ); - assert( voc().tagByName( "scope::application" ) <= tags ); - assert( voc().tagByName( "suite::debian" ) <= tags ); - assert( voc().tagByName( "use::searching" ) <= tags ); - assert( voc().tagByName( "works-with::software:package" ) <= tags ); + assert( tags.find("devel::buildtools") != tags.end() ); + assert( tags.find("implemented-in::c++") != tags.end() ); + assert( tags.find("interface::commandline") != tags.end() ); + assert( tags.find("role::program") != tags.end() ); + assert( tags.find("scope::application") != tags.end() ); + assert( tags.find("suite::debian") != tags.end() ); + assert( tags.find("use::searching") != tags.end() ); + assert( tags.find("works-with::software:package") != tags.end() ); } Test _3() { using namespace std; - /* Get the 'debtags' package */ - string p("debtags"); + /* Get the 'debtags' package */ + string p("debtags"); - /* Get its tags */ - std::set<Tag> tags = debtags.getTagsOfItem(p); - assert(!tags.empty()); + /* Get its tags */ + std::set<std::string> tags = debtags.getTagsOfItem(p); + assert(!tags.empty()); /* cerr << "Intersection size: " << endl; @@ -162,15 +163,14 @@ struct TestDebtags : DebtagsTestEnvironment assert( p <= packages ); /* Get one of the tags of 'debtags' */ - Tag tag = *tags.begin(); - assert(tag); + std::string tag = *tags.begin(); /* Get its items */ { /* Need this workaround until I figure out how to tell the new GCC * that TagDB is a TDBReadonlyDiskIndex and should behave as such */ - std::set<Tag> ts; + std::set<std::string> ts; ts.insert(tag); packages = debtags.getItemsHavingTags(ts); } @@ -190,20 +190,20 @@ struct TestDebtags : DebtagsTestEnvironment string p("debtags"); /* Get its tags */ - std::set<Tag> tags = debtags.getTagsOfItem(p); + std::set<std::string> tags = debtags.getTagsOfItem(p); assert(!tags.empty()); // Ensure that it's not tagged with gameplaying - Tag t = voc().tagByName("use::gameplaying"); - assert(! (t <= tags) ); + std::string t = "use::gameplaying"; + assert(tags.find(t) == tags.end()); // Add the gameplaying tag - PatchList<string, Tag> change; - change.addPatch(Patch<string, Tag>(p, wibble::singleton(t), wibble::Empty<Tag>())); + PatchList<string, string> change; + change.addPatch(Patch<string, string>(p, wibble::singleton(t), wibble::Empty<string>())); debtags.applyChange(change); // See that the patch is non empty - PatchList<string, Tag> tmp = debtags.changes(); + PatchList<string, string> tmp = debtags.changes(); assert(tmp.size() > 0); assert_eq(tmp.size(), 1u); @@ -211,8 +211,8 @@ struct TestDebtags : DebtagsTestEnvironment tags = debtags.getTagsOfItem(p); assert(!tags.empty()); - t = voc().tagByName("use::gameplaying"); - assert( t <= tags ); + t = "use::gameplaying"; + assert(tags.find(t) != tags.end()); // Save the patch debtags.savePatch(); @@ -252,18 +252,19 @@ struct TestDebtags : DebtagsTestEnvironment assert_eq(empty.timestamp(), 0); assert(!empty.hasData()); - tagcoll::PatchList<std::string, Tag> patches = empty.changes(); + tagcoll::PatchList<std::string, std::string> patches = empty.changes(); assert(patches.empty()); - set<Tag> res = empty.getTagsOfItem("apt"); - assert(res.empty()); - res = empty.getTagsOfItems(wibble::singleton(string("apt"))); + set<std::string> res = empty.getTagsOfItem("apt"); assert(res.empty()); + // TODO: currently does not compile because of a bug in tagcoll + //res = empty.getTagsOfItems(wibble::singleton(string("apt"))); + //assert(res.empty()); res = empty.getAllTags(); assert(res.empty()); - tagcoll::coll::Simple<string, Tag> coll; + tagcoll::coll::Simple<string, std::string> coll; empty.outputSystem(tagcoll::coll::inserter(coll)); assert_eq(coll.itemCount(), 0u); diff --git a/ept/debtags/expression.cc b/ept/debtags/expression.cc deleted file mode 100644 index 4a7967c..0000000 --- a/ept/debtags/expression.cc +++ /dev/null @@ -1,51 +0,0 @@ -/** \file - * Match tag expressions against sets of Debtags Tags - */ - -/* - * Copyright (C) 2003,2004,2005,2006,2007 Enrico Zini <enrico@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 <ept/debtags/expression.h> -#include <string> - -namespace tagcoll -{ - -template<> -bool Expression::operator()(const std::set<ept::debtags::Tag>& tags) const -{ - std::set<std::string> names; - for (std::set<ept::debtags::Tag>::const_iterator i = tags.begin(); - i != tags.end(); ++i) - names.insert(i->fullname()); - return this->m_impl->eval(names); -} - -template<> -bool Expression::operator()(const std::set<ept::debtags::Facet>& tags) const -{ - std::set<std::string> names; - for (std::set<ept::debtags::Facet>::const_iterator i = tags.begin(); - i != tags.end(); ++i) - names.insert(i->name()); - return this->m_impl->eval(names); -} - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/expression.h b/ept/debtags/expression.h deleted file mode 100644 index 45eb306..0000000 --- a/ept/debtags/expression.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef EPT_DEBTAGS_EXPRESSION_H -#define EPT_DEBTAGS_EXPRESSION_H - -/** \file - * Match tag expressions against sets of Debtags Tags - */ - -/* - * Copyright (C) 2003,2004,2005,2006,2007 Enrico Zini <enrico@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 <ept/debtags/tag.h> -#include <tagcoll/expression.h> -#include <set> - -namespace tagcoll -{ - -template<> -bool Expression::operator()(const std::set<ept::debtags::Tag>& tags) const; - -template<> -inline bool Expression::operator()(const std::set<ept::debtags::Facet>& tags) const; - -}; - -#endif -// vim:set ts=4 sw=4: diff --git a/ept/debtags/expression.test.h b/ept/debtags/expression.test.h index c96fd44..9f2ea08 100644 --- a/ept/debtags/expression.test.h +++ b/ept/debtags/expression.test.h @@ -20,7 +20,7 @@ #include <wibble/test.h> #include <ept/debtags/maint/path.h> -#include <ept/debtags/expression.h> +#include <tagcoll/expression.h> #include <ept/debtags/vocabulary.h> #include "debtags.test.h" @@ -34,10 +34,10 @@ struct TestExpression : DebtagsTestEnvironment { Test _1() { - set<Tag> test; - test.insert(voc.tagByName("use::editing")); - test.insert(voc.tagByName("use::viewing")); - test.insert(voc.tagByName("works-with::text")); + set<std::string> test; + test.insert("use::editing"); + test.insert("use::viewing"); + test.insert("works-with::text"); assert_eq(test.size(), 3u); diff --git a/ept/debtags/maint/debtagsindexer.cc b/ept/debtags/maint/debtagsindexer.cc deleted file mode 100644 index 6c8d6bc..0000000 --- a/ept/debtags/maint/debtagsindexer.cc +++ /dev/null @@ -1,265 +0,0 @@ -#include <ept/debtags/maint/debtagsindexer.h> -#include <ept/debtags/maint/path.h> -#include <ept/debtags/maint/pkgid.h> -#include <ept/debtags/maint/serializer.h> -#include <ept/debtags/vocabulary.h> - -#include <tagcoll/coll/intdiskindex.h> -#include <tagcoll/coll/simple.h> -#include <tagcoll/TextFormat.h> -#include <tagcoll/stream/filters.h> - -#include <wibble/exception.h> - -#include <cstring> - -using namespace std; - -namespace ept { -namespace debtags { - -/// MMapIndexer that indexes the package names -struct PkgIdGenerator : public tagcoll::diskindex::MMapIndexer -{ - // Sorted set of all available package names - std::set<std::string> pkgs; - - int encodedSize() const - { - int size = pkgs.size() * sizeof(int); - for (std::set<std::string>::const_iterator i = pkgs.begin(); - i != pkgs.end(); ++i) - size += i->size() + 1; - return tagcoll::diskindex::MMap::align(size); - } - - void encode(char* buf) const - { - int pos = pkgs.size() * sizeof(int); - int idx = 0; - for (std::set<std::string>::const_iterator i = pkgs.begin(); - i != pkgs.end(); ++i) - { - ((int*)buf)[idx++] = pos; - memcpy(buf + pos, i->c_str(), i->size() + 1); - pos += i->size() + 1; - } - } -}; - - -DebtagsIndexer::DebtagsIndexer(Vocabulary& voc) - : voc(voc), - mainSource(Path::debtagsSourceDir()), - userSource(Path::debtagsUserSourceDir()) -{ - rescan(); -} - -void DebtagsIndexer::rescan() -{ - ts_main_src = mainSource.timestamp(); - ts_user_src = userSource.timestamp(); - ts_main_tag = Path::timestamp(Path::tagdb()); - ts_main_idx = Path::timestamp(Path::tagdbIndex()); - ts_user_tag = Path::timestamp(Path::userTagdb()); - ts_user_idx = Path::timestamp(Path::userTagdbIndex()); -} - -bool DebtagsIndexer::needsRebuild() const -{ - // If there are no indexes of any kind, then we need rebuilding - if (ts_user_tag == 0 && ts_user_idx == 0 && ts_main_tag == 0 && ts_main_idx == 0) - return true; - - // If the user index is ok, then we are fine - if (ts_user_tag >= sourceTimestamp() && ts_user_idx >= sourceTimestamp()) - return false; - - // If there are user sources, then we cannot use the system index - if (ts_user_src > 0) - return true; - - // If there are no user sources, then we can fallback on the system - // indexes in case the user indexes are not up to date - if (ts_main_tag >= sourceTimestamp() && ts_main_idx >= sourceTimestamp()) - return false; - - return true; -} - -bool DebtagsIndexer::userIndexIsRedundant() const -{ - // If there is no user index, then it is not redundant - if (ts_user_tag == 0 && ts_user_idx == 0) - return false; - - // If we have user sources, then the user index is never redundant - if (ts_user_src > 0) - return false; - - // If the system index is not up to date, then the user index is not - // redundant - if (ts_main_tag < sourceTimestamp() || ts_main_idx < sourceTimestamp()) - return false; - - return true; -} - -bool DebtagsIndexer::rebuild(const std::string& tagfname, const std::string& idxfname) -{ - using namespace tagcoll; - - diskindex::MasterMMapIndexer master(idxfname); - - // Read and merge tag data - coll::Simple<string, string> merged; - mainSource.readTags(inserter(merged)); - userSource.readTags(inserter(merged)); - - if (merged.empty()) - //throw wibble::exception::Consistency("Reading debtags sources from " + Path::debtagsSourceDir() + " and " + Path::debtagsUserSourceDir(), "Unable to find any tag data"); - return false; - - // Create the pkgid index - PkgIdGenerator pkgidGen; - for (coll::Simple<string, string>::const_iterator i = merged.begin(); - i != merged.end(); ++i) - pkgidGen.pkgs.insert(i->first); - - // Temporary in-memory index to use for converting packages to ints while - // creating the debtags index - char buf[pkgidGen.encodedSize()]; - pkgidGen.encode(buf); - PkgId pkgid(buf, pkgidGen.encodedSize()); - - // Create the Debtags index - coll::IntDiskIndexer tagindexer; - merged.output(stringToInt(pkgid, voc, inserter(tagindexer))); - - // MMap 0: pkgid - master.append(pkgidGen); - // MMap 1: pkg->tag - master.append(tagindexer.pkgIndexer()); - // MMap 2: tag->pkg - master.append(tagindexer.tagIndexer()); - - // Write the tag database in text format - std::string tmpdb = tagfname + ".tmp"; - FILE* out = fopen(tmpdb.c_str(), "wt"); - if (!out) throw wibble::exception::File(tmpdb, "creating temporary copy of tag index"); - merged.output(textformat::StdioWriter(out)); - fclose(out); - - // Perform "atomic" update of the tag database - // FIXME: cannot be atomic because race conditions happening between file - // renames - if (rename(tmpdb.c_str(), tagfname.c_str()) == -1) - throw wibble::exception::System("Renaming " + tmpdb + " to " + tagfname); - - master.commit(); - return true; -} - -bool DebtagsIndexer::rebuildIfNeeded() -{ - if (needsRebuild()) - { - // Decide if we rebuild the user index or the system index - - if (ts_user_src == 0 && Path::access(Path::debtagsIndexDir(), W_OK) == 0) - { - // There are no user sources and we can write to the system index - // directory: rebuild the system index - if (!rebuild(Path::tagdb(), Path::tagdbIndex())) - return false; - ts_main_tag = Path::timestamp(Path::tagdb()); - ts_main_idx = Path::timestamp(Path::tagdbIndex()); - if (Path::tagdb() == Path::userTagdb()) - ts_user_tag = ts_main_tag; - if (Path::tagdbIndex() == Path::userTagdbIndex()) - ts_user_idx = ts_main_idx; - } else { - wibble::sys::fs::mkFilePath(Path::userTagdb()); - wibble::sys::fs::mkFilePath(Path::userTagdbIndex()); - if (!rebuild(Path::userTagdb(), Path::userTagdbIndex())) - return false; - ts_user_tag = Path::timestamp(Path::userTagdb()); - ts_user_idx = Path::timestamp(Path::userTagdbIndex()); - } - return true; - } - return false; -} - -bool DebtagsIndexer::deleteRedundantUserIndex() -{ - if (userIndexIsRedundant()) - { - // Delete the user indexes if they exist - if (Path::tagdb() != Path::userTagdb()) - { - unlink(Path::userTagdb().c_str()); - ts_user_tag = 0; - } - if (Path::tagdbIndex() != Path::userTagdbIndex()) - { - unlink(Path::userTagdbIndex().c_str()); - ts_user_idx = 0; - } - return true; - } - return false; -} - -bool DebtagsIndexer::getUpToDateTagdb(std::string& tagfname, std::string& idxfname) -{ - // If there are no indexes of any kind, then we have nothing to return - if (ts_user_tag == 0 && ts_user_idx == 0 && ts_main_tag == 0 && ts_main_idx == 0) - return false; - - // If the user index is up to date, use it - if (ts_user_tag >= sourceTimestamp() && - ts_user_idx >= sourceTimestamp()) - { - tagfname = Path::userTagdb(); - idxfname = Path::userTagdbIndex(); - return true; - } - - // If the user index is not up to date and we have user sources, we cannot - // fall back to the system index - if (ts_user_src != 0) - return false; - - // Fallback to the system index - if (ts_main_tag >= sourceTimestamp() && - ts_main_idx >= sourceTimestamp()) - { - tagfname = Path::tagdb(); - idxfname = Path::tagdbIndex(); - return true; - } - - return false; -} - - - -bool DebtagsIndexer::obtainWorkingDebtags(Vocabulary& voc, std::string& tagfname, std::string& idxfname) -{ - DebtagsIndexer t(voc); - - t.rebuildIfNeeded(); - t.deleteRedundantUserIndex(); - return t.getUpToDateTagdb(tagfname, idxfname); -} - -} -} - -#include <ept/debtags/maint/sourcedir.tcc> -#include <tagcoll/coll/simple.tcc> - -// vim:set ts=4 sw=4: -// -*- C++ -*- diff --git a/ept/debtags/maint/debtagsindexer.h b/ept/debtags/maint/debtagsindexer.h deleted file mode 100644 index b702c88..0000000 --- a/ept/debtags/maint/debtagsindexer.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef EPT_DEBTAGS_DEBTAGSINDEXER_H -#define EPT_DEBTAGS_DEBTAGSINDEXER_H - -#include <ept/debtags/maint/sourcedir.h> -#include <string> - -namespace ept { -namespace debtags { - -class Vocabulary; - -struct DebtagsIndexer -{ - Vocabulary& voc; - - SourceDir mainSource; - SourceDir userSource; - time_t ts_main_src; - time_t ts_user_src; - time_t ts_main_tag; - time_t ts_main_idx; - time_t ts_user_tag; - time_t ts_user_idx; - - time_t sourceTimestamp() const - { - time_t res = ts_main_src; - if (ts_user_src > res) res = ts_user_src; - return res; - } - bool needsRebuild() const; - bool rebuild(const std::string& tagfname, const std::string& idxfname); - bool rebuildIfNeeded(); - bool getUpToDateTagdb(std::string& tagfname, std::string& idxfname); - - bool userIndexIsRedundant() const; - bool deleteRedundantUserIndex(); - - void rescan(); - - DebtagsIndexer(Vocabulary& voc); - - static bool obtainWorkingDebtags(Vocabulary& voc, std::string& tagfname, std::string& idxfname); -}; - - -} -} - -// vim:set ts=4 sw=4: -#endif diff --git a/ept/debtags/maint/pkgid.cc b/ept/debtags/maint/pkgid.cc deleted file mode 100644 index c78d7c1..0000000 --- a/ept/debtags/maint/pkgid.cc +++ /dev/null @@ -1,66 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- - -/** @file - * @author Enrico Zini <enrico@enricozini.org> - * Quick map from package IDs to package names - */ - -/* - * Copyright (C) 2003-2007 Enrico Zini <enrico@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 <ept/debtags/maint/pkgid.h> -#include <ept/debtags/maint/path.h> - -namespace ept { -namespace debtags { - -PkgId::PkgId() {} - -PkgId::PkgId(const char* buf, int size) - : MMap(buf, size) {} - -PkgId::PkgId(const tagcoll::diskindex::MasterMMap& master, size_t idx) - : MMap(master, idx) {} - -int PkgId::byName(const std::string& name) const -{ - // Binary search the index to find the package ID - int begin, end; - - /* Binary search */ - begin = -1, end = size(); - while (end - begin > 1) - { - int cur = (end + begin) / 2; - if (byID(cur) > name) - end = cur; - else - begin = cur; - } - - if (begin == -1 || byID(begin) != name) - //throw NotFoundException(string("looking for the ID of string ") + str); - return -1; - else - return begin; -} - -} -} - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/maint/pkgid.h b/ept/debtags/maint/pkgid.h deleted file mode 100644 index e193f8c..0000000 --- a/ept/debtags/maint/pkgid.h +++ /dev/null @@ -1,91 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -#ifndef EPT_DEBTAGS_PKGID_H -#define EPT_DEBTAGS_PKGID_H - -/** @file - * @author Enrico Zini <enrico@enricozini.org> - * Quick map from package IDs to package names - */ - -/* - * Copyright (C) 2003-2007 Enrico Zini <enrico@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 <tagcoll/diskindex/mmap.h> -#include <string> - -namespace ept { -namespace debtags { - -/** - * Maps Packages to IDs and vice-versa. - * - * This is used in building the Debtags fast index, which works representing - * tags and packages as int IDs - */ -class PkgId : public tagcoll::diskindex::MMap -{ - tagcoll::diskindex::MasterMMap mastermmap; - time_t m_timestamp; - -public: - PkgId(); - PkgId(const tagcoll::diskindex::MasterMMap& master, size_t idx); - PkgId(const char* buf, int size); - - /// Get the timestamp of when the index was last updated - time_t timestamp() const { return m_timestamp; } - - /// Get the number of packages in the index - size_t size() const { return m_buf ? *(int*)m_buf / sizeof(int) : 0; } - - /** - * Get the ID of a package given its name. - * - * If not found, returns -1. - */ - int byName(const std::string& name) const; - - /** - * Get a package name given its ID. - * - * If not found, returns the empty string. - */ - std::string byID(int id) const - { - if (id >= 0 || static_cast<unsigned>(id) < size()) - return std::string(m_buf + ((int*)m_buf)[id]); - return std::string(); - } - - /// Get the number of packages in the index - int size(int id) const - { - if (id < 0 || (unsigned)id >= size()) - return 0; - if ((unsigned)id == size() - 1) - return m_size - ((int*)m_buf)[id] - 1; - else - return ((int*)m_buf)[id + 1] - ((int*)m_buf)[id] - 1; - } -}; - -} -} - -// vim:set ts=4 sw=4: -#endif diff --git a/ept/debtags/maint/pkgid.test.h b/ept/debtags/maint/pkgid.test.h deleted file mode 100644 index d49b72c..0000000 --- a/ept/debtags/maint/pkgid.test.h +++ /dev/null @@ -1,75 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -/* - * id->package mapping - * - * Copyright (C) 2006 Enrico Zini <enrico@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 <ept/debtags/maint/pkgid.h> -#include <ept/debtags/maint/path.h> -#include <ept/debtags/debtags.h> -#include <set> - -#include <ept/test.h> - -using namespace std; -using namespace ept; -using namespace ept::debtags; - -struct TestPkgid : DebtagsTestEnvironment -{ - Debtags debtags; - PkgId& pkgid; - - TestPkgid() - : pkgid(debtags.pkgid()) - { - } - -// Check that we can go from name to ID and back - Test _1() -{ - //int x = 0; - for (Debtags::const_iterator i = debtags.begin(); - i != debtags.end(); ++i) - { - int id = pkgid.byName(i->first); - std::string pkg = pkgid.byID(id); - assert(i->first == pkg); - - /* std::cerr << x << ": " << i->id() << ": " - << i->name() << ", " << pkgidx().name( i->id() ) << - std::endl; */ - //++ x; - } -} - -// Check that IDs are distinct - Test _2() -{ - using namespace std; - - size_t count = 0; - set<int> ids; - for (Debtags::const_iterator i = debtags.begin(); i != debtags.end(); ++i, ++count) - ids.insert(pkgid.byName(i->first)); - assert_eq(ids.size(), count); -} - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/maint/serializer.h b/ept/debtags/maint/serializer.h deleted file mode 100644 index 57c4c81..0000000 --- a/ept/debtags/maint/serializer.h +++ /dev/null @@ -1,949 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -/** - * @file cache/component/debtags/serializer.h - * @author Enrico Zini (enrico) <enrico@enricozini.org> - */ - -#ifndef EPT_DEBTAGS_SERIALIZER_H -#define EPT_DEBTAGS_SERIALIZER_H - -#include <ept/debtags/vocabulary.h> -#include <ept/debtags/maint/pkgid.h> -#include <tagcoll/patch.h> -#include <wibble/mixin.h> -#include <string> - -namespace ept { -namespace debtags { - -template<typename OUT> -class IntToPkg : public wibble::mixin::OutputIterator< IntToPkg<OUT> > -{ - PkgId& pkgid; - Vocabulary& voc; - OUT out; - -public: - IntToPkg(PkgId& pkgid, Vocabulary& voc, const OUT& out) - : pkgid(pkgid), voc(voc), out(out) {} - - template<typename ITEMS, typename TAGS> - IntToPkg<OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - std::set<std::string> ritems; - std::set<Tag> rtags; - - for (typename ITEMS::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - { - std::string pkg = pkgid.byID(*i); - if (!pkg.empty()) - ritems.insert(pkg); - } - - for (typename TAGS::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - { - Tag t = voc.tagByID(*i); - if (t.valid()) - rtags.insert(t); - } - - if (!ritems.empty() && !rtags.empty()) - { - *out = make_pair(ritems, rtags); - ++out; - } - return *this; - } -}; - -template<typename OUT> -IntToPkg<OUT> intToPkg(PkgId& pkgid, Vocabulary& voc, const OUT& out) -{ - return IntToPkg<OUT>(pkgid, voc, out); -} - -template<typename OUT> -class StringToInt : public wibble::mixin::OutputIterator< StringToInt<OUT> > -{ - PkgId& pkgid; - Vocabulary& voc; - OUT out; - -public: - StringToInt(PkgId& pkgid, Vocabulary& voc, const OUT& out) - : pkgid(pkgid), voc(voc), out(out) {} - - template<typename ITEMS, typename TAGS> - StringToInt<OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - std::set<int> ritems; - std::set<int> rtags; - - for (typename ITEMS::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - { - int id = pkgid.byName(*i); - if (id != -1) - ritems.insert(id); - } - - for (typename TAGS::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - { - Tag t = voc.tagByName(*i); - if (t.valid()) - rtags.insert(t.id()); - } - - if (!ritems.empty() && !rtags.empty()) - { - *out = make_pair(ritems, rtags); - ++out; - } - return *this; - } - -}; - -template<typename OUT> -StringToInt<OUT> stringToInt(PkgId& pkgid, Vocabulary& voc, const OUT& out) -{ - return StringToInt<OUT>(pkgid, voc, out); -} - -template<typename OUT> -class StringToPkg : public wibble::mixin::OutputIterator< StringToPkg<OUT> > -{ - PkgId& pkgid; - Vocabulary& voc; - OUT out; - -public: - StringToPkg(PkgId& pkgid, Vocabulary& voc, const OUT& out) - : pkgid(pkgid), voc(voc), out(out) {} - - template<typename ITEMS, typename TAGS> - StringToPkg<OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - std::set<std::string> ritems; - std::set<Tag> rtags; - - for (typename ITEMS::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - { - // Ensure that the package exists in the pkgid database - if (pkgid.byName(*i) == -1) - continue; - ritems.insert(*i); - } - - for (typename TAGS::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - { - Tag t = voc.tagByName(*i); - if (t.valid()) - rtags.insert(t); - } - - if (!ritems.empty() && !rtags.empty()) - { - *out = make_pair(ritems, rtags); - ++out; - } - return *this; - } - -}; - -template<typename OUT> -StringToPkg<OUT> stringToPkg(PkgId& pkgid, Vocabulary& voc, const OUT& out) -{ - return StringToPkg<OUT>(pkgid, voc, out); -} - -template<typename OUT> -class PkgToString : public wibble::mixin::OutputIterator< PkgToString<OUT> > -{ - OUT out; -public: - PkgToString(const OUT& out) : out(out) {} - - template<typename ITEMS, typename TAGS> - PkgToString<OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - std::set<std::string> stags; - for (typename TAGS::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - if (i->valid()) - stags.insert(i->fullname()); - *out = make_pair(data.first, stags); - ++out; - return *this; - } -}; - -template<typename OUT> -PkgToString<OUT> pkgToString(const OUT& out) -{ - return PkgToString<OUT>(out); -} - -template<typename OUT> -class PatchStringToInt : public wibble::mixin::OutputIterator< PatchStringToInt<OUT> > -{ - PkgId& pkgid; - Vocabulary& voc; - OUT out; - -public: - PatchStringToInt(PkgId& pkgid, Vocabulary& voc, const OUT& out) - : pkgid(pkgid), voc(voc), out(out) {} - - PatchStringToInt<OUT>& operator=(const tagcoll::Patch<std::string, std::string>& patch) - { - int id = pkgid.byName(patch.item); - if (id == -1) - return *this; - - tagcoll::Patch<int, int> res(id); - for (std::set<std::string>::const_iterator i = patch.added.begin(); - i != patch.added.end(); ++i) - { - Tag tag = voc.tagByName(*i); - if (tag.valid()) - res.add(tag.id()); - } - for (std::set<std::string>::const_iterator i = patch.removed.begin(); - i != patch.removed.end(); ++i) - { - Tag tag = voc.tagByName(*i); - if (tag.valid()) - res.remove(tag.id()); - } - *out = res; - ++out; - return *this; - } -}; - -template<typename OUT> -PatchStringToInt<OUT> patchStringToInt(PkgId& pkgid, Vocabulary& voc, const OUT& out) -{ - return PatchStringToInt<OUT>(pkgid, voc, out); -} - -template<typename OUT> -class PatchIntToString : public wibble::mixin::OutputIterator< PatchIntToString<OUT> > -{ - PkgId& pkgid; - Vocabulary& voc; - OUT out; - -public: - PatchIntToString(PkgId& pkgid, Vocabulary& voc, const OUT& out) - : pkgid(pkgid), voc(voc), out(out) {} - - PatchIntToString<OUT>& operator=(const tagcoll::Patch<int, int>& patch) - { - std::string name = pkgid.byID(patch.item); - if (name.empty()) - return *this; - - tagcoll::Patch<std::string, std::string> res(name); - for (std::set<int>::const_iterator i = patch.added.begin(); - i != patch.added.end(); ++i) - { - Tag tag = voc.tagByID(*i); - if (tag.valid()) - res.add(tag.fullname()); - } - for (std::set<int>::const_iterator i = patch.removed.begin(); - i != patch.removed.end(); ++i) - { - Tag tag = voc.tagByID(*i); - if (tag.valid()) - res.remove(tag.fullname()); - } - *out = res; - ++out; - return *this; - } -}; - -template<typename OUT> -PatchIntToString<OUT> patchIntToString(PkgId& pkgid, Vocabulary& voc, const OUT& out) -{ - return PatchIntToString<OUT>(pkgid, voc, out); -} - -#if 0 - GOOD STUFF - -template<typename OUT> -class ToInt : public wibble::mixin::OutputIterator< ToInt<OUT> > -{ - OUT out; -public: - ToInt(const OUT& out) : out(out) {} - - template<typename ITEMS, typename TAGS> - ToInt<OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - std::set<int> iitems; - std::set<int> itags; - for (typename ITEMS::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - if (i->valid()) - iitems.insert(i->ondiskId()); - for (typename TAGS::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - if (i->valid()) - itags.insert(i->id()); - *out = make_pair(iitems, itags); - ++out; - return *this; - } -}; - -template<typename OUT> -ToInt<OUT> toInt(const OUT& out) -{ - return ToInt<OUT>(out); -} - -template<typename ITEMCONV, typename TAGCONV, typename OUT> -class Converter : public wibble::mixin::OutputIterator< Converter<ITEMCONV, TAGCONV, OUT> > -{ - ITEMCONV itemconv; - TAGCONV tagconv; - OUT out; - -public: - Converter(const ITEMCONV& itemconv, const TAGCONV& tagconv, const OUT& out) - : itemconv(itemconv), tagconv(tagconv), out(out) {} - - template<typename ITEMS, typename TAGS> - Converter<ITEMCONV, TAGCONV, OUT>& operator=(const std::pair<ITEMS, TAGS>& data) - { - *out = make_pair(itemconv(data.first), tagconv(data.second)); - ++out; - return *this; - } -}; - -template<typename ITEMCONV, typename TAGCONV, typename OUT> -Converter<ITEMCONV, TAGCONV, OUT> converter(const ITEMCONV& itemconv, const TAGCONV& tagconv, const OUT& out) -{ - return Converter<ITEMCONV, TAGCONV, OUT>(itemconv, tagconv, out); -} - - -template<typename OUT> -class PatchToString : public wibble::mixin::OutputIterator< PatchToString<OUT> > -{ - OUT out; - -public: - PatchToString(const OUT& out) : out(out) {} - - template<typename PKG, typename TAG> - PatchToString<OUT>& operator=(const tagcoll::Patch<PKG, TAG>& patch) - { - if (!patch.item.valid()) - return *this; - - tagcoll::Patch<std::string, std::string> res(patch.item.name()); - for (typename std::set<TAG>::const_iterator i = patch.added.begin(); - i != patch.added.end(); ++i) - if (i->valid()) - res.add(i->fullname()); - for (typename std::set<TAG>::const_iterator i = patch.removed.begin(); - i != patch.removed.end(); ++i) - if (i->valid()) - res.remove(i->fullname()); - *out = res; - ++out; - return *this; - } -}; - -template<typename OUT> -PatchToString<OUT> patchToString(const OUT& out) -{ - return PatchToString<OUT>(out); -} - -#endif - -} -} - -#if 0 - -namespace tagcoll { -namespace coll { - -template<> -struct coll_traits< ept::cache::debtags::DebtagsIndex > -{ - typedef ept::cache::Package<> item_type; - typedef ept::cache::debtags::Tag tag_type; - typedef std::set< ept::cache::Package<> > itemset_type; - typedef std::set<ept::cache::debtags::Tag> tagset_type; -}; - -} -} - -namespace ept { -namespace cache { -namespace debtags { - -#if 0 -/** - * Convert Facets to ints - */ -class FacetIntConverter : public Implementation<FacetIntConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Facet, int>, - public Tagcoll::Converter<int, aptFront::cache::entity::Facet> -{ - typedef aptFront::cache::entity::Facet Facet; - typedef Tagcoll::OpSet<aptFront::cache::entity::Facet> FacetSet; - typedef Tagcoll::OpSet<int> IntSet; -public: - virtual int operator()(const aptFront::cache::entity::Facet& item) const; - virtual aptFront::cache::entity::Facet operator()(const int& item) const; - - virtual IntSet operator()(const FacetSet& item) const - { return Tagcoll::Converter<Facet, int>::operator()(item); } - virtual FacetSet operator()(const IntSet& item) const - { return Tagcoll::Converter<int, Facet>::operator()(item); } - - static std::string componentName(); -}; - -/** - * Convert Facets to strings - */ -class FacetStringConverter : public Implementation<FacetStringConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Facet, std::string>, - public Tagcoll::Converter<std::string, aptFront::cache::entity::Facet> -{ - typedef aptFront::cache::entity::Facet Facet; - typedef Tagcoll::OpSet<aptFront::cache::entity::Facet> FacetSet; - typedef Tagcoll::OpSet<std::string> StringSet; -public: - virtual std::string operator()(const aptFront::cache::entity::Facet& item) const; - virtual aptFront::cache::entity::Facet operator()(const std::string& item) const; - - virtual StringSet operator()(const FacetSet& item) const - { return Tagcoll::Converter<Facet, std::string>::operator()(item); } - virtual FacetSet operator()(const StringSet& item) const - { return Tagcoll::Converter<std::string, Facet>::operator()(item); } - - static std::string componentName(); -}; - -/** - * Convert Vocabulary to ints - */ -class TagIntConverter : public Implementation<TagIntConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Tag, int>, - public Tagcoll::Converter<int, aptFront::cache::entity::Tag> -{ - typedef aptFront::cache::entity::Tag Tag; - typedef Tagcoll::OpSet<aptFront::cache::entity::Tag> TagSet; - typedef Tagcoll::OpSet<int> IntSet; -public: - virtual int operator()(const aptFront::cache::entity::Tag& item) const; - virtual aptFront::cache::entity::Tag operator()(const int& item) const; - - virtual IntSet operator()(const TagSet& item) const - { return Tagcoll::Converter<Tag, int>::operator()(item); } - virtual TagSet operator()(const IntSet& item) const - { return Tagcoll::Converter<int, Tag>::operator()(item); } - - static std::string componentName(); -}; - -/** - * Convert Vocabulary to strings - */ -class TagStringConverter : public Implementation<TagStringConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Tag, std::string>, - public Tagcoll::Converter<std::string, aptFront::cache::entity::Tag> -{ - typedef aptFront::cache::entity::Tag Tag; - typedef Tagcoll::OpSet<aptFront::cache::entity::Tag> TagSet; - typedef Tagcoll::OpSet<std::string> StringSet; -public: - virtual std::string operator()(const Tag& item) const; - virtual Tag operator()(const std::string& item) const; - - virtual StringSet operator()(const TagSet& item) const - { return Tagcoll::Converter<Tag, std::string>::operator()(item); } - virtual TagSet operator()(const StringSet& item) const - { return Tagcoll::Converter<std::string, Tag>::operator()(item); } - - TagSet parseTagList(const std::string& str) const; - - static std::string componentName(); -}; - -/** - * Convert Aggregator to ints - */ -class PackageIntConverter : public Implementation<PackageIntConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Package, int>, - public Tagcoll::Converter<int, aptFront::cache::entity::Package> -{ - typedef aptFront::cache::entity::Package Package; - typedef Tagcoll::OpSet<aptFront::cache::entity::Package> PackageSet; - typedef Tagcoll::OpSet<int> IntSet; -public: - virtual int operator()(const Package& item) const; - virtual Package operator()(const int& item) const; - - virtual IntSet operator()(const PackageSet& item) const - { return Tagcoll::Converter<Package, int>::operator()(item); } - virtual PackageSet operator()(const IntSet& item) const - { return Tagcoll::Converter<int, Package>::operator()(item); } - - static std::string componentName(); -}; - -/** - * Convert Aggregator to strings - */ -class PackageStringConverter : public Implementation<PackageStringConverter>, - public Tagcoll::Converter<aptFront::cache::entity::Package, std::string>, - public Tagcoll::Converter<std::string, aptFront::cache::entity::Package> -{ - typedef aptFront::cache::entity::Package Package; - typedef Tagcoll::OpSet<aptFront::cache::entity::Package> PackageSet; - typedef Tagcoll::OpSet<std::string> StringSet; -public: - virtual std::string operator()(const Package& item) const; - virtual Package operator()(const std::string& item) const; - - virtual StringSet operator()(const PackageSet& item) const - { return Tagcoll::Converter<Package, std::string>::operator()(item); } - virtual PackageSet operator()(const StringSet& item) const - { return Tagcoll::Converter<std::string, Package>::operator()(item); } - - static std::string componentName(); -}; - -#endif - -} -} -} - -#endif - -#endif -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- - -#if 0 -/** - * @file cache/debtags/serializer.h - * @author Enrico Zini (enrico) <enrico@enricozini.org> - */ - -#ifndef EPT_CACHE_DEBTAGS_SERIALIZER_TCC -#define EPT_CACHE_DEBTAGS_SERIALIZER_TCC - -#include <ept/cache/debtags/serializer.h> -#if 0 -#include <ept/cache/debtags/pkgidx.h> -#include <ept/cache/debtags/vocabulary.h> -#include <ept/cache/package.h> -//#include <ept/cache/cache.h> -#endif - -namespace ept { -namespace t { -namespace cache { -namespace debtags { - - - -#if 0 -string FacetIntConverter::componentName() { return "FacetIntConverter"; } - -int FacetIntConverter::operator()(const aptFront::cache::entity::Facet& item) const -{ - if (!item.valid()) return -1; - return item.id(); -} -aptFront::cache::entity::Facet FacetIntConverter::operator()(const int& item) const -{ - return cache().tags().facetByID(item); -} - -string FacetStringConverter::componentName() { return "FacetStringConverter"; } - -std::string FacetStringConverter::operator()(const aptFront::cache::entity::Facet& item) const -{ - if (!item.valid()) return string(); - return item.name(); -} -aptFront::cache::entity::Facet FacetStringConverter::operator()(const std::string& item) const -{ - return cache().tags().facetByName(item); -} - -string TagIntConverter::componentName() { return "TagIntConverter"; } - -int TagIntConverter::operator()(const aptFront::cache::entity::Tag& item) const -{ - if (!item.valid()) return -1; - return item.id(); -} -aptFront::cache::entity::Tag TagIntConverter::operator()(const int& item) const -{ - return cache().tags().tagByID(item); -} - -string TagStringConverter::componentName() { return "TagStringConverter"; } - -std::string TagStringConverter::operator()(const aptFront::cache::entity::Tag& item) const -{ - if (!item.valid()) return string(); - return item.fullname(); -} -aptFront::cache::entity::Tag TagStringConverter::operator()(const std::string& item) const -{ - return cache().tags().tagByName(item); -} - -Tagcoll::OpSet<entity::Tag> TagStringConverter::parseTagList(const std::string& str) const -{ - if (str.empty()) - return Tagcoll::OpSet<entity::Tag>(); - - size_t i = str.find(", "); - if (i == string::npos) - { - // Check if we need curly brace expansion - if (str[str.size() - 1] == '}') - { - using namespace std; - Tagcoll::OpSet<entity::Tag> res; - size_t begin = str.find('{'); - if (begin == string::npos) - return res; - string prefix(str, 0, begin); - ++begin; - size_t end; - while ((end = str.find(',', begin)) != string::npos) - { - res += (*this)(prefix + str.substr(begin, end-begin)); - begin = end + 1; - } - res += (*this)(prefix + str.substr(begin, str.size() - 1 - begin)); - return res; - } else { - entity::Tag t = (*this)(str); - if (t.valid()) - return Tagcoll::OpSet<entity::Tag>() + t; - else - return Tagcoll::OpSet<entity::Tag>(); - } - } else { - return parseTagList(string(str, 0, i)) + parseTagList(string(str, i+2)); - } -} - -string PackageIntConverter::componentName() { return "PackageIntConverter"; } - -int PackageIntConverter::operator()(const aptFront::cache::entity::Package& item) const -{ - if (!item.valid()) return -1; - return item.id(); -} -aptFront::cache::entity::Package PackageIntConverter::operator()(const int& item) const -{ - PkgIdx& p = cache().pkgidx(); - return cache().packages().packageByName(string(p.name(item), p.size(item))); -} - -string PackageStringConverter::componentName() { return "PackageStringConverter"; } - -std::string PackageStringConverter::operator()(const aptFront::cache::entity::Package& item) const -{ - if (!item.valid()) return string(); - return item.name(); -} -aptFront::cache::entity::Package PackageStringConverter::operator()(const std::string& item) const -{ - return cache().packages().packageByName(item); -} -#endif - -} -} - -#endif - -#if 0 -#ifdef COMPILE_TESTSUITE -//#include <apt-front/cache/component/debtags/update.h> -#include <iostream> -#include "test-utils.h" - -namespace tut { -using namespace aptFront::cache; -using namespace component; -using namespace debtags; -using namespace std; - -struct cache_component_debtags_serializer_shar { - cache_component_debtags_serializer_shar () { - aptInit (); - ok = true; - debtags::fetchNewData(); - c.open( Cache::OpenDefault | - Cache::OpenReadOnly | Cache::OpenDebtags ); - } - void check() { - if (ok) return; - ok = true; - throw warning( "debtags init failed, cancelling" ); - } - ~cache_component_debtags_serializer_shar() { - check(); - } - Cache c; - bool ok; -}; - -TESTGRP( cache_component_debtags_serializer ); - -using namespace Tagcoll; - -template<> template<> -void to::test<1> () -{ - check(); - - PackageStringConverter& psc = c.packagestringconverter(); - - ensure(psc("Slartibartsfart") == entity::Package()); - - /* Get the 'debtags' package */ - entity::Package p = c.packages().packageByName( "debtags" ); - ensure(p.valid()); - - /* Get the 'debtags' package using the serializer */ - entity::Package p1 = psc("debtags"); - ensure(p1.valid()); - - /* They must be the same */ - ensure(p == p1); - - ensure_equals(psc(p), "debtags"); - ensure_equals(psc(p1), "debtags"); - ensure_equals(psc(p), psc(p1)); - - /* If there is an invalid package to serialize, it should be discarded */ - { - Tagcoll::OpSet<entity::Package> pkgs; - pkgs += c.packages().packageByName( "debtags" ); - pkgs += c.packages().packageByName( "tagcoll" ); - pkgs += entity::Package(); - - ensure_equals (pkgs.size(), 3u); - ensure_equals (psc(pkgs).size(), 2u); - ensure (psc(pkgs).contains("debtags")); - ensure (psc(pkgs).contains("tagcoll")); - } - - /* If there is an invalid package to serialize, it should be discarded */ - { - Tagcoll::OpSet<std::string> pkgs; - pkgs += "debtags"; - pkgs += "tagcoll"; - pkgs += "Slartibartsfart"; - - ensure_equals (pkgs.size(), 3u); - ensure_equals (psc(pkgs).size(), 2u); - ensure (psc(pkgs).contains(psc("debtags"))); - ensure (psc(pkgs).contains(psc("tagcoll"))); - ensure (!psc(pkgs).contains(entity::Package())); - } -} - -ostream& operator<<(ostream& out, const entity::Package& pkg) -{ - if (pkg.valid()) - return out << pkg.name(); - else - return out << "(invalid package)"; -} - -// Check that package conversions work two-way -template<> template<> -void to::test<2> () -{ - PackageStringConverter& psc = c.packagestringconverter(); - for (component::Aggregator::iterator i = c.packages().packagesBegin(); - i != c.packages().packagesEnd(); ++i) - { - try { - ensure_equals(*i, psc(psc(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[string] of package " << i->name(string("(invalid package)")) << endl; - throw; - } - } - - PackageIntConverter& pic = c.packageintconverter(); - for (component::Aggregator::iterator i = c.packages().packagesBegin(); - i != c.packages().packagesEnd(); ++i) - { - try { - ensure_equals(*i, pic(pic(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[int] of package " << i->name(string("(invalid package)")) << endl; - throw; - } - } -} - -// Check that facet conversions work two-way -template<> template<> -void to::test<3> () -{ - typedef Tagcoll::OpSet<entity::Facet> FacetSet; - - FacetStringConverter& fsc = c.facetstringconverter(); - FacetSet allFacets(c.tags().facets()); - for (FacetSet::const_iterator i = allFacets.begin(); i != allFacets.end(); i++) - { - try { - ensure_equals(*i, fsc(fsc(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[string] of facet " << i->name() << endl; - throw; - } - } - - FacetIntConverter& fic = c.facetintconverter(); - for (FacetSet::const_iterator i = allFacets.begin(); i != allFacets.end(); i++) - { - try { - ensure_equals(*i, fic(fic(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[int] of facet " << i->name() << endl; - throw; - } - } -} - -// Check that tag conversions work two-way -template<> template<> -void to::test<4> () -{ - typedef Tagcoll::OpSet<entity::Tag> TagSet; - - TagStringConverter& tsc = c.tagstringconverter(); - TagSet allTags(c.tags().tags()); - for (TagSet::const_iterator i = allTags.begin(); i != allTags.end(); i++) - { - try { - ensure_equals(*i, tsc(tsc(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[string] of tag " << i->fullname() << endl; - throw; - } - } - - TagIntConverter& tic = c.tagintconverter(); - for (TagSet::const_iterator i = allTags.begin(); i != allTags.end(); i++) - { - try { - ensure_equals(*i, tic(tic(*i))); - } catch (...) { - cerr << "Note: exception thrown during processing[int] of tag " << i->fullname() << endl; - throw; - } - } -} - -// Check TagStringConverter::parseTagList -template<> template<> -void to::test<5> () -{ - TagStringConverter& tsc = c.tagstringconverter(); - OpSet<entity::Tag> ts; - - // First ensure that we're using existing tags as samples - ensure(tsc("accessibility::TODO") != entity::Tag()); - ensure(tsc("role::sw:devel-lib") != entity::Tag()); - ensure(tsc("x11::xserver") != entity::Tag()); - ensure(tsc("antani") == entity::Tag()); - ensure(tsc("blinda") == entity::Tag()); - ensure(tsc("supercazzola") == entity::Tag()); - - ts = tsc.parseTagList("role::sw:devel-lib"); - ensure_equals(ts.size(), 1u); - ensure(ts.contains(tsc("role::sw:devel-lib"))); - - ts = tsc.parseTagList("accessibility::TODO, x11::xserver, role::sw:devel-lib"); - ensure_equals(ts.size(), 3u); - ensure(ts.contains(tsc("accessibility::TODO"))); - ensure(ts.contains(tsc("role::sw:devel-lib"))); - ensure(ts.contains(tsc("x11::xserver"))); - - ts = tsc.parseTagList("antani"); - ensure_equals(ts.size(), 0u); - - ts = tsc.parseTagList("antani, blinda, supercazzola"); - ensure_equals(ts.size(), 0u); - - ts = tsc.parseTagList("antani, x11::xserver, blinda"); - ensure_equals(ts.size(), 1u); - ensure(ts.contains(tsc("x11::xserver"))); -} - -// Check TagStringConverter::parseTagList's handling of curly brace expansion -template<> template<> -void to::test<6> () -{ - TagStringConverter& tsc = c.tagstringconverter(); - OpSet<entity::Tag> ts; - - // First ensure that we're using existing tags as samples - ensure(tsc("role::TODO") != entity::Tag()); - ensure(tsc("role::sw:server") != entity::Tag()); - ensure(tsc("role::aux:dummy") != entity::Tag()); - ensure(tsc("role::sw:amusement") != entity::Tag()); - ensure(tsc("role::sw:server{}") == entity::Tag()); - ensure(tsc("role::{}") == entity::Tag()); - ensure(tsc("role::{") == entity::Tag()); - ensure(tsc("role::}") == entity::Tag()); - - ts = tsc.parseTagList("role::{TODO,sw:server,aux:dummy,sw:amusement}"); - ensure_equals(ts.size(), 4u); - ensure(ts.contains(tsc("role::TODO"))); - ensure(ts.contains(tsc("role::sw:server"))); - ensure(ts.contains(tsc("role::aux:dummy"))); - ensure(ts.contains(tsc("role::sw:amusement"))); - - ts = tsc.parseTagList("role::{TODO,aux:dummy}, role::sw:{server,amusement}"); - ensure_equals(ts.size(), 4u); - ensure(ts.contains(tsc("role::TODO"))); - ensure(ts.contains(tsc("role::sw:server"))); - ensure(ts.contains(tsc("role::aux:dummy"))); - ensure(ts.contains(tsc("role::sw:amusement"))); -} - -} -#endif -#endif -#endif -// vim:set ts=4 sw=4: diff --git a/ept/debtags/maint/serializer.test.h b/ept/debtags/maint/serializer.test.h deleted file mode 100644 index 6a4f3a6..0000000 --- a/ept/debtags/maint/serializer.test.h +++ /dev/null @@ -1,133 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -/** - * @file - * @author Enrico Zini (enrico) <enrico@enricozini.org> - */ - -/* - * Tests for Debtags serialization filters - * - * Copyright (C) 2003-2007 Enrico Zini <enrico@debian.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <ept/debtags/maint/serializer.h> -#include <ept/debtags/maint/pkgid.h> -#include <ept/debtags/maint/path.h> -#include <ept/debtags/vocabulary.h> -#include <ept/debtags/debtags.h> - -#include <tagcoll/coll/simple.h> - -#include <wibble/singleton.h> - -#include <ept/test.h> - -using namespace std; -using namespace tagcoll; -using namespace ept; -using namespace ept::debtags; - -struct TestSerializer : DebtagsTestEnvironment -{ - Debtags debtags; - Vocabulary& voc; - PkgId& pkgid; - - TestSerializer() - : voc(debtags.vocabulary()), pkgid(debtags.pkgid()) {} - -/* Test going from a stream of tag data <string, string> to a stream of tag - * data <int, int> to a stream of tag data <Package, Tag> and finally back to a - * stream of tag data <string, string> - */ - Test _1() -{ - // Source data <string, string> - coll::Simple<string, string> source; - source.insert(wibble::singleton(string("debtags")), wibble::singleton(string("use::editing"))); - source.insert(wibble::singleton(string("debtags")), wibble::singleton(string("role::program"))); - - // <string, string> -> <int, int> - coll::Simple<int, int> dest; - source.output(stringToInt(pkgid, voc, inserter(dest))); - - assert_eq(dest.itemCount(), 1u); - assert_eq(dest.tagCount(), 2u); - - // <int, int> -> <Package, Tag> - coll::Simple<string, Tag> dest1; - dest.output(intToPkg(pkgid, voc, inserter(dest1))); - - assert_eq(dest1.itemCount(), 1u); - assert_eq(dest1.tagCount(), 2u); - - std::set<Tag> tags = dest1.getTagsOfItem("debtags"); - assert_eq(tags.size(), 2u); - - Tag useEditing = voc.tagByName("use::editing"); - Tag roleProgram = voc.tagByName("role::program"); - - assert(tags.find(useEditing) != tags.end()); - assert(tags.find(roleProgram) != tags.end()); - - // <Package, Tag> -> <string, string> - coll::Simple<string, string> dest2; - dest1.output(pkgToString(inserter(dest2))); - - assert_eq(dest2.itemCount(), 1u); - assert_eq(dest2.tagCount(), 2u); - - std::set<std::string> tags1 = dest2.getTagsOfItem("debtags"); - assert_eq(tags1.size(), 2u); - - assert(tags1.find("use::editing") != tags1.end()); - assert(tags1.find("role::program") != tags1.end()); -} - -/* Test going from patch with strings to patch with ints and vice versa */ - Test _2() -{ - PatchList<string, string> change; - change.addPatch(Patch<string, string>("debtags", - wibble::singleton(string("use::gameplaying")), - wibble::singleton(string("use::editing")))); - - // Deserialise to ints - PatchList<int, int> intChange; - change.output(patchStringToInt(pkgid, voc, tagcoll::inserter(intChange))); - assert_eq(intChange.size(), 1u); - assert_eq(intChange.begin()->second.added.size(), 1u); - assert_eq(intChange.begin()->second.removed.size(), 1u); - - // Serialise back to strings - PatchList<string, string> change1; - intChange.output(patchIntToString(pkgid, voc, tagcoll::inserter(change1))); - assert_eq(change1.size(), 1u); - assert_eq(change1.begin()->first, string("debtags")); - assert_eq(change1.begin()->second.item, string("debtags")); - assert_eq(change1.begin()->second.added.size(), 1u); - assert_eq(*change1.begin()->second.added.begin(), string("use::gameplaying")); - assert_eq(change1.begin()->second.removed.size(), 1u); - assert_eq(*change1.begin()->second.removed.begin(), string("use::editing")); -} - -}; - -#include <tagcoll/coll/simple.tcc> -#include <tagcoll/patch.tcc> - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/maint/sourcedir.cc b/ept/debtags/maint/sourcedir.cc index 79f0477..9b008fb 100644 --- a/ept/debtags/maint/sourcedir.cc +++ b/ept/debtags/maint/sourcedir.cc @@ -1,5 +1,5 @@ #include <ept/debtags/maint/sourcedir.h> -#include <ept/debtags/maint/vocabularymerger.h> +#include <ept/debtags/vocabulary.h> #include <ept/debtags/maint/path.h> #include <wibble/string.h> @@ -97,6 +97,7 @@ void SourceDir::readVocabularies(Vocabulary& out) for (const_iterator d = begin(); d != end(); ++d) { + if (d->d_name[0] == '.') continue; FileType type = fileType(d->d_name); if (type == VOC) { diff --git a/ept/debtags/maint/sourcedir.h b/ept/debtags/maint/sourcedir.h index f970155..988ae24 100644 --- a/ept/debtags/maint/sourcedir.h +++ b/ept/debtags/maint/sourcedir.h @@ -30,7 +30,7 @@ namespace ept { namespace debtags { -class VocabularyMerger; +class Vocabulary; /** * Access a directory containing Debtags data files diff --git a/ept/debtags/maint/vocabularymerger.test.h b/ept/debtags/maint/vocabularymerger.test.h deleted file mode 100644 index 4443a22..0000000 --- a/ept/debtags/maint/vocabularymerger.test.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Merge different vocabularies together and create the tag and facet indexes - * - * Copyright (C) 2003-2007 Enrico Zini <enrico@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 <wibble/test.h> -#include <ept/debtags/maint/vocabularymerger.h> -#include <tagcoll/input/string.h> - -using namespace std; -using namespace tagcoll; - -struct TestVocabularyMerger { - - inline static const char* indexref(const char* index, int id) - { - return index + ((int*)index)[id]; - } - - - Test _1() -{ - string voc1 = - "Facet: taste\n" - "Description: Taste\n\n" - "Tag: taste::sweet\n" - "Description: Sweet\n\n" - "Tag: taste::salty\n" - "Description: Salty\n\n"; - string voc2 = - "Facet: smell\n" - "Description: Smell\n\n" - "Tag: smell::fresh\n" - "Description: Fresh\n\n" - "Tag: smell::mold\n" - "Description: Mold\n\n"; - tagcoll::input::String in1(voc1); - tagcoll::input::String in2(voc2); - - ept::debtags::VocabularyMerger vm; - - // Read and merge the two vocabulary samples - vm.read(in1); - vm.read(in2); - - // Write the merged vocabulary to /dev/null (but generate offsets and indexes in the meantime) - vm.write("/dev/null"); - - // Create the facet index - char facetIndex[vm.facetIndexer().encodedSize()]; - vm.facetIndexer().encode(facetIndex); - - // Create the tag index - char tagIndex[vm.tagIndexer().encodedSize()]; - vm.tagIndexer().encode(tagIndex); - - // Check that the facet names have been encoded correctly and in order - assert_eq(string(indexref(facetIndex, 0) + 4*sizeof(int)), "smell"); - assert_eq(string(indexref(facetIndex, 1) + 4*sizeof(int)), "taste"); - - // Check the first and last tag indexes for the facets - assert_eq(((int*)indexref(facetIndex, 0))[2], 0); - assert_eq(((int*)indexref(facetIndex, 0))[3], 1); - assert_eq(((int*)indexref(facetIndex, 1))[2], 2); - assert_eq(((int*)indexref(facetIndex, 1))[3], 3); - - // Check that the tag names have been encoded correctly and in order - assert_eq(string(indexref(tagIndex, 0) + 3*sizeof(int)), "smell::fresh"); - assert_eq(string(indexref(tagIndex, 1) + 3*sizeof(int)), "smell::mold"); - assert_eq(string(indexref(tagIndex, 2) + 3*sizeof(int)), "taste::salty"); - assert_eq(string(indexref(tagIndex, 3) + 3*sizeof(int)), "taste::sweet"); - - // Check the facet indexes for the tags - assert_eq(((int*)indexref(tagIndex, 0))[2], 0); - assert_eq(((int*)indexref(tagIndex, 1))[2], 0); - assert_eq(((int*)indexref(tagIndex, 2))[2], 1); - assert_eq(((int*)indexref(tagIndex, 3))[2], 1); -} - -// Test parsing a vocabulary with a tag without a defined facet - Test _2() -{ - string voc = - "Tag: foo::bar\n" - "Description: Tag without facet\n" - " VocabularyMerged should behave fine in this case.\n\n"; - tagcoll::input::String in(voc); - - ept::debtags::VocabularyMerger vm; - vm.read(in); - - // Write the merged vocabulary to /dev/null (but generate offsets and indexes in the meantime) - vm.write("/dev/null"); - - // Create the facet index - char facetIndex[vm.facetIndexer().encodedSize()]; - vm.facetIndexer().encode(facetIndex); - - // Create the tag index - char tagIndex[vm.tagIndexer().encodedSize()]; - vm.tagIndexer().encode(tagIndex); -} - -// Test parsing a vocabulary with a facet without tags - Test _3() -{ - string voc = - "Facet: empty\n" - "Description: Facet without tags\n" - " VocabularyMerged used to segfault in this case.\n\n"; - tagcoll::input::String in(voc); - - ept::debtags::VocabularyMerger vm; - vm.read(in); - - // Write the merged vocabulary to /dev/null (but generate offsets and indexes in the meantime) - vm.write("/dev/null"); - - // Create the facet index - char facetIndex[vm.facetIndexer().encodedSize()]; - vm.facetIndexer().encode(facetIndex); - - // Create the tag index - char tagIndex[vm.tagIndexer().encodedSize()]; - vm.tagIndexer().encode(tagIndex); -} - -}; -// vim:set ts=4 sw=4: diff --git a/ept/debtags/tag.cc b/ept/debtags/tag.cc deleted file mode 100644 index 09392e9..0000000 --- a/ept/debtags/tag.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2005,2006 Enrico Zini <enrico@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 <ept/debtags/tag.h> -#include <ept/debtags/vocabulary.h> -#include <stdexcept> - -namespace ept { -namespace debtags { - -static inline std::string constget(const std::map<std::string, std::string>& m, - const std::string& key) -{ - std::map<std::string, std::string>::const_iterator i = m.find(key); - if (i == m.end()) - return std::string(); - else - return i->second; -} - -std::string Facet::name() const -{ - if (valid()) - return m_tags->facetName(m_id); - throw std::out_of_range( "No name for this facet" ); -} -std::string Facet::name(const std::string& d) const -{ - return valid() ? m_tags->facetName(m_id) : d; -} - -std::string Facet::shortDescription() const -{ - if (valid()) - return constget(m_tags->facetData(m_id), "_SD_"); - throw std::out_of_range( "No short description for this facet" ); -} -std::string Facet::shortDescription(const std::string& d) const -{ - return valid() ? constget(m_tags->facetData(m_id), "_SD_") : d; -} - -std::string Facet::longDescription() const -{ - if (valid()) - return constget(m_tags->facetData(m_id), "Description"); - throw std::out_of_range( "No long description for this facet" ); -} -std::string Facet::longDescription(const std::string& d) const -{ - return valid() ? constget(m_tags->facetData(m_id), "Description") : d; -} - -bool Facet::hasTag(const std::string& name) const -{ - if (!valid()) - throw std::out_of_range( "hasTag() called on an invalid facet" ); - return m_tags->hasTag(this->name() + "::" + name); -} - -std::set< Tag > Facet::tags() const -{ - if (!valid()) - throw std::out_of_range( "tags() called on an invalid facet" ); - return m_tags->tags(m_id); -} - - -Facet Tag::facet() const -{ - if (valid()) - return m_tags->facetByTag(m_id); - throw std::out_of_range( "No facet for this tag" ); -} - -std::string Tag::name() const -{ - if (valid()) - return m_tags->tagShortName(m_id); - throw std::out_of_range( "No name for this tag" ); -} -std::string Tag::name(const std::string& d) const -{ - return valid() ? m_tags->tagShortName(m_id) : d; -} - -std::string Tag::fullname() const -{ - if (valid()) - return m_tags->tagName(m_id); - throw std::out_of_range( "No full name for this tag" ); -} -std::string Tag::fullname(const std::string& d) const -{ - return valid() ? m_tags->tagName(m_id) : d; -} - -std::string Tag::shortDescription() const -{ - if (valid()) - return constget(m_tags->tagData(m_id), "_SD_"); - throw std::out_of_range( "No short description for this tag" ); -} -std::string Tag::shortDescription(const std::string& d) const -{ - return valid() ? constget(m_tags->tagData(m_id), "_SD_") : d; -} - -std::string Tag::longDescription() const -{ - if (valid()) - return constget(m_tags->tagData(m_id), "Description"); - throw std::out_of_range( "No long description for this tag" ); -} -std::string Tag::longDescription(const std::string& d) const -{ - return valid() ? constget(m_tags->tagData(m_id), "Description") : d; -} - -} -} - -// vim:set ts=3 sw=3: diff --git a/ept/debtags/tag.h b/ept/debtags/tag.h deleted file mode 100644 index bb7488f..0000000 --- a/ept/debtags/tag.h +++ /dev/null @@ -1,251 +0,0 @@ -// -*- C++ -*- -#ifndef EPT_DEBTAGS_TAG_H -#define EPT_DEBTAGS_TAG_H - -/** \file - * Debtags facets and tags - */ - -/* - * Copyright (C) 2005,2006,2007 Enrico Zini <enrico@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 <set> -#include <string> - -namespace ept { -namespace debtags { - -class Vocabulary; - -class Tag; - -/** - * Representation of a facet. - * - * ept::debtags::Facet represents a Facet with all its informations. - * It is guaranteed to have fast value-copy semantics, so it can be passed - * around freely and efficiently without worrying about memory management - * issues. - * - * The class is normally instantiated using a Vocabulary: - * \code - * Facet facet = vocabulary.faceByName("made-of"); - * \endcode - * - * Facets can contain an "invalid" value, in which case using any of their - * methods will likely produce segfault. The "invalid" facets are useful as - * "none" return values: - * - * \code - * Facet facet = vocabulary.facetByName("made-of"); - * if (!facet) - * throw SomeException("facet \"made-of\" has not been defined"); - * \endcode - */ -class Facet -{ -protected: - const Vocabulary* m_tags; - int m_id; - - Facet(const Vocabulary* tags, int id) : m_tags(tags), m_id(id) {} - -public: - Facet() : m_tags(0), m_id(-1) {} - ~Facet() {} - - bool operator==(const Facet& f) const { return m_id == f.m_id; } - bool operator!=(const Facet& f) const { return m_id != f.m_id; } - bool operator<(const Facet& f) const { return m_id < f.m_id; } - - /** - * Return true if the facet is valid - */ - operator bool() const { return m_id != -1; } - bool valid() const { return m_id != -1; } - - /** - * Return the name of the facet - * @throws std::out_of_range if the facet is not valid - */ - std::string name() const; - /** - * Return the name of the facet - * - * Returns d if the facet is not valid. - */ - std::string name(const std::string& d) const; - - /** - * Return the short description of the facet - * @throws std::out_of_range if the facet is not valid - */ - std::string shortDescription() const; - /** - * Return the short description of the facet - * - * Returns d if the facet is not valid. - */ - std::string shortDescription(const std::string& d) const; - - /** - * Return the long description of the facet - * @throws std::out_of_range if the facet is not valid - */ - std::string longDescription() const; - /** - * Return the long description of the facet - * - * Returns d if the facet is not valid. - */ - std::string longDescription(const std::string& d) const; - - /** - * Return true if the facet has a tag with the given name (name, not fullname) - */ - bool hasTag(const std::string& name) const; - - /** - * Return the list of tags in this facet - */ - std::set<Tag> tags() const; - - /** - * Return the ID of this facet - * - * @warning This method is exported to help in writing tests, but it is not - * part of the normal API: do not use it, because future implementations may - * not be based on IDs and therefore not have this method. - */ - int id() const { return m_id; } - - friend class Vocabulary; -}; - -/** - * Representation of a tag. - * - * ept::debtags::Tag represents a Tag with all its informations. - * It is guaranteed to have fast value-copy semantics, so it can be passed - * around freely and efficiently without worrying about memory management - * issues. - * - * The class is normally instantiated using a Vocabulary: - * \code - * Tag tag = vocabulary.tagByName("made-of::lang:c++"); - * \endcode - * - * Tags can contain an "invalid" value, in which case using any of their - * methods will likely produce segfault. The "invalid" facets are useful as - * "none" return values: - * - * \code - * Tag tag = vocabulary.tagByName("made-of"); - * if (!tag) - * throw SomeException("tag \"mytag\" has not been defined"); - * \endcode - */ -class Tag -{ -protected: - const Vocabulary* m_tags; - int m_id; - - Tag(const Vocabulary* tags, int id) : m_tags(tags), m_id(id) {} - -public: - typedef std::set< Tag > Set; - - Tag() : m_tags(0), m_id(-1) {} - ~Tag() {} - - bool operator==(const Tag& f) const { return m_id == f.m_id; } - bool operator!=(const Tag& f) const { return m_id != f.m_id; } - bool operator<(const Tag& f) const { return m_id < f.m_id; } - - operator bool() const { return m_id != -1; } - bool valid() const { return m_id != -1; } - - Facet facet() const; - - /** - * Return the name of the tag, without the facet:: prefix - * @throws std::out_of_range if the tag is not valid - */ - std::string name() const; - /** - * Return the short description of the tag - * - * Returns d if the tag is not valid. - */ - std::string name(const std::string& d) const; - - /** - * Return the name of the tag, with the facet:: prefix - * @throws std::out_of_range if the tag is not valid - */ - std::string fullname() const; - /** - * Return the short description of the tag - * - * Returns d if the tag is not valid. - */ - std::string fullname(const std::string& d) const; - - /** - * Return the short description of the tag - * @throws std::out_of_range if the tag is not valid - */ - std::string shortDescription() const; - /** - * Return the short description of the tag - * - * Returns d if the tag is not valid. - */ - std::string shortDescription(const std::string& d) const; - - /** - * Return the long description of the tag - * - * @throws std::out_of_range if the tag is not valid - */ - std::string longDescription() const; - /** - * Return the long description of the tag - * - * Returns d if the tag is not valid. - */ - std::string longDescription(const std::string& d) const; - - /** - * Return the ID of this tag - * - * @warning This method is exported to help in writing tests, but it is not - * part of the normal API: do not use it, because future implementations may - * not be based on IDs and therefore not have this method. - */ - int id() const { return m_id; } - - friend class Vocabulary; -}; - -} -} - -// vim:set ts=3 sw=3: -#endif diff --git a/ept/debtags/tag.test.h b/ept/debtags/tag.test.h deleted file mode 100644 index 998147d..0000000 --- a/ept/debtags/tag.test.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2005,2007 Enrico Zini <enrico@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 - */ - -#if 0 -#include <ept/tests/test-utils.h> -#include <ept/debtags/tag.h> -#include <ept/debtags/vocabulary.h> -#include <ept/debtags/maint/path.h> - -#include <tagcoll/utils/set.h> - -using namespace std; -using namespace ept::debtags; - -namespace tut { - -struct ept_debtags_tag_shar -{ - Path::OverrideDebtagsSourceDir odsd; - Path::OverrideDebtagsIndexDir odid; - Path::OverrideDebtagsUserSourceDir odusd; - Path::OverrideDebtagsUserIndexDir oduid; - Vocabulary voc; - - ept_debtags_tag_shar() - : odsd("./"), odid("./"), odusd("./"), oduid("./") {} -}; - -TESTGRP( ept_debtags_tag ); - -template<> template<> -void to::test<1>() -{ - Tag a, b; - ensure( a == b ); - ensure( !a.valid() ); - ensure( !b.valid() ); -} - -template<> template<> -void to::test<2>() -{ - Tag a; - int x = 1; - try { - a.shortDescription(); - x = 2; - } catch (...) { - x = 3; - } - ensure_equals( x, 3 ); -} - -template<> template<> -void to::test< 3 >() -{ - Facet f = voc.facetByName( "works-with" ); - Tag t = voc.tagByName( "works-with::people" ); - ensure( t.valid() ); - ensure( f.valid() ); - ensure( t.facet() == f ); - ensure( tagcoll::utils::set_contains(f.tags(), t) ); -} - -template<> template<> -void to::test< 4 >() -{ - Facet f = voc.facetByName( "works-with" ); - Tag t = voc.tagByName( "works-with::people" ); - ensure( t.valid() ); - ensure( f.valid() ); - ensure( f.hasTag( t.name() ) ); -} - -template<> template<> -void to::test< 5 >() -{ - Tag t = voc.tagByName( "works-with::people" ); - ensure( t.valid() ); - ensure( t.facet().hasTag( t.name() ) ); - ensure( tagcoll::utils::set_contains(t.facet().tags(), t) ); -} - -} - -/* -#include <ept/cache/tag.tcc> -#include <ept/cache/debtags/vocabulary.tcc> -*/ - -// vim:set ts=3 sw=3: -#endif diff --git a/ept/debtags/vocabulary.cc b/ept/debtags/vocabulary.cc index 7f3a6b7..25887fa 100644 --- a/ept/debtags/vocabulary.cc +++ b/ept/debtags/vocabulary.cc @@ -39,6 +39,52 @@ using namespace tagcoll; namespace ept { namespace debtags { +namespace voc { +std::string Data::shortDescription() const +{ + if (m_desc.empty()) + { + string d = longDescription(); + if (d.empty()) return d; + size_t pos = d.find('\n'); + if (pos == std::string::npos) + m_desc = d; + else + m_desc = d.substr(0, pos); + } + return m_desc; +} + +std::string Data::longDescription() const +{ + const_iterator i = find("Description"); + if (i == end()) return std::string(); + return i->second; +} + +bool FacetData::hasTag(const std::string& name) const +{ + return m_tags.find(name) != m_tags.end(); +} + +const TagData* FacetData::tagData(const std::string& name) const +{ + std::map<std::string, voc::TagData>::const_iterator i = m_tags.find(name); + if (i == m_tags.end()) return 0; + return &i->second; +} + +std::set<std::string> FacetData::tags() const +{ + std::set<std::string> res; + for (std::map<std::string, voc::TagData>::const_iterator i = m_tags.begin(); + i != m_tags.end(); ++i) + res.insert(i->first); + return res; +} + +} + static inline std::string getfacet(const std::string& tagname) { size_t p = tagname.find("::"); @@ -67,11 +113,11 @@ Vocabulary::~Vocabulary() voc::TagData& voc::FacetData::obtainTag(const std::string& name) { - std::map<std::string, voc::TagData>::iterator i = tags.find(name); - if (i == tags.end()) + std::map<std::string, voc::TagData>::iterator i = m_tags.find(name); + if (i == m_tags.end()) { // Create the tag if it's missing - pair<std::map<std::string, TagData>::iterator, bool> res = tags.insert(make_pair<std::string, TagData>(name, TagData())); + pair<std::map<std::string, TagData>::iterator, bool> res = m_tags.insert(make_pair<std::string, TagData>(name, TagData())); i = res.first; i->second.name = name; } @@ -93,15 +139,7 @@ voc::FacetData& Vocabulary::obtainFacet(const std::string& name) voc::TagData& Vocabulary::obtainTag(const std::string& fullname) { - size_t p = fullname.find("::"); - if (p == string::npos) - { - voc::FacetData& facet = obtainFacet("legacy"); - return facet.obtainTag(fullname); - } else { - voc::FacetData& facet = obtainFacet(fullname.substr(0, p)); - return facet.obtainTag(fullname.substr(p + 2)); - } + return obtainFacet(getfacet(fullname)).obtainTag(fullname); } @@ -115,7 +153,7 @@ bool Vocabulary::hasTag(const std::string& name) const { const voc::FacetData* f = facetData(getfacet(name)); if (!f) return false; - return f->tags.find(name) != f->tags.end(); + return f->hasTag(name); } const voc::FacetData* Vocabulary::facetData(const std::string& name) const @@ -131,10 +169,7 @@ const voc::TagData* Vocabulary::tagData(const std::string& tagname) const const voc::FacetData* f = facetData(getfacet(tagname)); if (!f) return 0; - std::map<std::string, voc::TagData>::const_iterator i = f->tags.find(tagname); - if (i == f->tags.end()) return 0; - - return &i->second; + return f->tagData(tagname); } std::set<std::string> Vocabulary::facets() const @@ -151,21 +186,17 @@ std::set<std::string> Vocabulary::tags() const std::set<std::string> res; for (std::map<std::string, voc::FacetData>::const_iterator i = m_facets.begin(); i != m_facets.end(); ++i) - for (std::map<std::string, voc::TagData>::const_iterator j = i->second.tags.begin(); - j != i->second.tags.end(); ++j) + for (std::map<std::string, voc::TagData>::const_iterator j = i->second.m_tags.begin(); + j != i->second.m_tags.end(); ++j) res.insert(j->first); return res; } std::set<std::string> Vocabulary::tags(const std::string& facet) const { - std::set<std::string> res; const voc::FacetData* f = facetData(facet); - if (!f) return res; - for (std::map<std::string, voc::TagData>::const_iterator i = f->tags.begin(); - i != f->tags.end(); ++i) - res.insert(i->first); - return res; + if (!f) return std::set<std::string>(); + return f->tags(); } void Vocabulary::read(tagcoll::input::Input& input) @@ -309,8 +340,8 @@ void Vocabulary::write(FILE* out) writeDebStyleField(out, j->first, j->second); fputc('\n', out); - for (std::map<std::string, voc::TagData>::iterator t = f->second.tags.begin(); - t != f->second.tags.end(); t++) + for (std::map<std::string, voc::TagData>::iterator t = f->second.m_tags.begin(); + t != f->second.m_tags.end(); t++) { //fprintf(stderr, "Writing tag %.*s\n", PFSTR(t->first)); writeDebStyleField(out, "Tag", f->first + "::" + t->first); diff --git a/ept/debtags/vocabulary.h b/ept/debtags/vocabulary.h index 59b4905..c126539 100644 --- a/ept/debtags/vocabulary.h +++ b/ept/debtags/vocabulary.h @@ -24,11 +24,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <ept/debtags/tag.h> -#include <tagcoll/diskindex/mmap.h> - #include <string> #include <vector> +#include <set> #include <map> namespace tagcoll { @@ -41,23 +39,106 @@ namespace ept { namespace debtags { namespace voc { -class TagData : public std::map<std::string, std::string> +/// Base class for facet and tag data +struct Data : public std::map<std::string, std::string> { +protected: + // Cache the parsed short description + mutable std::string m_desc; + public: std::string name; + /** + * Return the short description of the tag + * @throws std::out_of_range if the tag is not valid + */ + std::string shortDescription() const; + + /** + * Return the long description of the tag + * + * @throws std::out_of_range if the tag is not valid + */ + std::string longDescription() const; +}; + +/** + * Representation of a tag. + * + * ept::debtags::Tag represents a Tag with all its informations. + * It is guaranteed to have fast value-copy semantics, so it can be passed + * around freely and efficiently without worrying about memory management + * issues. + * + * The class is normally instantiated using a Vocabulary: + * \code + * Tag tag = vocabulary.tagByName("made-of::lang:c++"); + * \endcode + * + * Tags can contain an "invalid" value, in which case using any of their + * methods will likely produce segfault. The "invalid" facets are useful as + * "none" return values: + * + * \code + * Tag tag = vocabulary.tagByName("made-of"); + * if (!tag) + * throw SomeException("tag \"mytag\" has not been defined"); + * \endcode + */ +struct TagData : public Data +{ TagData() {} + + // Facet facet() const; }; -class FacetData : public std::map<std::string, std::string> +/** + * Representation of a facet. + * + * ept::debtags::Facet represents a Facet with all its informations. + * It is guaranteed to have fast value-copy semantics, so it can be passed + * around freely and efficiently without worrying about memory management + * issues. + * + * The class is normally instantiated using a Vocabulary: + * \code + * Facet facet = vocabulary.faceByName("made-of"); + * \endcode + * + * Facets can contain an "invalid" value, in which case using any of their + * methods will likely produce segfault. The "invalid" facets are useful as + * "none" return values: + * + * \code + * Facet facet = vocabulary.facetByName("made-of"); + * if (!facet) + * throw SomeException("facet \"made-of\" has not been defined"); + * \endcode + */ +class FacetData : public Data { public: - std::string name; - std::map<std::string, TagData> tags; + std::map<std::string, TagData> m_tags; FacetData() {} TagData& obtainTag(const std::string& fullname); + + /** + * Return true if the facet has a tag with the given name (name, not fullname) + */ + bool hasTag(const std::string& name) const; + + /** + * Return the tag data for the given tag, or 0 if not found + */ + const TagData* tagData(const std::string& name) const; + + /** + * Return the list of tags in this facet + */ + std::set<std::string> tags() const; }; } diff --git a/ept/debtags/vocabulary.test.h b/ept/debtags/vocabulary.test.h index 977eef5..a6ed1b8 100644 --- a/ept/debtags/vocabulary.test.h +++ b/ept/debtags/vocabulary.test.h @@ -20,19 +20,11 @@ #include <wibble/test.h> #include <ept/debtags/vocabulary.h> -#include <ept/debtags/maint/vocabularymerger.h> #include <ept/debtags/maint/path.h> #include <tagcoll/utils/set.h> #include <tagcoll/input/stdio.h> -#include "debtags.test.h" - -// This is not exported by default -namespace ept { -namespace debtags { -int tagcmp(const char* tag1, const char* tag2); -} -} +#include "ept/test.h" using namespace std; using namespace tagcoll::utils; @@ -62,11 +54,11 @@ struct TestVocabulary : DebtagsTestEnvironment Test _4() { - Tag people = tags().tagByName( "works-with::people" ), - midgets = tags().tagByName( "works-with::midgets" ), - blahg = tags().tagByName( "works-with::blahg" ), - text = tags().tagByName( "works-with::text" ), - people2 = tags().tagByName( "works-with::people" ); + const voc::TagData *people = tags().tagData( "works-with::people" ), + *midgets = tags().tagData( "works-with::midgets" ), + *blahg = tags().tagData( "works-with::blahg" ), + *text = tags().tagData( "works-with::text" ), + *people2 = tags().tagData( "works-with::people" ); assert( people != midgets ); assert( people != text ); assert( people != blahg ); @@ -78,11 +70,11 @@ struct TestVocabulary : DebtagsTestEnvironment Test _5() { - Tag a = tags().tagByName( "works-with::people" ), - b = tags().tagByName( "works-with::midgets" ); - std::set< Tag > s = tags().tags(), - f = tags().tags( "works-with" ), - n = tags().tags( "nonsense" ); + std::string a = "works-with::people", + b = "works-with::midgets"; + std::set<std::string> s = tags().tags(), + f = tags().tags( "works-with" ), + n = tags().tags( "nonsense" ); assert( set_contains(s, a) ); assert( set_contains(f, a) ); assert( set_contains(s, f) ); @@ -93,38 +85,34 @@ struct TestVocabulary : DebtagsTestEnvironment Test _6() { - Facet f = tags().facetByName( "works-with" ); - Tag t = tags().tagByName( "works-with::people" ); - assert_eq(f.name(), "works-with"); - assert_eq(t.name(), "people"); - assert_eq(t.fullname(), "works-with::people"); + const voc::FacetData* f = tags().facetData( "works-with" ); + assert(f); + assert_eq(f->name, "works-with"); + + const voc::TagData* t = tags().tagData( "works-with::people" ); + assert(t); + assert_eq(t->name, "works-with::people"); } Test _7() { - Facet f = tags().facetByName( "works-with" ); - std::set< Tag > x = tags().tags( "works-with" ); - assert( x == f.tags() ); + const voc::FacetData* f = tags().facetData( "works-with" ); + std::set<std::string> x = tags().tags( "works-with" ); + assert( x == f->tags() ); } Test _8() { - Facet f = tags().facetByName( "does-not-work-with" ); - int x = 1; - try { - f.tags(); - x = 2; - } catch (...) { - x = 3; - } - assert_eq( x, 3 ); + const voc::FacetData* f = tags().facetData( "does-not-work-with" ); + assert(!f); } Test _9() { - Facet f = tags().facetByName( "legacy" ); - assert_eq(f.shortDescription(), ""); - assert_eq(f.longDescription(), ""); + const voc::FacetData* f = tags().facetData( "legacy" ); + assert(f); + assert_eq(f->shortDescription(), ""); + assert_eq(f->longDescription(), ""); //assert_eq(f.shortDescription( "weehee" ), "weehee"); } @@ -136,31 +124,26 @@ struct TestVocabulary : DebtagsTestEnvironment Test _11() { - // assert that all tags are somehow working - std::set<Facet> facets = tags().facets(); + // assert that all facets are somehow working + std::set<std::string> facets = tags().facets(); - for (std::set<Facet>::const_iterator i = facets.begin(); + for (std::set<std::string>::const_iterator i = facets.begin(); i != facets.end(); i++) { - i->name(string("foo")); - i->shortDescription(string("foo")); - i->longDescription(string("foo")); - i->tags(); + const voc::FacetData* f = tags().facetData(*i); + assert(f); } } Test _12() { // assert that all tags are somehow working - std::set<Tag> tags = this->tags().tags(); - - for (std::set<Tag>::const_iterator i = tags.begin(); + std::set<std::string> tags = this->tags().tags(); + for (std::set<std::string>::const_iterator i = tags.begin(); i != tags.end(); i++) { - i->name(string("foo")); - i->fullname(string("foo")); - i->shortDescription(string("foo")); - i->longDescription(string("foo")); + const voc::TagData* t = this->tags().tagData(*i); + assert(t); } } @@ -169,126 +152,57 @@ struct TestVocabulary : DebtagsTestEnvironment { Vocabulary& tags = this->tags(); - Tag first = tags.tagByName("accessibility::TODO"); - assert(first != Tag()); - assert_eq(first.fullname(), string("accessibility::TODO")); - assert_eq(first.name(), string("TODO")); - assert_eq(first.shortDescription(), string("Need an extra tag")); - - Tag last = tags.tagByName("x11::xserver"); - assert(last != Tag()); - assert_eq(last.fullname(), string("x11::xserver")); - assert_eq(last.name(), string("xserver")); - assert_eq(last.shortDescription(), string("X Server")); + const voc::TagData* first = tags.tagData("accessibility::TODO"); + assert(first); + assert_eq(first->name, string("accessibility::TODO")); + assert_eq(first->shortDescription(), string("Need an extra tag")); + + const voc::TagData* last = tags.tagData("x11::xserver"); + assert(last); + assert_eq(last->name, string("x11::xserver")); + assert_eq(last->shortDescription(), string("X Server")); } Test _14() { // assert that it's possible to go from facet to ID and back - std::set<Facet> facets = tags().facets(); - - for (std::set<Facet>::const_iterator i = facets.begin(); - i != facets.end(); i++) - { - Facet f = tags().facetByID(i->id()); - assert_eq(*i, f); - assert_eq(i->name(), f.name()); - assert_eq(i->shortDescription(), f.shortDescription()); - assert_eq(i->longDescription(), f.longDescription()); - assert_eq(i->tags().size(), f.tags().size()); - } + // we don't use IDs anymore } Test _15() { // assert that it's possible to go from tag to ID and back - std::set<Tag> tags = this->tags().tags(); - - for (std::set<Tag>::const_iterator i = tags.begin(); - i != tags.end(); i++) - { - Tag t = this->tags().tagByID(i->id()); - assert_eq(*i, t); - assert_eq(i->name(), t.name()); - assert_eq(i->fullname(), t.fullname()); - assert_eq(i->shortDescription(), t.shortDescription()); - assert_eq(i->longDescription(), t.longDescription()); - } + // we don't use IDs anymore } Test _16() { // assert that facet IDs are distinct - std::set<Facet> facets = tags().facets(); - std::set<int> ids; - for (std::set<Facet>::const_iterator i = facets.begin(); - i != facets.end(); i++) - ids.insert(i->id()); - - assert_eq(facets.size(), ids.size()); + // we don't use IDs anymore } Test _17() { // assert that tag IDs are distinct - std::set<Tag> tags = this->tags().tags(); - std::set<int> ids; - for (std::set<Tag>::const_iterator i = tags.begin(); - i != tags.end(); i++) - ids.insert(i->id()); - - assert_eq(tags.size(), ids.size()); + // we don't use IDs anymore } Test _18() { // assert that all the tags are indexed - ept::debtags::VocabularyMerger voc; - tagcoll::input::Stdio in(ept::debtags::Path::vocabulary()); - voc.read(in); - std::set<std::string> all = voc.tagNames(); - for (std::set<std::string>::const_iterator i = all.begin(); - i != all.end(); ++i) - assert(this->tags().hasTag(*i)); - - // There should be the same amount of tags in both - std::set<Tag> allTags = this->tags().tags(); - assert_eq(all.size(), allTags.size()); + // we don't use the index anymore } Test _19() { // test the tagcmp function - - // If unfaceted, same as strcmp - assert(ept::debtags::tagcmp("antani", "blinda") < 0); - assert(ept::debtags::tagcmp("blinda", "antani") > 0); - assert_eq(ept::debtags::tagcmp("antani", "antani"), 0); - - // If the same and faceted, should work - assert_eq(ept::debtags::tagcmp("antani::blinda", "antani::blinda"), 0); - - // With different facet names, work just as strcmp - assert(ept::debtags::tagcmp("antani::blinda", "blinda::blinda") < 0); - assert(ept::debtags::tagcmp("blinda::blinda", "antani::blinda") > 0); - assert(ept::debtags::tagcmp("anta::blinda", "antani::blinda") < 0); - assert(ept::debtags::tagcmp("antani::blinda", "anta::blinda") > 0); - assert(ept::debtags::tagcmp("anta::blinda", "anta-ni::blinda") < 0); - assert(ept::debtags::tagcmp("anta-ni::blinda", "anta::blinda") > 0); - - // With same facet names, work just as strcmp on the tags - assert(ept::debtags::tagcmp("a::antani", "a::blinda") < 0); - assert(ept::debtags::tagcmp("a::blinda", "a::antani") > 0); - assert(ept::debtags::tagcmp("a::anta", "a::antani") < 0); - assert(ept::debtags::tagcmp("a::antani", "a::anta") > 0); - assert(ept::debtags::tagcmp("a::anta", "a::anta-ni") < 0); - assert(ept::debtags::tagcmp("a::anta-ni", "a::anta") > 0); + // we don't have tagcmp anymore } Test _20() { // check that we're seeing all the tags for a facet - std::set<Tag> t = tags().tags("accessibility"); + std::set<std::string> t = tags().tags("accessibility"); assert_eq(t.size(), 10u); t = tags().tags("works-with-format"); @@ -306,10 +220,10 @@ struct TestVocabulary : DebtagsTestEnvironment assert(!empty.hasData()); - set<Facet> facets = empty.facets(); + set<std::string> facets = empty.facets(); assert_eq(facets.size(), 0u); - set<Tag> tags = empty.tags(); + set<std::string> tags = empty.tags(); assert_eq(tags.size(), 0u); } diff --git a/ept/textsearch/extraindexers.cc b/ept/textsearch/extraindexers.cc index 4fdfdd4..179688f 100644 --- a/ept/textsearch/extraindexers.cc +++ b/ept/textsearch/extraindexers.cc @@ -44,10 +44,10 @@ void AptTagsExtraIndexer::operator()(Xapian::Document& doc, const apt::PackageRe void DebtagsExtraIndexer::operator()(Xapian::Document& doc, const apt::PackageRecord& rec) const { // Index tags as well - set<Tag> tags = debtags.getTagsOfItem(doc.get_data()); - for (set<Tag>::const_iterator ti = tags.begin(); + set<std::string> tags = debtags.getTagsOfItem(doc.get_data()); + for (set<std::string>::const_iterator ti = tags.begin(); ti != tags.end(); ++ti) - doc.add_term("XT"+ti->fullname()); + doc.add_term("XT"+*ti); } } diff --git a/tools/ept-cache.cc b/tools/ept-cache.cc index 2b28eec..6ee3205 100644 --- a/tools/ept-cache.cc +++ b/tools/ept-cache.cc @@ -1,7 +1,7 @@ /* * ept-cache - Commandline interface to the ept library * - * Copyright (C) 2007 Enrico Zini <enrico@debian.org> + * Copyright (C) 2007--2010 Enrico Zini <enrico@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 @@ -28,7 +28,7 @@ #include <ept/apt/packagerecord.h> #include <ept/popcon/popcon.h> #include <ept/popcon/local.h> -#include <ept/debtags/expression.h> +#include <tagcoll/expression.h> #include <ept/textsearch/textsearch.h> #include <ept/textsearch/extraindexers.h> @@ -568,7 +568,7 @@ struct Generator generateRecords(out); } - void debtagsSearch(const set<Tag>& wantedTags, Consumer& out) + void debtagsSearch(const set<std::string>& wantedTags, Consumer& out) { debug("Generate by querying debtags\n"); env().debtags().outputHavingTags(wantedTags, OutputInfo(filters, out)); diff --git a/tools/filters.h b/tools/filters.h index fa8c2b0..050172a 100644 --- a/tools/filters.h +++ b/tools/filters.h @@ -24,7 +24,7 @@ #include <vector> #include <string> -#include <ept/debtags/expression.h> +#include <tagcoll/expression.h> /* * * For packages diff --git a/tools/info.cc b/tools/info.cc index cd9966d..64aff2e 100644 --- a/tools/info.cc +++ b/tools/info.cc @@ -1,7 +1,7 @@ /* * ept-cache - Commandline interface to the ept library * - * Copyright (C) 2007 Enrico Zini <enrico@debian.org> + * Copyright (C) 2007--2010 Enrico Zini <enrico@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 @@ -101,7 +101,7 @@ void Info::wantTags() set<string> stags = record->tag(); for (set<string>::const_iterator i = stags.begin(); i != stags.end(); ++i) - tags.insert(env().voc().tagByName(*i)); + tags.insert(*i); } has_tags = true; } diff --git a/tools/info.h b/tools/info.h index 2cbe249..7fe6d0b 100644 --- a/tools/info.h +++ b/tools/info.h @@ -1,7 +1,7 @@ /* * ept-cache - Commandline interface to the ept library * - * Copyright (C) 2007 Enrico Zini <enrico@debian.org> + * Copyright (C) 2007--2010 Enrico Zini <enrico@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 @@ -21,8 +21,6 @@ #ifndef EPTCACHE_INFO_H #define EPTCACHE_INFO_H -#include <ept/debtags/tag.h> - #include <string> #include <set> @@ -57,7 +55,7 @@ struct Info ept::apt::PackageRecord* record; bool has_tags; - std::set<ept::debtags::Tag> tags; + std::set<std::string> tags; bool has_popcon; float popcon; diff --git a/tools/utils.h b/tools/utils.h index 3e4b283..d0e7034 100644 --- a/tools/utils.h +++ b/tools/utils.h @@ -36,9 +36,9 @@ basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, cons for (typename std::set<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++) if (i == tags.begin()) - out << i->fullname(); + out << *i; else - out << ", " << i->fullname(); + out << ", " << *i; return out; } |