summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorEnrico Zini <enrico@enricozini.org>2010-05-10 18:58:02 +0100
committerEnrico Zini <enrico@enricozini.org>2010-05-10 18:58:02 +0100
commit16c7f645ed52eed014d4016fe6160c405e0f6787 (patch)
treeb067ca7fcebd9d916f5b4d7b4475ec8884c7a656 /tools
parent1b5ac4e66699cacde7123da3b111a0a16ee55db4 (diff)
downloadlibept-16c7f645ed52eed014d4016fe6160c405e0f6787.tar.gz
ept-cache superseded by axi-cache
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt12
-rw-r--r--tools/Environment.cc126
-rw-r--r--tools/Environment.h136
-rw-r--r--tools/EptCacheOptions.h293
-rw-r--r--tools/ept-cache-man-hooks49
-rw-r--r--tools/ept-cache.cc1060
-rw-r--r--tools/filters.cc112
-rw-r--r--tools/filters.h125
-rw-r--r--tools/info.cc126
-rw-r--r--tools/info.h79
-rw-r--r--tools/manpage.cc62
-rw-r--r--tools/utils.h72
12 files changed, 1 insertions, 2251 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index bd75e75..6ec14fe 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -4,18 +4,8 @@ link_libraries( ept )
add_executable( ept-cat ept-cat.cpp )
add_executable( pkglist pkglist.cpp )
-add_executable( manpage manpage.cc )
-add_executable( ept-cache
- ept-cache.cc Environment.cc filters.cc info.cc )
set( bindir ${CMAKE_CURRENT_BINARY_DIR} )
set( srcdir ${CMAKE_CURRENT_SOURCE_DIR} )
-add_custom_command(
- TARGET manpage
- POST_BUILD
- DEPENDS manpage
- COMMAND LD_LIBRARY_PATH=${ept_BINARY_DIR} ${bindir}/manpage ept-cache ${srcdir}/ept-cache-man-hooks > ${bindir}/ept-cache.1 )
-
-install( TARGETS ept-cache RUNTIME DESTINATION bin )
-install( FILES ${bindir}/ept-cache.1 DESTINATION share/man/man1 )
+install( PROGRAMS ept-cache DESTINATION bin )
diff --git a/tools/Environment.cc b/tools/Environment.cc
deleted file mode 100644
index 2249591..0000000
--- a/tools/Environment.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Common environment for many program parts
- *
- * Copyright (C) 2003 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 "Environment.h"
-
-#include <ept/apt/apt.h>
-#include <ept/debtags/debtags.h>
-#include <ept/debtags/vocabulary.h>
-#include <ept/popcon/popcon.h>
-#include <ept/popcon/local.h>
-#include <ept/axi/axi.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h> // isatty
-
-using namespace std;
-using namespace ept;
-
-static Environment* instance = 0;
-
-Environment& Environment::get() throw ()
-{
- if (instance == 0)
- instance = new Environment;
-
- return *instance;
-}
-
-// Initialize the environment with default values
-Environment::Environment() throw ()
- : m_apt(0), m_debtags(0), m_popcon(0), m_popconlocal(0), m_axi(0), _verbose(false), _debug(false) {}
-
-void Environment::init(bool editable)
-{
- m_apt = new ept::apt::Apt;
- m_debtags = new ept::debtags::Debtags(editable);
- m_vocabulary = new ept::debtags::Vocabulary;
- m_popcon = new ept::popcon::Popcon;
- m_popconlocal = new ept::popcon::Local;
- if (axi::timestamp() > 0)
- m_axi = new Xapian::Database(axi::path_db());
- else
- m_axi = new Xapian::Database;
-}
-
-void fatal_error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- fprintf(stderr, "debtags: ");
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
- exit(1);
-}
-
-void error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
-void warning(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
-void verbose(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- if (Environment::get().verbose())
- {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
-}
-
-void debug(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- if (Environment::get().debug())
- {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
-}
-
-void feedback(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
-{
- if (isatty(1))
- {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- }
-}
-
-
-
-// vim:set ts=4 sw=4:
diff --git a/tools/Environment.h b/tools/Environment.h
deleted file mode 100644
index d332da3..0000000
--- a/tools/Environment.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef EPTCACHE_ENVIRONMENT_H
-#define EPTCACHE_ENVIRONMENT_H
-
-/*
- * Common environment for many program parts
- *
- * Copyright (C) 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 <string>
-
-namespace Xapian {
-class Database;
-}
-
-namespace ept {
-namespace apt {
-class Apt;
-}
-namespace debtags {
-class Debtags;
-class Vocabulary;
-}
-namespace popcon {
-class Popcon;
-class Local;
-}
-}
-
-class Environment
-{
-protected:
- /// Apt data provider
- ept::apt::Apt* m_apt;
-
- /// Debtags data provider
- ept::debtags::Debtags* m_debtags;
-
- /// Debtags vocabulary data provider
- ept::debtags::Vocabulary* m_vocabulary;
-
- /// Popcon data provider
- ept::popcon::Popcon* m_popcon;
-
- /// Popcon local vote data provider
- ept::popcon::Local* m_popconlocal;
-
- /// TextSearch data provider
- Xapian::Database* m_axi;
-
- // True when operations should be verbose
- bool _verbose;
-
- // True when operations should be very verbose
- bool _debug;
-
- Environment() throw ();
-
-public:
- static Environment& get() throw ();
-
- /**
- * Initialise the data providers.
- *
- * This method must be called before they can be accessed.
- */
- void init(bool editable = false);
-
- /// Access the apt data provider
- ept::apt::Apt& apt() { return *m_apt; }
-
- /// Access the debtags data provider
- ept::debtags::Debtags& debtags() { return *m_debtags; }
-
- /// Access the tag vocabulary
- ept::debtags::Vocabulary& voc() { return *m_vocabulary; }
-
- /// Access the popcon data
- ept::popcon::Popcon& popcon() { return *m_popcon; }
-
- /// Access the popcon data
- ept::popcon::Local& popconLocal() { return *m_popconlocal; }
-
- /// Access the textsearch data
- Xapian::Database& axi() { return *m_axi; }
-
- // Accessor methods
-
- bool verbose() const throw () { return _verbose; }
- bool verbose(bool verbose) throw () { return _verbose = verbose; }
-
- bool debug() const throw () { return _debug; }
- bool debug(bool debug) throw ()
- {
- // Debug implies verbose
- if (debug)
- _verbose = true;
- return _debug = debug;
- }
-};
-
-// Commodity output functions
-
-#ifndef ATTR_PRINTF
- #ifdef GCC
- #define ATTR_PRINTF(string, first) __attribute__((format (printf, string, first)))
- #else
- #define ATTR_PRINTF(string, first)
- #endif
-#endif
-
-void fatal_error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-void error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-void warning(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-void verbose(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-void debug(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-void feedback(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
-
-static inline Environment& env() { return Environment::get(); }
-
-// vim:set ts=4 sw=4:
-#endif
diff --git a/tools/EptCacheOptions.h b/tools/EptCacheOptions.h
deleted file mode 100644
index f666e12..0000000
--- a/tools/EptCacheOptions.h
+++ /dev/null
@@ -1,293 +0,0 @@
-#ifndef EPTCACHE_OPTIONS_H
-#define EPTCACHE_OPTIONS_H
-
-/*
- * Commandline parser for tagcoll
- *
- * Copyright (C) 2003,2004,2005,2006 Enrico Zini
- *
- * 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/config.h>
-#include <wibble/commandline/parser.h>
-
-namespace wibble {
-namespace commandline {
-
-struct EptCacheOptions : public StandardParserWithMandatoryCommand
-{
-public:
- BoolOption* out_quiet;
- BoolOption* out_verbose;
-
- BoolOption* out_debug;
- BoolOption* out_names;
- BoolOption* out_short;
- BoolOption* out_full;
- BoolOption* out_tagcoll;
- IntOption* out_limit;
- IntOption* out_cutoff;
- StringOption* out_sort;
-
- StringOption* filter_tagexpr;
- StringOption* filter_type;
-
-#if 0
- BoolOption* out_facets;
- BoolOption* match_invert;
-
- BoolOption* misc_local;
- BoolOption* misc_reindex;
- IntOption* misc_distance;
- StringOption* misc_vocfile;
-
- BoolOption* smse_reltags;
- BoolOption* smse_disctags;
-
-#endif
- Engine* show;
- Engine* search;
- Engine* dumpavail;
- Engine* reindex;
- Engine* info;
- Engine* related;
-#if 0
- Engine* update;
- Engine* selfcheck;
- Engine* check;
- Engine* tagcat;
- Engine* tagshow;
- Engine* tagsearch;
- Engine* cat;
- Engine* grep;
- Engine* install;
- Engine* diff;
- Engine* maintainers;
- Engine* tag;
- Engine* submit;
- Engine* todo;
- Engine* score;
- Engine* stats;
- Engine* todoreport;
- Engine* smartsearch;
- Engine* vocfilter;
-#endif
-
- EptCacheOptions()
- : StandardParserWithMandatoryCommand("ept-cache", VERSION, 1, "enrico@enricozini.org")
- {
- usage = "<command> [options and arguments]";
- description = "High-level tool to access package information";
-
- // Output options
- out_verbose = add<BoolOption>("verbose", 'v', "verbose", "",
- "enable verbose output");
- out_debug = add<BoolOption>("debug", 0, "debug", "",
- "enable debugging output (including verbose output)");
-
- // Create the package output group
- OptionGroup* pkgOutputOpts = createGroup("Output options");
- out_names = pkgOutputOpts->add<BoolOption>("names", 0, "names", "",
- "output only the names of the packages");
- out_quiet = pkgOutputOpts->add<BoolOption>("quiet", 'q', "quiet", "",
- "do not write anything to standard output");
- out_short = pkgOutputOpts->add<BoolOption>("short", 0, "short", "",
- "output the names of the packages, plus a short description");
- out_full = pkgOutputOpts->add<BoolOption>("full", 0, "full", "",
- "output the full record of package data");
- out_tagcoll = pkgOutputOpts->add<BoolOption>("tagcoll", 0, "tagcoll", "",
- "tagcoll-style output");
- out_limit = pkgOutputOpts->add<IntOption>("limit", 0, "limit", "count",
- "maximum number of packages to show");
- out_cutoff = pkgOutputOpts->add<IntOption>("cutoff", 0, "cutoff", "percent",
- "do not show results that are this percent worse than the top result");
- out_sort = pkgOutputOpts->add<StringOption>("sort", 's', "sort", "method",
- "sort order (use 'list' for a list of supported options)");
-
- OptionGroup* filterOpts = createGroup("Filter options");
- filter_tagexpr = filterOpts->add<StringOption>("ftags", 0, "ftags", "tagexpr",
- "only print packages matching this tag expression");
- filter_type = filterOpts->add<StringOption>("type", 't', "type", "name",
- "only print packages of a given type (use 'list' for a list of supported types)");
-
-#if 0
- // Create the collection output group
- OptionGroup* collOutputOpts = createGroup("Options controlling transformations of tag data on output");
- out_facets = collOutputOpts->add<BoolOption>("facets", 0, "facets", "",
- "output only the names of the facets (mainly used for computing statistics)");
-
- // Create the matching options group
- OptionGroup* matchOpts = createGroup("Options controlling matching of packages");
- match_invert = matchOpts->add<BoolOption>("invert", 'i', "invert", "",
- "invert the match, selecting non-matching items");
-
- selfcheck = addEngine("selfcheck", "",
- "perform a series of internal self checks using the current tag data");
-
- check = addEngine("check", "<file>",
- "check that all the tags in the given tagged collection are present "
- "in the tag vocabulary. Checks the main database if no file is "
- "specified");
-
- tagcat = addEngine("tagcat", "", "output the tag vocabulary");
-
- tagshow = addEngine("tagshow", "",
- "show the vocabulary informations about a tag");
-
- tagsearch = addEngine("tagsearch", "<string [string [string ...]]>",
- "show a summary of all tags whose data contains the given strings");
-
- related = addEngine("related", "<pkg1[,pkg2[,pkg3...]]>",
- "show packages related to the given one(s)",
- "Output a list of the packages that are related to the given package or list of packages. "
- "If more than one package are to be specified, separate them with commas.\n"
- "The --distance option can be used to control how closely related the output "
- "packages should be from the package(s) specified.");
- related->examples = "debtags related mutt,mozilla-browser";
- misc_distance = related->add<IntOption>("distance", 'd', "distance",
- "set the maximum distance to use for the \"related\" command (defaults to 0)");
-
- cat = addEngine("cat", "", "output the full package tag database");
- cat->add(matchOpts);
- cat->add(collOutputOpts);
-#endif
-
- show = addEngine("show", "<pkg>",
- "show informations about a package, like apt-cache show does, but "
- "adds new fields with all available extra metadata");
- show->add(pkgOutputOpts);
-
- search = addEngine("search", "[keywords]",
- "output the names and descriptions of the packages that match"
- " the given tag expression");
- search->add(pkgOutputOpts);
- search->add(filterOpts);
-
- dumpavail = addEngine("dumpavail", "[keywords]",
- "output the full package database, with all extra metadata");
- dumpavail->add(pkgOutputOpts);
- dumpavail->add(filterOpts);
-
- reindex = addEngine("reindex", "",
- "updates the various indexes managed by libept (requires root).\n"
- "It needs to be run as root");
- reindex->add(out_quiet);
-
- info = addEngine("info", "",
- "show information about the data providers.\n");
-
- related = addEngine("related", "[pkgnames]",
- "show packages similar to the given ones",
- "Show packages similar to the given ones. Package similarity is "
- " computed by how many common elements there are in their"
- " descriptions and their tags");
- related->add(pkgOutputOpts);
- related->add(filterOpts);
-
-#if 0
- update = addEngine("update", "",
- "updates the package tag database (requires root)",
- "Collect package tag data from the sources listed in "
- "/etc/debtags/sources.list, then regenerate the debtags "
- "tag database and main index.\n"
- "It needs to be run as root");
- misc_local = update->add<BoolOption>("local", 0, "local",
- "do not download files when performing an update");
- misc_reindex = update->add<BoolOption>("reindex", 0, "reindex",
- "do not download any file, just do reindexing if needed");
-#endif
-
-#if 0
- grep = addEngine("grep", "<tag expression>",
- "output the lines of the full package tag database that match"
- " the given tag expression");
- grep->add(matchOpts);
- grep->add(collOutputOpts);
-
- install = addEngine("install", "<tag expression>",
- "apt-get install the packages that match the given tag expression",
- "Invokes apt-get install with the names of the packages matched "
- "by the given tag expression. If you want to see what packages "
- "would be installed you can use debtags search, as "
- "debtags install just calls apt-get install on all "
- "the results of an equivalent debtags search. Please note "
- "that debtags install is just a prototype feature useful "
- "for experimenting in some environments like Custom Debian "
- "Distributions. For this reason it is suggested that you "
- "use debtags just as a way to find packages, and "
- "proper package managers as the way to install them");
- install->add(matchOpts);
-
- diff = addEngine("diff", "[filename]",
- "create a tag patch between the current tag database and the tag"
- "collection [filename]. Standard input is used if filename is not specified");
- diff->aliases.push_back("mkpatch");
-
- maintainers = addEngine("maintainers", "",
- "create a tagged collection of maintainers and the tags of the"
- "packages they maintain");
- maintainers->add(collOutputOpts);
-
- tag = addEngine("tag", "{add|rm|ls} <package> [tags...]",
- "view and edit the tags for a package",
- "General manipulation of tags, useful for automation in scripts.\n"
- "It can be used in three ways:\n"
- "tag add <package> <tags...> will add the tags to the given package\n"
- "tag rm <package> <tags...> will remove the tags from the given package\n"
- "tag ls <package> will output the names of the tags of the given package");
-
- submit = addEngine("submit", "[patch]",
- "mail the given patch file to the central tag repository."
- "If [patch] is omitted, mail the local tag modifications.");
-
- todo = addEngine("todo", "",
- "print a list of the installed packages that are not yet tagged");
- todo->add(pkgOutputOpts);
-
- score = addEngine("score", "",
- "score uninstalled packages according to how often their tags "
- "appear in the packages that are installed already");
-
- stats = addEngine("stats", "",
- "print statistics about Debtags");
-
- todoreport = addEngine("todoreport", "",
- "print a report of packages needing work");
-
- smartsearch = addEngine("smartsearch", "<word [word1 [+tag [-tag1 ...]]]>",
- "Perform a keyword search integrated with related packages.\n"
- "A + prefix indicates a wanted tag. A - prefix indicates "
- "an unwanted tag. Other words indicate keywords to search.\n"
- "Remember to use '--' before unwanted tags to avoid to have "
- "them interpreted as commandline switches.\n");
- smse_reltags = smartsearch->add<BoolOption>("relevant", 0, "relevant",
- "only print the tag names sorted by increasing relevance");
- smse_disctags = smartsearch->add<BoolOption>("discriminant", 0, "discriminant",
- "only print the tag names sorted by increasing discriminance");
-
- vocfilter = addEngine("vocfilter", "tagfile",
- "filter out the tags that are not found in the given vocabulary file");
- misc_vocfile = vocfilter->add<StringOption>("vocabulary", 0, "vocabulary",
- "vocabulary file to use instead of the current debtags vocabulary");
-#endif
- }
-};
-
-}
-}
-
-// vim:set ts=4 sw=4:
-#endif
diff --git a/tools/ept-cache-man-hooks b/tools/ept-cache-man-hooks
deleted file mode 100644
index 3563668..0000000
--- a/tools/ept-cache-man-hooks
+++ /dev/null
@@ -1,49 +0,0 @@
-DESCRIPTION end
-|\fBept-cache\fP is a high-level tool to access package information.
-|.P
-|It can currently search and display data from four sources: the APT database,
-|the Debtags tag information, Popcon package scores and a fast Xapian-based full
-|text index on package descriptions.
-|.P
-|If the Xapian data source is enabled, output results are by default sorted by
-|relevance order, with the best results first. If you are seeing strange
-|results in the output, rerun the search with the \-\-full switch and look at
-|the Search\-Score headers.
-
-OPTIONS end
-|.SH EXAMPLES
-|.P
-|.nf
-|# Output all the available information about apt
-|ept-cache show apt
-|
-|# Keyword search
-|ept-cache search image editor
-|
-|# Keyword search with simple tag filter
-|ept-cache search -t gui image editor
-|
-|# More results
-|ept-cache search -t gui --limit=300 image editor
-|
-|# Output full package records for grep-dctrl.
-|# The records will contain improved Tag: headers, Popcon information and
-|# any other information that is available through libept.
-|ept-cache dumpavail -t gui image editor
-|
-|# Show packages similar to mutt
-|ept-cache related mutt
-|
-|# Show packages somewhat inbetween mutt and iceweasel
-|ept-cache related mutt iceweasel
-|
-|# Show what data sources are available
-|ept-cache info
-|
-|# Build or update the indexes (needs root)
-|ept-cache reindex
-|.fi
-
-AUTHOR before
-|.SH SEE ALSO
-|\fBdebtags\fP (1), \fBapt-cache\fP (1)
diff --git a/tools/ept-cache.cc b/tools/ept-cache.cc
deleted file mode 100644
index bd3a8af..0000000
--- a/tools/ept-cache.cc
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * 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
- * 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 "Environment.h"
-#include "EptCacheOptions.h"
-#include "info.h"
-#include "filters.h"
-#include "utils.h"
-
-#include <ept/apt/apt.h>
-#include <ept/apt/packagerecord.h>
-#include <ept/debtags/debtags.h>
-#include <ept/debtags/vocabulary.h>
-#include <ept/popcon/popcon.h>
-#include <ept/popcon/local.h>
-#include <tagcoll/expression.h>
-#include <ept/axi/axi.h>
-
-#include <wibble/regexp.h>
-#include <wibble/string.h>
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/*
- * * For packages
- *
- * Filters:
- * + keyword search
- * + tag expression
- * - min/max popularity
- * - installed status
- *
- * Sort orders
- * + unsorted
- * + alphabetical (?)
- * + by popularity
- * + by representativeness (only when installed)
- * - by xapian score
- *
- * Show
- * + Names only
- * + Names and short descriptions
- * + Full fields (dumpavail)
- * + Nothing (return value à la grep)
- *
- *
- * * For tags
- *
- * Filters
- *
- * - keyword search
- * - relevance search
- *
- * Sort orders
- *
- * - alphabetic order
- * - relevance order
- * - xapian order (automatically given by the data source)
- *
- * Show
- * - Names only
- * - Names and short descriptions
- * - Full fields (dumpavail)
- * - Nothing (return value à la grep)
- */
-
-using namespace std;
-using namespace tagcoll;
-using namespace wibble;
-using namespace ept;
-using namespace ept::debtags;
-using namespace ept::apt;
-
-static const int DEFAULT_QUALITY_CUTOFF = 50;
-
-// Database of expression macros
-struct ExpressionMacros : public map<string, string>
-{
- ExpressionMacros() {
- insert(make_pair("gui", "role::program && (interface::x11 || interface::3d)"));
- insert(make_pair("cmdline", "role::program && interface::commandline"));
- insert(make_pair("game", "role::program && game::*"));
- insert(make_pair("devel", "devel::* && !role::shared-lib"));
- insert(make_pair("clean", "!role::shared-lib && !role::app-data"));
- }
-} expressionMacros;
-
-// Sorting infrastructure
-template<typename SORTER>
-struct Negator
-{
- const SORTER& s;
-
- Negator(const SORTER& s) : s(s) {}
-
- bool operator()(const Info* a, const Info* b) const
- {
- return s(b, a);
- }
-};
-template<typename SORTER>
-Negator<SORTER> negator(const SORTER& s)
-{
- return Negator<SORTER>(s);
-}
-bool popularitySort(const Info* a, const Info* b)
-{
- return a->popcon * a->xapian_score < b->popcon * b->xapian_score;
-}
-bool tfidfSort(const Info* a, const Info* b)
-{
- return a->tfidf < b->tfidf;
-}
-bool nameSort(const Info* a, const Info* b)
-{
- return a->name < b->name;
-}
-bool downloadSizeSort(const Info* a, const Info* b)
-{
- return a->record->packageSize() < b->record->packageSize();
-}
-bool installedSizeSort(const Info* a, const Info* b)
-{
- return a->record->installedSize() < b->record->installedSize();
-}
-
-/// Consumer for package filters
-struct Consumer
-{
- size_t count;
- int limit;
-
- Consumer() : count(0), limit(-1) {}
- virtual ~Consumer() {}
-
- // Set the maximum number of items to consume from now on
- void setLimit(int limit) { this->limit = limit; }
-
- // Set the maximum number of items to consume from now on to unlimited
- void resetLimit() { limit = -1; }
-
- // Consume one Info item; returns true if it can consume more, false if
- // production should stop for this consumer
- virtual bool operator()(Info& i)
- {
- ++count;
- if (limit == -1)
- return true;
- else if (limit > 0)
- {
- --limit;
- return true;
- } else
- return false;
- }
-
- // Signal that no more items will be produced
- virtual void done() {}
-};
-
-struct Sorter : public Consumer
-{
- vector<Info*> data;
- bool reverse;
- char sortType;
- Consumer* out;
-
- Sorter(const std::string& stype, Consumer* out)
- : reverse(false), sortType(0), out(out)
- {
- // Parse the sort type
- for (string::const_iterator i = stype.begin();
- i != stype.end(); ++i)
- switch (*i)
- {
- case '-': reverse = true; break;
- default: if (!sortType) sortType = *i; break;
- }
- // Early warning to avoid complaining after generation was done
- if (sortType != 'd' && sortType != 'i' && sortType != 'n' && sortType != 'p' && sortType != 't' && sortType != 'x')
- throw wibble::exception::Consistency("parsing sort type", "invalid sort type (use 'list' for a list)");
- }
- virtual ~Sorter()
- {
- if (out) delete out;
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- delete *i;
- }
-
- /**
- * Disconnect the chained consumer so that it will not be deallocated when
- * the Sorter object is deleted.
- *
- * @returns The chained consumer
- */
- Consumer* disconnectConsumer()
- {
- Consumer* res;
- this->out = 0;
- return res;
- }
-
- virtual bool operator()(Info& i)
- {
- if (!Consumer::operator()(i))
- return false;
- data.push_back(new Info(i));
- return true;
- }
-
- virtual void done()
- {
- bool generateReversed = false;
-
- // Perform sorting
- switch (sortType)
- {
- case 'd':
- // Download size
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- (*i)->wantRecord();
- if (reverse)
- std::sort(data.begin(), data.end(), negator(downloadSizeSort));
- else
- std::sort(data.begin(), data.end(), downloadSizeSort);
- break;
- case 'i':
- // Installed size
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- (*i)->wantRecord();
- if (reverse)
- std::sort(data.begin(), data.end(), negator(installedSizeSort));
- else
- std::sort(data.begin(), data.end(), installedSizeSort);
- break;
- case 'n':
- // Alphabetical
- if (reverse)
- std::sort(data.begin(), data.end(), negator(nameSort));
- else
- std::sort(data.begin(), data.end(), nameSort);
- break;
- case 'p':
- // Popularity
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- (*i)->wantPopcon();
- if (reverse)
- std::sort(data.begin(), data.end(), negator(popularitySort));
- else
- std::sort(data.begin(), data.end(), popularitySort);
- break;
- case 't':
- // TFIDF
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- (*i)->wantPopconLocal();
- if (reverse)
- //std::sort(data.begin(), data.end(), negator(tfidfSort));
- std::sort(data.begin(), data.end(), negator(tfidfSort));
- else
- std::sort(data.begin(), data.end(), tfidfSort);
- break;
- case 'x':
- // Xapian score
-
- // We need to flip the other way round here, because xapian
- // produces results in reverse score order
- generateReversed = !reverse;
- break;
- default:
- throw wibble::exception::Consistency("sorting", "invalid sort type (use 'list' for a list)");
- }
-
- if (generateReversed)
- {
- for (vector<Info*>::reverse_iterator i = data.rbegin();
- i != data.rend(); ++i)
- if (!(*out)(**i))
- break;
- }
- else
- {
- for (vector<Info*>::iterator i = data.begin();
- i != data.end(); ++i)
- if (!(*out)(**i))
- break;
- }
- }
-};
-
-struct NullPrinter : public Consumer
-{
- virtual ~NullPrinter() {}
-};
-
-struct NamePrinter : public Consumer
-{
- ostream& out;
- NamePrinter(ostream& out) : out(out) {}
-
- virtual ~NamePrinter() {}
- virtual bool operator()(Info& i)
- {
- if (!Consumer::operator()(i))
- return false;
- out << i.name << endl;
- return true;
- }
-};
-
-struct ShortDescPrinter : public Consumer
-{
- ostream& out;
- ShortDescPrinter(ostream& out) : out(out) {}
- virtual ~ShortDescPrinter() {}
- virtual bool operator()(Info& i)
- {
- if (!Consumer::operator()(i))
- return false;
- i.wantRecord();
- out << i.name << " - " <<
- i.record->shortDescription("(short description not available)") << endl;
- return true;
- }
-};
-
-struct TagcollPrinter : public Consumer
-{
- ostream& out;
- TagcollPrinter(ostream& out) : out(out) {}
- virtual ~TagcollPrinter() {}
- virtual bool operator()(Info& i)
- {
- if (!Consumer::operator()(i))
- return false;
- i.wantTags();
- out << i.name << ": " << i.tags << endl;
- return true;
- }
-};
-
-struct FullRecordPrinter : public Consumer
-{
- bool hasDebtags;
- bool hasPopcon;
- bool hasPopconLocal;
- ostream& out;
- FullRecordPrinter(ostream& out) : out(out)
- {
- hasDebtags = env().debtags().hasData();
- hasPopcon = env().popcon().hasData();
- hasPopconLocal = env().popconLocal().hasData();
- }
- virtual ~FullRecordPrinter() {}
- virtual bool operator()(Info& info)
- {
- if (!Consumer::operator()(info))
- return false;
- info.wantRecord();
- info.wantTags();
- PackageRecord& record = *info.record;
- bool tagsPrinted = false;
- for (size_t i = 0; i < record.size(); ++i)
- {
- if (record.name(i) == "Tag")
- {
- tagsPrinted = true;
- if (!info.tags.empty())
- out << "Tag: " << info.tags << std::endl;
- } else {
- out << record.field(i);
- }
- }
- if (!tagsPrinted)
- if (!info.tags.empty())
- out << "Tag: " << info.tags << std::endl;
- if (hasPopcon)
- {
- info.wantPopcon();
- out << "Popcon: " << info.popcon << endl;
- }
- if (hasPopconLocal)
- {
- info.wantPopconLocal();
- out << "TFIDF: " << info.tfidf << endl;
- }
- if (info.has_xapian)
- {
- out << "Search-Score: " << info.xapian_score << endl;
- }
- out << std::endl;
- return true;
- }
-};
-
-/// Send a tag stream to an Info consumer
-class OutputInfo : public wibble::mixin::OutputIterator<OutputInfo>
-{
- const filter::Base& filter;
- Consumer& out;
- // When true, the consumer is ignoring the input
- bool done;
-
-public:
- OutputInfo(const filter::Base& filter, Consumer& out)
- : filter(filter), out(out), done(false) {}
-
- template<typename ITEMS, typename TAGS>
- OutputInfo& operator=(const std::pair<ITEMS, TAGS>& data)
- {
- if (done) return *this;
- for (typename ITEMS::const_iterator i = data.first.begin();
- i != data.first.end(); ++i)
- {
- if (!env().apt().isValid(*i)) continue;
- Info info(*i);
- info.has_tags = true;
- info.tags = data.second;
- if (filter(info))
- if (!out(info))
- {
- done = true;
- break;
- }
- }
- return *this;
- }
-};
-
-/**
- * Generate an Info stream and send it to a consumer.
- *
- * The sorting order will depend on what is the data provider that is chosen to
- * initiate the stream, and is thus undefined.
- */
-struct Generator
-{
- filter::And filters;
-
- Xapian::QueryParser qp;
- Xapian::Stem stem;
-
- Generator() : stem("en")
- {
- qp.set_default_op(Xapian::Query::OP_AND);
- qp.set_database(env().axi());
- qp.set_stemmer(stem);
- qp.set_stemming_strategy(Xapian::QueryParser::STEM_SOME);
- qp.add_prefix("pkg", "XP");
- qp.add_boolean_prefix("tag", "XT");
- qp.add_boolean_prefix("sec", "XS");
- }
-
- Xapian::Query makeQuery(const vector<string>& keywords)
- {
- // Add prefixes to tag names
- const Vocabulary& voc = env().voc();
- vector<string> kw;
- for (vector<string>::const_iterator i = keywords.begin();
- i != keywords.end(); ++i)
- {
- if (voc.hasTag(*i))
- kw.push_back("tag:" + *i);
- else
- kw.push_back(*i);
- }
- return qp.parse_query(str::join(kw.begin(), kw.end(), " "),
- Xapian::QueryParser::FLAG_BOOLEAN |
- Xapian::QueryParser::FLAG_LOVEHATE |
- Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE |
- Xapian::QueryParser::FLAG_WILDCARD |
- Xapian::QueryParser::FLAG_PURE_NOT |
- Xapian::QueryParser::FLAG_SPELLING_CORRECTION);
- }
-
- // Generate all the packages, without records
- void generateNames(Consumer& out)
- {
- debug("Generate iterating names\n");
- for (Apt::iterator i = env().apt().begin();
- i != env().apt().end(); ++i)
- {
- Info info(*i);
- if (filters(info))
- if (!out(info))
- break;
- }
- }
-
- // Generate all the packages, with records
- void generateRecords(Consumer& out)
- {
- debug("Generate iterating records\n");
- PackageRecord rec;
- for (Apt::record_iterator i = env().apt().recordBegin();
- i != env().apt().recordEnd(); ++i)
- {
- rec.scan(*i);
- Info info(rec.package());
- info.record = &rec;
- if (filters(info))
- if (!out(info))
- break;
- }
- }
-
- // Generate after a keyword search
- void keywordXapianSearch(const vector<string>& keywords, Consumer& out, int qualityCutoff = DEFAULT_QUALITY_CUTOFF)
- {
- debug("Generate with xapian\n");
- Xapian::Enquire enquire(env().axi());
-
- // Set up the base query
- Xapian::Query query = makeQuery(keywords);
- enquire.set_query(query);
- debug("Xapian query: %s\n", query.get_description().c_str());
-
-#if 0
- // Get a set of tags to expand the query
- vector<string> expand = env().textsearch().expand(enquire);
-
- // Build the expanded query
- Xapian::Query expansion(Xapian::Query::OP_OR, expand.begin(), expand.end());
- enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, query, expansion));
- debug("Expanded Xapian query: %s\n", enquire.get_query().get_description().c_str());
-#endif
-
- //cerr << "Q: " << enquire.get_query().get_description() << endl;
- fromXapianEnquire(enquire, out, qualityCutoff);
- }
-
- void fromXapianEnquire(Xapian::Enquire& enquire, Consumer& out, int qualityCutoff = DEFAULT_QUALITY_CUTOFF, const Xapian::MatchDecider* md = 0)
- {
- // Retrieve the first result, to compute the cutoff score
- Xapian::MSet first = enquire.get_mset(0, 1, 0, 0, md);
- Xapian::MSetIterator ifirst = first.begin();
- if (ifirst == first.end())
- // If there are no results, quit now
- return;
- // Set a percentage cutoff based on the quality of the first results
- debug(" Reference value for quality cutoff: %d%%\n", ifirst.get_percent());
- Xapian::percent cutoff = ifirst.get_percent() * qualityCutoff / 100;
- debug(" Quality cutoff at: %d%%\n", cutoff);
- enquire.set_cutoff(cutoff);
-
- bool done = false;
- for (size_t pos = 0; !done; pos += 20)
- {
- // Limit to 1000 matches
- Xapian::MSet matches = enquire.get_mset(pos, 20, 0, 0, md);
- if (matches.size() < 20)
- done = true;
- for (Xapian::MSetIterator i = matches.begin(); i != matches.end(); ++i)
- {
- // Filter out results that apt doesn't know
- if (!env().apt().isValid(i.get_document().get_data()))
- {
- debug(" Not in apt database: %s\n", i.get_document().get_data().c_str());
- continue;
- }
- // Create the info element
- Info info(i.get_document().get_data());
- info.has_xapian = true;
- info.xapian_score = i.get_percent();
-
- debug(" Producing %s (%d%%)\n", info.name.c_str(), info.xapian_score);
-
- // Pass it on to the consumer
- if (filters(info))
- if (!out(info))
- {
- done = true;
- break;
- }
- }
- }
- }
-
- void keywordAptSearch(const vector<string>& keywords, Consumer& out)
- {
- debug("Generate iterating records plus a keyword search\n");
- filters.acquire_front(new filter::Description(keywords));
- generateRecords(out);
- }
-
- void debtagsSearch(const set<std::string>& wantedTags, Consumer& out)
- {
- debug("Generate by querying debtags\n");
- env().debtags().outputHavingTags(wantedTags, OutputInfo(filters, out));
- }
-};
-
-
-/**
- * Instantiate the consumer defined by the output options.
- *
- * If no output option has been specified, it returns the given default.
- * Otherwise it creates a new default consumer and deletes the default one.
- */
-Consumer* createPrinter(const wibble::commandline::EptCacheOptions& opts, Consumer* def)
-{
- Consumer* res = 0;
- if (opts.out_names->boolValue())
- res = new NamePrinter(cout);
- else if (opts.out_short->boolValue())
- res = new ShortDescPrinter(cout);
- else if (opts.out_full->boolValue())
- res = new FullRecordPrinter(cout);
- else if (opts.out_quiet->boolValue())
- res = new NullPrinter();
- else if (opts.out_tagcoll->boolValue())
- res = new TagcollPrinter(cout);
- else
- res = def;
- if (res != def)
- delete def;
- return res;
-}
-
-bool usesXapian(wibble::commandline::EptCacheOptions& opts)
-{
- return opts.hasNext() && axi::timestamp() > 0;
-}
-
-void generate(wibble::commandline::EptCacheOptions& opts, Consumer& output,
- int defaultXapianLimit = -1, int defaultXapianQualityCutoff = DEFAULT_QUALITY_CUTOFF)
-{
- Generator gen;
-
- // Append filters
- if (opts.filter_tagexpr->isSet())
- gen.filters.acquire(new filter::TagExpression(opts.filter_tagexpr->stringValue()));
-
- if (opts.filter_type->isSet())
- {
- ExpressionMacros::const_iterator i = expressionMacros.find(opts.filter_type->stringValue());
- if (i == expressionMacros.end())
- throw wibble::exception::Consistency("parsing filter type", "invalid filter type (use 'list' for a list)");
- gen.filters.acquire(new filter::TagExpression(i->second));
- }
-
- // Configure the output consumer with sorters and limits
- Consumer* cons = &output;
-
- // If we sort, we introduce an intermediate step
- if (opts.out_sort->isSet())
- cons = new Sorter(opts.out_sort->stringValue(), cons);
-
- // Set the output limit where it's needed
- bool xapian = usesXapian(opts);
- if (xapian)
- {
- if (opts.out_sort->isSet())
- {
- // If we use Xapian and we have a sorter, we need a cutoff
- // at the quality score: since the sorter will scramble the
- // xapian relevance scoring, we only need to feed good
- // results to it
-
- // Keep the default Xapian quality cutoff set by the user, then
-
- // Set the match limit on the printer side
- if (opts.out_limit->isSet())
- output.setLimit(opts.out_limit->intValue());
- } else {
- // If we use Xapian and don't have a sorter, we can keep
- // generating less relevant results as the xapian sorting
- // order will help the user to make sense of the results
- defaultXapianQualityCutoff = -1;
-
- // Set the match limit at the beginning of the output chain
- if (opts.out_limit->isSet())
- cons->setLimit(opts.out_limit->intValue());
- else if (defaultXapianLimit != -1)
- // Xapian shows the best matches first, so we can greatly
- // reduce the limit
- cons->setLimit(defaultXapianLimit);
- }
- }
- else
- {
- // If we don't use Xapian, the packages arrive in undefined
- // order, so we need to feed all of them to the sorter
- // because we don't know when the top scored packages will
- // be generated, or to the output
-
- // Set the match limit on the printer side
- if (opts.out_limit->isSet())
- output.setLimit(opts.out_limit->intValue());
- }
-
- if (opts.out_cutoff->isSet())
- defaultXapianQualityCutoff = opts.out_cutoff->intValue();
-
- if (opts.hasNext())
- {
- // We have keywords
- vector<string> keywords;
- while (opts.hasNext())
- keywords.push_back(toLower(opts.next()));
- if (axi::timestamp() > 0)
- gen.keywordXapianSearch(keywords, *cons, defaultXapianQualityCutoff);
- else
- gen.keywordAptSearch(keywords, *cons);
- } else {
- // No keyword search
- if (opts.out_names->boolValue())
- gen.generateNames(*cons);
- else
- gen.generateRecords(*cons);
- }
-
- // Signal the end of input to the consumers
- cons->done();
-}
-
-struct BlacklistDecider : public Xapian::MatchDecider
-{
- std::set<std::string> blacklist;
- BlacklistDecider() {}
- BlacklistDecider(const std::set<std::string>& blacklist) : blacklist(blacklist) {}
-
- virtual bool operator()(const Xapian::Document& doc) const
- {
- return blacklist.find(doc.get_data()) == blacklist.end();
- }
-};
-
-Xapian::Query makeRelatedQuery(const std::string& pkgname)
-{
- Xapian::Enquire enquire(env().axi());
-
- // Retrieve the document for the given package
- enquire.set_query(Xapian::Query("XP"+pkgname));
- Xapian::MSet matches = enquire.get_mset(0, 1);
- Xapian::MSetIterator mi = matches.begin();
- if (mi == matches.end()) return Xapian::Query();
- Xapian::Document doc = mi.get_document();
-
- // Return the query to get the list of similar documents
- return Xapian::Query(Xapian::Query::OP_OR, doc.termlist_begin(), doc.termlist_end());
-}
-
-void generateRelated(wibble::commandline::EptCacheOptions& opts, Consumer& output,
- int defaultXapianLimit = -1, int defaultXapianQualityCutoff = DEFAULT_QUALITY_CUTOFF)
-{
- Generator gen;
-
- // Append filters
- if (opts.filter_tagexpr->isSet())
- gen.filters.acquire(new filter::TagExpression(opts.filter_tagexpr->stringValue()));
-
- if (opts.filter_type->isSet())
- {
- ExpressionMacros::const_iterator i = expressionMacros.find(opts.filter_type->stringValue());
- if (i == expressionMacros.end())
- throw wibble::exception::Consistency("parsing filter type", "invalid filter type (use 'list' for a list)");
- gen.filters.acquire(new filter::TagExpression(i->second));
- }
-
- // Configure the output consumer with sorters and limits
- Consumer* cons = &output;
-
- // If we sort, we introduce an intermediate step
- if (opts.out_sort->isSet())
- cons = new Sorter(opts.out_sort->stringValue(), cons);
-
- // Set the output limit where it's needed
- if (opts.out_sort->isSet())
- {
- // If we use Xapian and we have a sorter, we need a cutoff
- // at the quality score: since the sorter will scramble the
- // xapian relevance scoring, we only need to feed good
- // results to it
-
- // Keep the default Xapian quality cutoff set by the user, then
-
- // Set the match limit on the printer side
- if (opts.out_limit->isSet())
- output.setLimit(opts.out_limit->intValue());
- } else {
- // If we use Xapian and don't have a sorter, we can keep
- // generating less relevant results as the xapian sorting
- // order will help the user to make sense of the results
- defaultXapianQualityCutoff = -1;
-
- // Set the match limit at the beginning of the output chain
- if (opts.out_limit->isSet())
- cons->setLimit(opts.out_limit->intValue());
- else if (defaultXapianLimit != -1)
- // Xapian shows the best matches first, so we can greatly
- // reduce the limit
- cons->setLimit(defaultXapianLimit);
- }
-
- if (opts.out_cutoff->isSet())
- defaultXapianQualityCutoff = opts.out_cutoff->intValue();
-
- Xapian::Enquire enq(env().axi());
- string name = opts.next();
- Xapian::Query query = makeRelatedQuery(name);
- BlacklistDecider blacklister;
- debug("Excluding '%s' from the results\n", name.c_str());
- blacklister.blacklist.insert(name);
- // We can even easily compute packages related to a list of packages
- while (opts.hasNext())
- {
- name = opts.next();
- debug("Excluding '%s' from the results\n", name.c_str());
- blacklister.blacklist.insert(name);
- if (!env().apt().isValid(name))
- throw wibble::exception::Consistency("reading package names", "package "+name+" does not exist");
- query = Xapian::Query(Xapian::Query::OP_AND, query, makeRelatedQuery(name));
- }
- //enq.register_match_decider("blacklist", &blacklister);
- //gen.filters.acquire(new filter::Blacklist(seen));
- enq.set_query(query);
-
- // Generate from the Xapian enquire
- //cerr << "Q: " << enq.get_query().get_description() << endl;
- gen.fromXapianEnquire(enq, *cons, defaultXapianQualityCutoff, &blacklister);
-
- // Signal the end of input to the consumers
- cons->done();
-}
-
-bool printOutOptionsHelpIfNeeded(wibble::commandline::EptCacheOptions& opts)
-{
- if (opts.filter_type->isSet() && opts.filter_type->stringValue() == "list")
- {
- for (ExpressionMacros::const_iterator i = expressionMacros.begin();
- i != expressionMacros.end(); ++i)
- cout << i->first << ": " << i->second << endl;
- return true;
- }
-
- if (opts.out_sort->isSet() && opts.out_sort->stringValue() == "list")
- {
- cout << "Available sort options:" << endl
- << endl
- << "download size - Sort by download size" << endl
- << "installed size - Sort by installed size" << endl
- << "name - Sort alphabetically by package name" << endl
- << "popularity - Sort by popcon popularity" << endl
- << "tfidf - Sort by how much a package makes a system unique" << endl
- << "xapian - Sort by xapian relevance score" << endl
- << endl
- << "It is sufficient to provide a nonambiguous prefix of the sort type." << endl
- << "Add a '-' to the begining or end to reverse the sort order." << endl
- << "Example:" << endl
- << " ept-cache search -s p- image editor" << endl;
- return true;
- }
- return false;
-}
-
-int success_if_had_output(Consumer* output)
-{
- int count = output->count;
- delete output;
- return count > 0 ? 0 : 1;
-}
-
-int main(int argc, const char* argv[])
-{
- wibble::commandline::EptCacheOptions opts;
- bool warn_non_root_on_error = false;
-
- try {
- // Install the handler for unexpected exceptions
- wibble::exception::InstallUnexpected installUnexpected;
-
- if (opts.parse(argc, argv))
- return 0;
-
- if (opts.out_verbose->boolValue())
- ::Environment::get().verbose(true);
-
- if (opts.out_debug->boolValue())
- ::Environment::get().debug(true);
-
- // show <pkg>
- // Similar to apt-cache show <pkg>, but add extra metadata to the output."
- if (opts.foundCommand() == opts.show)
- {
- env().init();
- Consumer* output = createPrinter(opts, new FullRecordPrinter(cout));
- while (opts.hasNext())
- {
- string name = opts.next();
-
- if (env().apt().isValid(name))
- {
- Info i(name);
- (*output)(i);
- } else {
- verbose("Package %s not found", name.c_str());
- }
- }
- return success_if_had_output(output);
- }
- else if (opts.foundCommand() == opts.search)
- {
- if (printOutOptionsHelpIfNeeded(opts))
- return 1;
- env().init();
- Consumer* output = createPrinter(opts, new ShortDescPrinter(cout));
-
- // Generate the results
- generate(opts, *output, 50, DEFAULT_QUALITY_CUTOFF);
-
- return success_if_had_output(output);
- }
- // dumpavail
- // Output the full package database, with all the extra info available
- else if (opts.foundCommand() == opts.dumpavail)
- {
- if (printOutOptionsHelpIfNeeded(opts))
- return 1;
- env().init();
- Consumer* output = createPrinter(opts, new FullRecordPrinter(cout));
-
- // Generate the results
- generate(opts, *output, -1, -1);
-
- return success_if_had_output(output);
- }
- // related
- // List packages related to the given one
- else if (opts.foundCommand() == opts.related)
- {
- if (printOutOptionsHelpIfNeeded(opts))
- return 1;
- env().init();
- Consumer* output = createPrinter(opts, new ShortDescPrinter(cout));
-
- // Generate the results
- generateRelated(opts, *output, 15, DEFAULT_QUALITY_CUTOFF);
-
- return success_if_had_output(output);
- }
- // reindex
- // Rebuilds indexes (requires root)
- else if (opts.foundCommand() == opts.reindex)
- {
- warn_non_root_on_error = true;
-
- mode_t prev_umask = umask(022);
-
- int exitcode;
- if (opts.out_quiet->boolValue())
- exitcode = system("update-apt-xapian-index --quiet");
- else
- exitcode = system("update-apt-xapian-index");
- if (exitcode != 0)
- {
- stringstream str;
- str << "got an exit code of " << exitcode;
- throw wibble::exception::Consistency("running update-apt-xapian-index", str.str());
- }
-
- // TODO: if verbose, print the various data files used
-
- umask(prev_umask);
- }
- // info
- // Show information about the data providers
- else if (opts.foundCommand() == opts.info)
- {
- env().init();
- if (env().debtags().hasData())
- cout << "Debtags: enabled." << endl;
- else
- cout << "Debtags: disabled. To enable it, run 'debtags update' as root." << endl;
-
- if (env().popcon().hasData())
- cout << "Popcon: enabled." << endl;
- else
- cout << "Popcon: disabled. To enable it, download http://popcon.debian.org/all-popcon-results.txt.gz" << endl
- << " in /var/lib/popcon/ and run 'ept-cache reindex' as root" << endl;
-
- if (env().popconLocal().hasData())
- cout << "Popcon local scan: enabled." << endl;
- else
- cout << "Popcon local scan: disabled. To enable it, install the popularity-contest package and" << endl
- << " enable it to run." << endl;
-
- time_t xts = axi::timestamp();
- if (xts > 0)
- if (xts < env().apt().timestamp())
- cout << "Xapian: enabled but not up to date. To update it, run 'update-apt-xapian-index' as root." << endl;
- else
- cout << "Xapian: enabled and up to date." << endl;
- else
- cout << "Xapian: disabled. To enable it, run 'ept-cache reindex' as root" << endl;
-
- // TODO: if verbose, print the various data files used
- }
- else
- throw wibble::exception::BadOption(string("unhandled command ") +
- (opts.foundCommand() ? opts.foundCommand()->name() : "(null)"));
-
- return 0;
- } catch (wibble::exception::BadOption& e) {
- cerr << e.desc() << endl;
- opts.outputHelp(cerr);
- return 1;
- } catch (std::exception& e) {
- cerr << e.what() << endl;
- if (warn_non_root_on_error && getuid() != 0)
- cerr << "You may need to be root to perform this operation." << endl;
- return 1;
- } catch (Xapian::DatabaseVersionError& e) {
- cerr << "Xapian " << e.get_type() << ": " << e.get_msg();
- if (!e.get_context().empty())
- cerr << ". Context: " << e.get_context();
- cerr << endl;
- cerr << endl;
- cerr << "Please recreate the database by removing /var/lib/apt-xapian and running ept-cache reindex as root." << endl;
- } catch (Xapian::Error& e) {
- cerr << "Xapian " << e.get_type() << ": " << e.get_msg();
- if (!e.get_context().empty())
- cerr << ". Context: " << e.get_context();
- cerr << endl;
- if (warn_non_root_on_error && getuid() != 0)
- cerr << "You may need to be root to perform this operation." << endl;
- return 1;
- }
-}
-
-#include <ept/debtags/debtags.tcc>
-
-// vim:set ts=4 sw=4:
diff --git a/tools/filters.cc b/tools/filters.cc
deleted file mode 100644
index f4f21de..0000000
--- a/tools/filters.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * Copyright (C) 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 "filters.h"
-#include "info.h"
-#include "utils.h"
-
-#include <ept/apt/packagerecord.h>
-
-#include <wibble/regexp.h>
-
-using namespace std;
-
-namespace filter {
-
-And::~And()
-{
- for (iterator i = begin(); i != end(); ++i)
- delete *i;
-}
-void And::acquire_front(Base* filter)
-{
- insert(begin(), filter);
-}
-void And::acquire(Base* filter)
-{
- push_back(filter);
-}
-bool And::operator()(Info& info) const
-{
- if (empty())
- return true;
- for (const_iterator i = begin(); i != end(); ++i)
- if (!(**i)(info))
- return false;
- return true;
-}
-
-Or::~Or()
-{
- for (iterator i = begin(); i != end(); ++i)
- delete *i;
-}
-void Or::acquire_front(Base* filter)
-{
- insert(begin(), filter);
-}
-void Or::acquire(Base* filter)
-{
- push_back(filter);
-}
-bool Or::operator()(Info& info) const
-{
- if (empty())
- return true;
- for (const_iterator i = begin(); i != end(); ++i)
- if ((**i)(info))
- return true;
- return false;
-}
-
-Description::Description(const std::string& str)
-{
- wibble::Tokenizer tok(str, "[^[:blank:]]+", REG_EXTENDED);
- for (wibble::Tokenizer::const_iterator i = tok.begin();
- i != tok.end(); ++i)
- keywords.push_back(toLower(*i));
-}
-
-bool Description::operator()(Info& info) const
-{
- info.wantRecord();
- string name = toLower(info.name);
- string desc = toLower(info.record->description());
- for (std::vector<std::string>::const_iterator i = keywords.begin();
- i != keywords.end(); ++i)
- if (name.find(*i) == string::npos && desc.find(*i) == string::npos)
- return false;
- return true;
-}
-
-bool TagExpression::operator()(Info& info) const
-{
- info.wantTags();
- return expr(info.tags);
-}
-
-bool Blacklist::operator()(Info& info) const
-{
- return blacklist.find(info.name) == blacklist.end();
-}
-
-}
-
-// vim:set ts=4 sw=4:
diff --git a/tools/filters.h b/tools/filters.h
deleted file mode 100644
index 050172a..0000000
--- a/tools/filters.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * Copyright (C) 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
- */
-
-#ifndef EPTCACHE_FILTERS_H
-#define EPTCACHE_FILTERS_H
-
-#include <vector>
-#include <string>
-
-#include <tagcoll/expression.h>
-
-/*
- * * For packages
- *
- * Filters:
- * - keyword search
- * - tag expression
- * - min/max popularity
- * - installed status
- *
- */
-
-class Info;
-
-namespace filter {
-
-/// Interface for package filters
-struct Base
-{
- virtual ~Base() {}
- virtual bool operator()(Info& i) const = 0;
-};
-
-/// ANDs a list of filters, with short-circuit semantics
-struct And : public std::vector<Base*>, public Base
-{
- virtual ~And();
- // Add a filter at the beginning of the list
- void acquire_front(Base* filter);
- // Add a filter at the end of the list
- void acquire(Base* filter);
- // Match the info if all filters match
- virtual bool operator()(Info& info) const;
-};
-
-/// ORs a list of filters, with short-circuit semantics
-struct Or : public std::vector<Base*>, public Base
-{
- virtual ~Or();
- // Add a filter at the beginning of the list
- void acquire_front(Base* filter);
- // Add a filter at the end of the list
- void acquire(Base* filter);
- // Match the info if one of the filters match
- virtual bool operator()(Info& info) const;
-};
-
-/// Negates a filter
-struct Not : public Base
-{
- Base* filter;
- Not(Base* filter) : filter(filter) {}
- virtual ~Not() { if (filter) delete filter; }
- virtual bool operator()(Info& info) const
- {
- return ! (*filter)(info);
- }
-};
-
-/// Text search on package name and description
-struct Description : public Base
-{
- std::vector<std::string> keywords;
-
- // Split up the string in keywords and lowercase them
- Description(const std::string& str);
-
- // Assume split up, lowercased keywords
- Description(const std::vector<std::string>& keywords) : keywords(keywords) {}
-
- virtual bool operator()(Info& info) const;
-};
-
-// Debtags expression filter
-struct TagExpression : public Base
-{
- tagcoll::Expression expr;
-
- TagExpression(const std::string& expr) : expr(expr) {}
- TagExpression(const tagcoll::Expression& expr) : expr(expr) {}
-
- virtual bool operator()(Info& info) const;
-};
-
-// Blacklist filter
-struct Blacklist : public Base
-{
- std::set<std::string> blacklist;
-
- Blacklist(const std::set<std::string>& blacklist) : blacklist(blacklist) {}
-
- virtual bool operator()(Info& info) const;
-};
-
-}
-
-#endif
-// vim:set ts=4 sw=4:
diff --git a/tools/info.cc b/tools/info.cc
deleted file mode 100644
index 2f7ba3e..0000000
--- a/tools/info.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * 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
- * 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 "info.h"
-
-#include "Environment.h"
-
-#include <ept/apt/apt.h>
-#include <ept/apt/packagerecord.h>
-#include <ept/debtags/debtags.h>
-#include <ept/popcon/popcon.h>
-#include <ept/popcon/local.h>
-
-using namespace std;
-using namespace ept;
-using namespace ept::debtags;
-using namespace ept::apt;
-
-Info::Info(const std::string& name)
- : name(name), has_xapian(false), xapian_score(100), deallocate_record(false), record(0), has_tags(false), has_popcon(false), has_local(false) {}
-
-Info::~Info()
-{
- if (deallocate_record && record)
- delete record;
-}
-
-Info::Info(const Info& i)
- : name(i.name), has_xapian(i.has_xapian), xapian_score(i.xapian_score),
- has_tags(i.has_tags), tags(i.tags), has_popcon(i.has_popcon),
- popcon(i.popcon), has_local(i.has_local), tfidf(i.tfidf)
-{
- if (i.record)
- {
- deallocate_record = true;
- record = new PackageRecord(*i.record);
- } else {
- deallocate_record = false;
- record = 0;
- }
-}
-
-Info::Info& Info::operator=(const Info& i)
-{
- name = i.name;
- has_xapian = i.has_xapian;
- xapian_score = i.xapian_score;
- has_tags = i.has_tags;
- tags = i.tags;
- has_popcon = i.has_popcon;
- popcon = i.popcon;
- has_local = i.has_local;
- tfidf = i.tfidf;
-
- if (i.record)
- {
- PackageRecord* newrec = new PackageRecord(*i.record);
- if (record && deallocate_record)
- delete record;
- deallocate_record = true;
- record = newrec;
- } else {
- if (record && deallocate_record)
- delete record;
- deallocate_record = false;
- record = 0;
- }
- return *this;
-}
-
-void Info::wantRecord()
-{
- if (record) return;
- record = new PackageRecord(env().apt().rawRecord(name));
- deallocate_record = true;
-}
-
-void Info::wantTags()
-{
- if (has_tags) return;
- tags = env().debtags().getTagsOfItem(name);
- if (tags.empty() && !env().debtags().hasData())
- {
- wantRecord();
- set<string> stags = record->tag();
- for (set<string>::const_iterator i = stags.begin();
- i != stags.end(); ++i)
- tags.insert(*i);
- }
- has_tags = true;
-}
-
-void Info::wantPopcon()
-{
- if (has_popcon) return;
- popcon = env().popcon().score(name);
- has_popcon = true;
-}
-
-void Info::wantPopconLocal()
-{
- if (has_local) return;
- tfidf = env().popconLocal().tfidf(env().popcon(), name);
- has_local = true;
-}
-
-#include <ept/debtags/debtags.tcc>
-
-// vim:set ts=4 sw=4:
diff --git a/tools/info.h b/tools/info.h
deleted file mode 100644
index 7fe6d0b..0000000
--- a/tools/info.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef EPTCACHE_INFO_H
-#define EPTCACHE_INFO_H
-
-#include <string>
-#include <set>
-
-namespace ept {
-namespace apt {
-class PackageRecord;
-}
-}
-
-/**
- * Information about a package.
- *
- * This allows to have a stream of:
- * \l names
- * \l package records
- * \l tags
- * \l popcon scores
- * \l xapian scores
- *
- * All optional and only retrieved on demand
- */
-struct Info
-{
- std::string name;
-
- // This is only available if the info stream is generated by a Xapian
- // search. Therefore there is no wantXapian() method.
- bool has_xapian;
- int xapian_score;
-
- bool deallocate_record;
- ept::apt::PackageRecord* record;
-
- bool has_tags;
- std::set<std::string> tags;
-
- bool has_popcon;
- float popcon;
-
- bool has_local;
- float tfidf;
-
- Info(const std::string& name);
- Info(const Info& i);
- ~Info();
-
- Info& operator=(const Info& i);
-
- void wantRecord();
- void wantTags();
- void wantPopcon();
- void wantPopconLocal();
-};
-
-#endif
-// vim:set ts=4 sw=4:
diff --git a/tools/manpage.cc b/tools/manpage.cc
deleted file mode 100644
index e4909ce..0000000
--- a/tools/manpage.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * tagged collection - Experimental programs to test and study tagged collections
- *
- * Copyright (C) 2003,2004,2005,2006 Enrico Zini
- *
- * 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/config.h>
-#include <wibble/commandline/doc.h>
-#include "EptCacheOptions.h"
-#include <iostream>
-
-using namespace std;
-
-int main(int argc, const char* argv[])
-{
- try {
- if (argc == 1)
- throw wibble::exception::BadOption("no arguments provided");
-
- string cmd(argv[1]);
- string hooks(argc > 2 ? argv[2] : "");
-
- if (cmd == "ept-cache")
- {
- wibble::commandline::EptCacheOptions opts;
- wibble::commandline::Manpage help("ept-cache", VERSION, 1, "enrico@enricozini.org");
- if (!hooks.empty())
- help.readHooks(hooks);
- help.output(cout, opts);
- }
- else
- throw wibble::exception::BadOption("unknown command " + cmd);
-
- return 0;
- } catch (wibble::exception::BadOption& e) {
- cerr << e.desc() << endl << endl;
- cerr << "Usage: manpage <command>" << endl << endl;
- cerr << "Supported commands are: ept-cache" << endl;
- return 1;
- } catch (std::exception& e) {
- cerr << e.what() << endl;
- return 1;
- }
-}
-
-#include <ept/debtags/debtags.tcc>
-
-// vim:set ts=4 sw=4:
diff --git a/tools/utils.h b/tools/utils.h
deleted file mode 100644
index d0e7034..0000000
--- a/tools/utils.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ept-cache - Commandline interface to the ept library
- *
- * Copyright (C) 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
- */
-
-#ifndef EPTCACHE_UTILS_H
-#define EPTCACHE_UTILS_H
-
-#include <string>
-#include <ostream>
-
-#include <wibble/singleton.h>
-#include <wibble/empty.h>
-
-namespace std {
-
-// Facilities for outputting a tag set
-template<typename TAG, typename _Traits>
-basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const std::set<TAG>& tags)
-{
- for (typename std::set<TAG>::const_iterator i = tags.begin();
- i != tags.end(); i++)
- if (i == tags.begin())
- out << *i;
- else
- out << ", " << *i;
- return out;
-}
-
-// Facilities for outputting a wibble::Singleton
-template<typename TAG, typename _Traits>
-basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const wibble::Singleton<TAG>& tags)
-{
- out << *tags.begin();
- return out;
-}
-
-// Facilities for outputting a wibble::Empty
-template<typename TAG, typename _Traits>
-basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const wibble::Empty<TAG>&)
-{
- return out;
-}
-
-}
-
-// Convert a string to lower case
-static inline std::string toLower(const std::string& s)
-{
- std::string res;
- for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
- res += tolower(*i);
- return res;
-}
-
-#endif
-// vim:set ts=4 sw=4: