[Debtags-commits] [svn] r1641 - debtags/trunk/tools
Enrico Zini
enrico at costa.debian.org
Sun Mar 5 18:01:37 UTC 2006
Author: enrico
Date: Sun Mar 5 18:01:35 2006
New Revision: 1641
Added:
debtags/trunk/tools/DebtagsOptions.h
Removed:
debtags/trunk/tools/CommandlineParser.cc
debtags/trunk/tools/CommandlineParser.h
Modified:
debtags/trunk/tools/Makefile.am
debtags/trunk/tools/debtags.cc
Log:
Ported to the new commandline parser
Modified: debtags/trunk/tools/Makefile.am
==============================================================================
--- debtags/trunk/tools/Makefile.am (original)
+++ debtags/trunk/tools/Makefile.am Sun Mar 5 18:01:35 2006
@@ -5,7 +5,6 @@
debtags_SOURCES = \
Exec.cc \
ChildProcess.cc \
- CommandlineParser.cc \
Environment.cc \
acqprogress.cc \
instantiations.cc \
@@ -14,4 +13,4 @@
INCLUDES = -I.. $(LIBTAGCOLL_CFLAGS) $(LIBABT_FRONT_CFLAGS)
-EXTRA_DIST = acqprogress.h ChildProcess.h CommandlineParser.h Environment.h Exec.h Printer.h
+EXTRA_DIST = acqprogress.h ChildProcess.h DebtagsOptions.h Environment.h Exec.h Printer.h
Modified: debtags/trunk/tools/debtags.cc
==============================================================================
--- debtags/trunk/tools/debtags.cc (original)
+++ debtags/trunk/tools/debtags.cc Sun Mar 5 18:01:35 2006
@@ -46,7 +46,7 @@
#include <tagcoll/experiments.h>
#include "Environment.h"
-#include "CommandlineParser.h"
+#include "DebtagsOptions.h"
#include "acqprogress.h"
#include "Printer.h"
@@ -1096,859 +1096,706 @@
public:
};
-class CommandlineParserWithCommand : public CommandlineParser
+int main(int argc, const char* argv[])
{
-protected:
- map<string, int> command_map;
+ commandline::DebtagsOptions opts;
-public:
- CommandlineParserWithCommand(const std::string& argv0,
- const std::string& cmdline_summary,
- const std::string& description) throw ()
- : CommandlineParser(argv0, cmdline_summary, description)
- {
- add("version", 'V', "version", "print the program version, then exit");
- }
+ try {
+ // Install the handler for unexpected exceptions
+ InstallUnexpected installUnexpected;
- void addCommand(const std::string name, int id) throw ()
- {
- command_map[name] = id;
- }
+ opts.parse(argc, argv);
+ if (!opts.lastCommand())
+ throw commandline::BadOption("could not understand the command to execute");
- int parse(int& argc, const char**& argv) throw ()
- {
- if (!CommandlineParser::parse(argc, argv))
+ if (opts.outputGroup.verbose->boolValue())
+ ::Environment::get().verbose(true);
+
+ if (opts.outputGroup.debug->boolValue())
+ ::Environment::get().debug(true);
+
+ // Perform the correct operation
+ if (opts.helpGroup.help->boolValue())
{
- printHelp();
- exit(1);
+ // Provide help as requested
+ commandline::Help help(APPNAME, VERSION);
+ commandline::OptionParser* o = opts.lastCommand();
+
+ if (o && !o->name().empty())
+ // Help on a specific command
+ help.outputHelp(cout, *o);
+ else
+ // General help
+ help.outputHelp(cout, opts);
}
- if (get("help").defined())
+ else if (opts.helpGroup.version->boolValue())
{
- printHelp();
- exit(0);
+ // Print the program version
+ commandline::Help help(APPNAME, VERSION);
+ help.outputVersion(cout);
}
- if (get("version").defined())
+ else if (opts.lastCommand() == &opts.generic)
{
- printf("%s ver." PACKAGE_VERSION "\n", APPNAME);
- exit(0);
+ commandline::Help help(APPNAME, VERSION);
+ help.outputHelp(cout, opts);
}
- if (argc == 1)
+ else if (opts.lastCommand() == &opts.help)
{
- printHelp();
- exit(1);
+ commandline::Help help(APPNAME, VERSION);
+ commandline::OptionParser* o = 0;
+ if (opts.hasNext())
+ o = opts.command(opts.next());
+
+ if (o)
+ // Help on a specific command
+ help.outputHelp(cout, *o);
+ else
+ // General help
+ help.outputHelp(cout, opts);
}
-
- string command_string = argv[1];
- map<string, int>::const_iterator cmap_i = command_map.find(command_string);
- if (cmap_i == command_map.end())
+ else if (opts.lastCommand() == &opts.selfcheck)
{
- fprintf(stderr, "Invalid command: \"%.*s\"\n", PFSTR(command_string));
- printHelp();
- exit(1);
- }
+ debtagsInit();
+ component::Tags& voc = Global::get().tags();
- for (int i = 1; i < argc; i++)
- argv[i] = argv[i + 1];
- --argc;
-
- return cmap_i->second;
- }
-};
+ // ensure that all facets are readable
+ FacetSet facets = voc.facets();
+ for (FacetSet::const_iterator i = facets.begin(); i != facets.end(); i++)
+ {
+ i->name(string("foo"));
+ i->shortDescription(string("foo"));
+ i->longDescription(string("foo"));
+ i->tags();
+ }
+
+ // ensure that all tags are readable
+ TagSet tags = voc.tags();
+ for (TagSet::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"));
+ }
-class CommandlineArgs
-{
-protected:
- int argc;
- const char** argv;
- int _next;
+ return 0;
+ }
+ // Output the full package tag database
+ else if (opts.lastCommand() == &opts.cat)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+ auto_ptr< Printer<Package, Tag> > printer;
-public:
- CommandlineArgs(int argc, const char* argv[]) throw () : argc(argc), argv(argv), _next(1) {}
+ if (opts.outputGroup.group->boolValue())
+ printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
+ else
+ printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
- // Return true if there is another argument left in the list
- bool hasNext() const throw () { return argc >= _next + 1; }
+ Searcher searcher(debtags, printer.get());
+ searcher.output();
- // Return the next argument in the list
- string next() throw ()
- {
- if (hasNext())
- {
- return argv[_next++];
- } else {
- return "-";
+ return 0;
}
- }
-};
+ // search [-v] <tag expression>\n"
+ // Output the names and description of the packages that match\n"
+ // the given tag expression\n"
+ else if (opts.lastCommand() == &opts.search)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+ APTPrinter printer;
+ Searcher searcher(debtags, &printer);
+ string expression = opts.next();
-enum valid_command { UPDATE, SELFCHECK, CHECK, TAGSHOW, TAGSEARCH, TAGCAT, SHOW, RELATED, CAT, SEARCH, GREP, INSTALL, MKPATCH, MAINTAINERS, TAG, SUBMIT, TODO, SCORE, FACETCOLL, STATS, TODOREPORT, SMARTSEARCH };
+ int matched =
+ searcher.output(expression, opts.matchGroup.invert->boolValue());
-int main(int argc, const char* argv[])
-{
- try {
- // Install the handler for unexpected exceptions
- InstallUnexpected installUnexpected;
+ return matched > 0 ? 0 : 1;
+ }
+ // grep [-v] [-q] <tag expression>
+ // Output the lines of the full package tag database that match the
+ // given tag expression
+ else if (opts.lastCommand() == &opts.grep)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+ auto_ptr< Printer<Package, Tag> > printer;
+
+ if (opts.outputGroup.quiet->boolValue())
+ printer = auto_ptr< Printer<Package, Tag> >(new NullPrinter);
+ if (opts.outputGroup.group->boolValue())
+ printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
+ else
+ printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
- CommandlineParserWithCommand opts(APPNAME, "[options] [command] [file1|-] [file2|-]",
- "Commandline interface to access and manipulate Debian Package Tags.\n\n"
- "Commands are:\n"
- " update Updates the package tag database (requires root)\n"
- " selfcheck Perform a series of internal self checks using the current tag data\n"
- " check <file> Check that all the tags in the given tagged collection are present\n"
- " in the tag vocabulary. Checks the main database if no file is\n"
- " specified\n"
- " tagcat Output the tag vocabulary\n"
- " tagshow <tag> Show the vocabulary informations about a tag\n"
- " tagsearch <string [string [string [...]]]>\n"
- " Show a summary of all tags whose data contains the given strings\n"
- " show <pkg> Call apt-cache show <pkg>, but add tag informations to the output.\n"
- " related <pkg1[,pkg2[,pkg2,[...]]]>\n"
- " Show packages related to the specified ones.\n"
- " cat Output the full package tag database\n"
- " search [-v] <tag expression>\n"
- " Output the names and description of the packages that match\n"
- " the given tag expression\n"
- " grep [-v] [-q] <tag expression>\n"
- " Output the lines of the full package tag database that match\n"
- " the given tag expression\n"
- " install [-v] [-q] <tag expression>\n"
- " apt-get install the packages that match the given tag expression\n"
- " mkpatch [filename]\n"
- " Create a tag patch between the current tag database and the tag\n"
- " collection [filename]\n"
- " maintainers Create a tagged collection of maintainers and the tags of the\n"
- " packages they maintain\n"
- " tag [add <package> <tags...>\n"
- " tag [rm <package> <tags...>\n"
- " tag [ls <package>\n"
- " View and edit the tags for a package\n"
- " submit [patch]\n"
- " Mail the given patch file to the central tag repository.\n"
- " If [patch] is omitted, mail the local tag modifications.\n"
- " todo Print a list of the installed packages that are not yet tagged\n"
- " score Score uninstalled packages according to how often their tags\n"
- " appear in the packages that are installed already\n"
- " facetcoll Print the tagged collection where each package is tagged with\n"
- " its facets only\n"
- " stats Print statistics about Debtags\n"
- " todoreport Print a report of packages needing work\n"
- " ssearch <word [word1 [+tag [-tag1 ...]]]>\n"
- " Perform a keyword search integrated with related packages.\n"
- " A + prefix indicates a wanted tag. A - prefix indicates\n"
- " an unwanted tag. Other words indicate keywords to search.\n"
- " Remember to use '--' before unwanted tags to avoid to have\n"
- " them interpreted as commandline switches.\n");
-
-
- /*
- opts.add("hierarchy", 's', "smart-hierarchy", "build a smart hierarchy");
- opts.add("implications", 'm', "show-implications", "output a list of tag implications");
- opts.add("copy", 'c', "copy", "output the collection");
- opts.add("diff", 'd', "diff", "output a tag patch file with the differences between two files (requires two file arguments)");
- */
-
- //opts.add("expanded", 'x', "expanded-output", "produce full (and redundant) output data instead of compact");
- opts.add("groupitems", 'g', "group-items", "group items with the same tagset in the output collection");
- opts.add("distance", 'd', "distance", "set the maximum distance to use for the \"related\" command (defaults to 0)", "num");
-
- opts.add("invert-match", 'v', "invert-match", "invert the sense of matching, to select non-matching lines");
- opts.add("quiet", 'q', "quiet", "do not write anything to standard output, but exit with 0 if any match is found");
- opts.add("local", 0, "local", "do not download files when performing an update");
-
- opts.add("verbose", 'V', "verbose", "enable verbose output");
- opts.add("debug", 0, "debug", "enable debugging output (including verbose output)");
-
- opts.addCommand("update", (int)UPDATE);
- opts.addCommand("check", (int)CHECK);
- opts.addCommand("selfcheck", (int)SELFCHECK);
- opts.addCommand("tagcat", (int)TAGCAT);
- opts.addCommand("tagshow", (int)TAGSHOW);
- opts.addCommand("tagsearch", (int)TAGSEARCH);
- opts.addCommand("show", (int)SHOW);
- opts.addCommand("related", (int)RELATED);
- opts.addCommand("cat", (int)CAT);
- opts.addCommand("search", (int)SEARCH);
- opts.addCommand("grep", (int)GREP);
- opts.addCommand("install", (int)INSTALL);
- opts.addCommand("mkpatch", (int)MKPATCH);
- opts.addCommand("maintainers", (int)MAINTAINERS);
- opts.addCommand("tag", (int)TAG);
- opts.addCommand("submit", (int)SUBMIT);
- opts.addCommand("todo", (int)TODO);
- opts.addCommand("score", (int)SCORE);
- opts.addCommand("facetcoll", (int)FACETCOLL);
- opts.addCommand("stats", (int)STATS);
- opts.addCommand("todoreport", (int)TODOREPORT);
- opts.addCommand("ssearch", (int)SMARTSEARCH);
+ Searcher searcher(debtags, printer.get());
+ string expression = opts.next();
- // Process the commandline
- valid_command cmd = (valid_command)opts.parse(argc, argv);
+ int matched =
+ searcher.output(expression, opts.matchGroup.invert->boolValue());
- CommandlineArgs args(argc, argv);
+ return matched > 0 ? 0 : 1;
+ }
+ // install [-v] [-q] <tag expression>
+ // apt-get install the packages that match the given tag expression
+ else if (opts.lastCommand() == &opts.install)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+ Installer installer;
- if (opts.get("verbose").defined())
- ::Environment::get().verbose(true);
+ Searcher searcher(debtags, &installer);
+ string expression = opts.next();
- if (opts.get("debug").defined())
- ::Environment::get().debug(true);
+ searcher.output(expression, opts.matchGroup.invert->boolValue());
- /*
- if (cmd != UPDATE && cmd != CAT && cmd != GREP && cmd != INSTALL && cmd != TAGSHOW)
- Debtags::Environment::init(false);
- */
-
- // Perform the correct operation
- switch (cmd)
+ return 1;
+ }
+ // tagcat
+ // Output the entire tag vocabulary
+ else if (opts.lastCommand() == &opts.tagcat)
{
- case SELFCHECK:
- {
- debtagsInit();
- component::Tags& voc = Global::get().tags();
-
- // ensure that all facets are readable
- FacetSet facets = voc.facets();
- for (FacetSet::const_iterator i = facets.begin(); i != facets.end(); i++)
- {
- i->name(string("foo"));
- i->shortDescription(string("foo"));
- i->longDescription(string("foo"));
- i->tags();
- }
+ debtagsInit();
+ wantTagDatabase();
- // ensure that all tags are readable
- TagSet tags = voc.tags();
- for (TagSet::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"));
- }
+ component::Tags& voc = Global::get().tags();
- return 0;
- }
- // Output the full package tag database
- case CAT:
+ OpSet<Facet> facets = voc.facets();
+ for (OpSet<Facet>::const_iterator i = facets.begin();
+ i != facets.end(); i++)
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- auto_ptr< Printer<Package, Tag> > printer;
-
- if (opts.get("groupitems").defined())
- printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
- else
- printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
+ printVocabularyItem(*i);
- Searcher searcher(debtags, printer.get());
- searcher.output();
-
- return 0;
+ OpSet<Tag> tags = i->tags();
+ for (OpSet<Tag>::const_iterator j = tags.begin();
+ j != tags.end(); j++)
+ printVocabularyItem(*j);
}
+ return 0;
+ }
+ // tagshow <tag>
+ // Show the vocabulary informations about a tag
+ else if (opts.lastCommand() == &opts.tagshow)
+ {
+ debtagsInit();
+ wantTagDatabase();
+ string tag = opts.next();
- // search [-v] <tag expression>\n"
- // Output the names and description of the packages that match\n"
- // the given tag expression\n"
- case SEARCH:
+ Tag t = Global::get().tags().tagByName(tag);
+ if (!t)
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- APTPrinter printer;
- Searcher searcher(debtags, &printer);
- string expression = args.next();
-
- int matched =
- searcher.output(expression, opts.get("invert-match").defined());
-
- return matched > 0 ? 0 : 1;
+ verbose("Tag `%.*s' was not found in tag vocabulary\n", PFSTR(tag));
+ return 1;
}
-
-
- // grep [-v] [-q] <tag expression>
- // Output the lines of the full package tag database that match the
- // given tag expression
- case GREP:
+ else
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- auto_ptr< Printer<Package, Tag> > printer;
-
- if (opts.get("quiet").defined())
- printer = auto_ptr< Printer<Package, Tag> >(new NullPrinter);
- if (opts.get("groupitems").defined())
- printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
- else
- printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
-
- Searcher searcher(debtags, printer.get());
- string expression = args.next();
+ printVocabularyItem(t);
+ return 0;
+ }
+ }
+ // tagsearch <pattern [pattern [pattern [...]]]>
+ // Show a summary of all tags matching the given patterns
+ else if (opts.lastCommand() == &opts.tagsearch)
+ {
+ debtagsInit();
+ wantTagDatabase();
- int matched =
- searcher.output(expression, opts.get("invert-match").defined());
+ SubstringTagMatcher match;
- return matched > 0 ? 0 : 1;
+ // Get the patterns to be matched
+ bool empty;
+ while (opts.hasNext())
+ {
+ string pattern = opts.next();
+ match.add(pattern);
+ empty = false;
}
- // install [-v] [-q] <tag expression>
- // apt-get install the packages that match the given tag expression
- case INSTALL:
+ if (empty)
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- Installer installer;
-
- Searcher searcher(debtags, &installer);
- string expression = args.next();
-
- searcher.output(expression, opts.get("invert-match").defined());
-
+ error("No patterns given in commandline\n");
return 1;
}
- // tagcat
- // Output the entire tag vocabulary
- case TAGCAT:
- {
- debtagsInit();
- wantTagDatabase();
+ component::Tags& voc = Global::get().tags();
- component::Tags& voc = Global::get().tags();
+ int matched = 0;
- OpSet<Facet> facets = voc.facets();
- for (OpSet<Facet>::const_iterator i = facets.begin();
- i != facets.end(); i++)
- {
- printVocabularyItem(*i);
-
- OpSet<Tag> tags = i->tags();
- for (OpSet<Tag>::const_iterator j = tags.begin();
- j != tags.end(); j++)
- printVocabularyItem(*j);
- }
- return 0;
- }
- // tagshow <tag>
- // Show the vocabulary informations about a tag
- case TAGSHOW:
+ OpSet<Facet> facets = voc.facets();
+ for (OpSet<Facet>::const_iterator i = facets.begin();
+ i != facets.end(); i++)
{
- debtagsInit();
- wantTagDatabase();
- string tag = args.next();
-
- Tag t = Global::get().tags().tagByName(tag);
- if (!t)
+ if (match(*i))
{
- verbose("Tag `%.*s' was not found in tag vocabulary\n", PFSTR(tag));
- return 1;
- }
- else
- {
- printVocabularyItem(t);
- return 0;
+ matched++;
+ printShortVocabularyItem(*i);
}
- }
- // tagsearch <pattern [pattern [pattern [...]]]>
- // Show a summary of all tags matching the given patterns
- case TAGSEARCH:
- {
- debtagsInit();
- wantTagDatabase();
- SubstringTagMatcher match;
-
- // Get the patterns to be matched
- bool empty;
- while (args.hasNext())
- {
- string pattern = args.next();
- match.add(pattern);
- empty = false;
- }
-
- if (empty)
- {
- error("No patterns given in commandline\n");
- return 1;
- }
-
- component::Tags& voc = Global::get().tags();
-
- int matched = 0;
-
- OpSet<Facet> facets = voc.facets();
- for (OpSet<Facet>::const_iterator i = facets.begin();
- i != facets.end(); i++)
- {
- if (match(*i))
+ OpSet<Tag> tags = i->tags();
+ for (OpSet<Tag>::const_iterator j = tags.begin();
+ j != tags.end(); j++)
+ if (match(*j))
{
matched++;
- printShortVocabularyItem(*i);
+ printShortVocabularyItem(*j);
}
+ }
- OpSet<Tag> tags = i->tags();
- for (OpSet<Tag>::const_iterator j = tags.begin();
- j != tags.end(); j++)
- if (match(*j))
- {
- matched++;
- printShortVocabularyItem(*j);
- }
- }
+ return matched > 0 ? 0 : 1;
+ }
+ // show <pkg>
+ // Call apt-cache show <pkg>, but add tag informations to the output.\n"
+ else if (opts.lastCommand() == &opts.show)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- return matched > 0 ? 0 : 1;
- }
- // show <pkg>
- // Call apt-cache show <pkg>, but add tag informations to the output.\n"
- case SHOW:
+ while (opts.hasNext())
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ string name = opts.next();
- while (args.hasNext())
+ entity::Package pkg = packageByName(name);
+ if (pkg.valid())
{
- string name = args.next();
-
- entity::Package pkg = packageByName(name);
- if (pkg.valid())
+ cout << pkg.candidateVersion().completeRecord() << endl;
+ cout << "Tags: ";
+ OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
+ for (OpSet<Tag>::const_iterator i = ts.begin();
+ i != ts.end(); i++)
+ if (i == ts.begin())
+ cout << i->fullname();
+ else
+ cout << ", " + i->fullname();
+ cout << endl;
+ return 0;
+ } else {
+ verbose("Package %.*s not found", PFSTR(name));
+ return 1;
+ }
+ }
+ }
+ // related <pkg1[,pkg2[,pkg2,[...]]]>
+ // Show packages related to the specified ones
+ else if (opts.lastCommand() == &opts.related)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+
+ int maxdist = 0;
+ if (opts.related.distance->boolValue())
+ maxdist = opts.related.distance->intValue();
+ string pkg = opts.next();
+
+ // Split the items on commas
+ string splititem;
+ OpSet<entity::Package> splititems;
+ for (string::const_iterator c = pkg.begin(); c != pkg.end(); c++)
+ if (*c == ',')
+ {
+ entity::Package p = packageByName(splititem);
+ if (p.valid())
{
- cout << pkg.candidateVersion().completeRecord() << endl;
- cout << "Tags: ";
- OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
- for (OpSet<Tag>::const_iterator i = ts.begin();
- i != ts.end(); i++)
- if (i == ts.begin())
- cout << i->fullname();
- else
- cout << ", " + i->fullname();
- cout << endl;
- return 0;
+ splititems.insert(p);
} else {
- verbose("Package %.*s not found", PFSTR(name));
+ error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
return 1;
}
- }
+ splititem = string();
+ } else
+ splititem += *c;
+ entity::Package p = packageByName(splititem);
+ if (p.valid())
+ {
+ splititems.insert(p);
+ } else {
+ error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
+ return 1;
}
- // related <pkg1[,pkg2[,pkg2,[...]]]>
- // Show packages related to the specified ones
- case RELATED:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- int maxdist = 0;
- if (opts.get("distance").defined())
- maxdist = opts.get("distance").intVal();
- string pkg = args.next();
-
- // Split the items on commas
- string splititem;
- OpSet<entity::Package> splititems;
- for (string::const_iterator c = pkg.begin(); c != pkg.end(); c++)
- if (*c == ',')
- {
- entity::Package p = packageByName(splititem);
- if (p.valid())
- {
- splititems.insert(p);
- } else {
- error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
- return 1;
- }
- splititem = string();
- } else
- splititem += *c;
- entity::Package p = packageByName(splititem);
- if (p.valid())
- {
- splititems.insert(p);
- } else {
- error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
- return 1;
- }
+ // Get the tagset as the intersection of the tagsets of all input items
+ OpSet<entity::Package>::const_iterator i = splititems.begin();
+ OpSet<Tag> ts = debtags.tagdb().getTags(*i);
+ for (++i; i != splititems.end(); i++)
+ ts = ts ^ debtags.tagdb().getTags(*i);
- // Get the tagset as the intersection of the tagsets of all input items
- OpSet<entity::Package>::const_iterator i = splititems.begin();
- OpSet<Tag> ts = debtags.tagdb().getTags(*i);
- for (++i; i != splititems.end(); i++)
- ts = ts ^ debtags.tagdb().getTags(*i);
+ if (ts.empty())
+ {
+ if (splititems.size() > 1)
+ fprintf(stderr, "The packages %.*s are unrelated: cannot find a barycenter to start computing relationships from.\n", PFSTR(pkg));
+ else
+ fprintf(stderr, "The package %.*s has no tags attached.\n", PFSTR(pkg));
+ return 1;
+ }
- if (ts.empty())
- {
- if (splititems.size() > 1)
- fprintf(stderr, "The packages %.*s are unrelated: cannot find a barycenter to start computing relationships from.\n", PFSTR(pkg));
+ APTPrinter printer(splititems);
+ OpSet<entity::Package> related(debtags.tagdb().getRelatedItems(ts, maxdist));
+ printer.print(related);
+ printer.flush();
+
+ if (printer.count() > 50 && maxdist == 0 && isatty(1))
+ {
+ string tags;
+ for (OpSet<Tag>::const_iterator i = ts.begin();
+ i != ts.end(); i++)
+ if (i == ts.begin())
+ tags += i->fullname();
else
- fprintf(stderr, "The package %.*s has no tags attached.\n", PFSTR(pkg));
- return 1;
- }
-
- APTPrinter printer(splititems);
- OpSet<entity::Package> related(debtags.tagdb().getRelatedItems(ts, maxdist));
- printer.print(related);
- printer.flush();
-
- if (printer.count() > 50 && maxdist == 0 && isatty(1))
- {
- string tags;
- for (OpSet<Tag>::const_iterator i = ts.begin();
- i != ts.end(); i++)
- if (i == ts.begin())
- tags += i->fullname();
- else
- tags += "%2C" + i->fullname();
- feedback("\nIt seems that this set of packages lacks tag information that could help to better distinguish package similarities.\nYou can help providing better tagging: just point your browser to http://debian.vitavonni.de/packagebrowser/?tags=%.*s\n", PFSTR(tags));
- }
- return 0;
+ tags += "%2C" + i->fullname();
+ feedback("\nIt seems that this set of packages lacks tag information that could help to better distinguish package similarities.\nYou can help providing better tagging: just point your browser to http://debian.vitavonni.de/packagebrowser/?tags=%.*s\n", PFSTR(tags));
}
- // 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
- case CHECK:
- {
- debtagsInit();
- wantTagDatabase();
+ return 0;
+ }
+ // 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
+ else if (opts.lastCommand() == &opts.check)
+ {
+ debtagsInit();
+ wantTagDatabase();
- string file;
- if (args.hasNext())
- file = args.next();
- else
- file = utils::Path::tagdb();
+ string file;
+ if (opts.hasNext())
+ file = opts.next();
+ else
+ file = utils::Path::tagdb();
- TagcollChecker checker;
- readCollection(file, checker);
+ TagcollChecker checker;
+ readCollection(file, checker);
- if (checker.missingCount() > 0)
- {
- checker.report();
- return 1;
- }
- else
- return 0;
+ if (checker.missingCount() > 0)
+ {
+ checker.report();
+ return 1;
}
- // update
- // Updates the package tag database (requires root)
- case UPDATE:
+ else
+ return 0;
+ }
+ // update
+ // Updates the package tag database (requires root)
+ else if (opts.lastCommand() == &opts.update)
+ {
+ if (geteuid() != 0)
{
- if (geteuid() != 0)
- {
- throw ConsistencyCheckException("You must be root to update the system debtags database");
- }
- struct winsize ws;
- unsigned int ScreenWidth;
+ throw ConsistencyCheckException("You must be root to update the system debtags database");
+ }
+ struct winsize ws;
+ unsigned int ScreenWidth;
- if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
- ScreenWidth = ws.ws_col - 1;
+ if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
+ ScreenWidth = ws.ws_col - 1;
+
+ AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
+ //Debtags::Environment::get().updateDebtagsDatabase(&Stat);
+ mode_t prev_umask = umask(022);
+ //debtags::updateDatabase(&Stat);
+ if (!opts.update.local->boolValue())
+ debtags::fetchNewData(&Stat);
+ debtagsInit();
+ umask(prev_umask);
+ }
+ // mkpatch [filename]
+ // Create a tag patch between the current tag database and the tag
+ // collection [filename]
+ else if (opts.lastCommand() == &opts.diff)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
- //Debtags::Environment::get().updateDebtagsDatabase(&Stat);
- mode_t prev_umask = umask(022);
- //debtags::updateDatabase(&Stat);
- if (!opts.get("local").defined())
- debtags::fetchNewData(&Stat);
- debtagsInit();
- umask(prev_umask);
- break;
- }
- // mkpatch [filename]
- // Create a tag patch between the current tag database and the tag
- // collection [filename]
- case MKPATCH:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ string file = opts.next();
- string file = args.next();
+ InputMerger<entity::Package, Tag> coll;
+ readCollection(
+ Global::get().packagestringconverter(),
+ Global::get().tagstringconverter(),
+ file, coll);
+
+ PatchList<entity::Package, Tag> newpatches;
+ newpatches.addPatch(debtags.tagdb(), coll);
+
+ TextFormat<entity::Package, Tag>::outputPatch(
+ Global::get().packagestringconverter(),
+ Global::get().tagstringconverter(),
+ newpatches, stdout);
+ }
+ // maintainers
+ // Create a tagged collection of maintainers and the tags of the
+ // packages they maintain
+ else if (opts.lastCommand() == &opts.maintainers)
+ {
+ debtagsInit();
+ wantTagDatabase();
+
+ // Gather maintainer informations
+ InputMerger<string, Tag> maints;
+ for (component::Packages::iterator i = Global::get().packages().packagesBegin();
+ i != Global::get().packages().packagesEnd(); ++i)
+ {
+ if (!i->valid())
+ continue;
+ entity::Version v = i->candidateVersion();
+ if (!v.valid())
+ continue;
+ maints.consume(v.maintainer(), i->tags());
+ }
+ MaintPrinter printer;
+ maints.output(printer);
+ }
+ // tag
+ // tag [add <package> <tags...>\n"
+ // tag [rm <package> <tags...>\n"
+ // tag [ls <package>\n"
+ // View and edit the tags for a package\n");
+ else if (opts.lastCommand() == &opts.tag)
+ {
+ std::string cmd = opts.next();
- InputMerger<entity::Package, Tag> coll;
- readCollection(
- Global::get().packagestringconverter(),
- Global::get().tagstringconverter(),
- file, coll);
-
- PatchList<entity::Package, Tag> newpatches;
- newpatches.addPatch(debtags.tagdb(), coll);
-
- TextFormat<entity::Package, Tag>::outputPatch(
- Global::get().packagestringconverter(),
- Global::get().tagstringconverter(),
- newpatches, stdout);
- break;
- }
- // maintainers
- // Create a tagged collection of maintainers and the tags of the
- // packages they maintain
- case MAINTAINERS:
+ if (cmd == "add" || cmd == "rm")
{
- debtagsInit();
+ component::PackageTags& debtags = debtagsInit(true);
wantTagDatabase();
- // Gather maintainer informations
- InputMerger<string, Tag> maints;
- for (component::Packages::iterator i = Global::get().packages().packagesBegin();
- i != Global::get().packages().packagesEnd(); ++i)
- {
- if (!i->valid())
- continue;
- entity::Version v = i->candidateVersion();
- if (!v.valid())
- continue;
- maints.consume(v.maintainer(), i->tags());
- }
- MaintPrinter printer;
- maints.output(printer);
- break;
- }
- // tag
- // tag [add <package> <tags...>\n"
- // tag [rm <package> <tags...>\n"
- // tag [ls <package>\n"
- // View and edit the tags for a package\n");
- case TAG:
- {
- std::string cmd = args.next();
+ string name = opts.next();
- if (cmd == "add" || cmd == "rm")
+ entity::Package pkg = packageByName(name);
+ if (!pkg.valid())
{
- component::PackageTags& debtags = debtagsInit(true);
- wantTagDatabase();
-
- string name = args.next();
-
- entity::Package pkg = packageByName(name);
- if (!pkg.valid())
- {
- error("Package %.*s not found\n", PFSTR(name));
- return 1;
- }
+ error("Package %.*s not found\n", PFSTR(name));
+ return 1;
+ }
- OpSet<Tag> tagset;
+ OpSet<Tag> tagset;
- while (args.hasNext())
- {
- string tag = args.next();
- Tag t = Global::get().tags().tagByName(tag);
- if (t)
- tagset += t;
- else
- error("Tag `%.*s' not found: ignored\n", PFSTR(tag));
- }
-
- if (!tagset.empty())
- {
- PatchList<entity::Package, Tag> change;
- if (cmd == "add")
- change.addPatch(Patch<entity::Package, Tag>(pkg, tagset, OpSet<Tag>()));
- else
- change.addPatch(Patch<entity::Package, Tag>(pkg, OpSet<Tag>(), tagset));
- debtags.tagdb().applyChange(change);
- debtags.savePatch();
- } else
- verbose("No tags to add\n");
- }
- else if (cmd == "ls")
+ while (opts.hasNext())
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
-
- string name = args.next();
- entity::Package pkg = packageByName(name);
- if (pkg.valid())
- {
- OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
- for (OpSet<Tag>::const_iterator i = ts.begin();
- i != ts.end(); i++)
- printf("%.*s\n", PFSTR(i->fullname()));
- return 0;
- } else {
- verbose("Package %.*s not found", PFSTR(name));
- return 1;
- }
+ string tag = opts.next();
+ Tag t = Global::get().tags().tagByName(tag);
+ if (t)
+ tagset += t;
+ else
+ error("Tag `%.*s' not found: ignored\n", PFSTR(tag));
}
- else
- throw ConsistencyCheckException("command " + cmd + " is not valid working with tags");
- break;
+
+ if (!tagset.empty())
+ {
+ PatchList<entity::Package, Tag> change;
+ if (cmd == "add")
+ change.addPatch(Patch<entity::Package, Tag>(pkg, tagset, OpSet<Tag>()));
+ else
+ change.addPatch(Patch<entity::Package, Tag>(pkg, OpSet<Tag>(), tagset));
+ debtags.tagdb().applyChange(change);
+ debtags.savePatch();
+ } else
+ verbose("No tags to add\n");
}
- // submit
- // Mail the local updates to the tag database to the central tag
- // repository
- case SUBMIT:
+ else if (cmd == "ls")
{
component::PackageTags& debtags = debtagsInit();
wantTagDatabase();
- if (args.hasNext())
+ string name = opts.next();
+ entity::Package pkg = packageByName(name);
+ if (pkg.valid())
{
- StdioParserInput in(args.next());
- PatchList<entity::Package, Tag> patch =
- TextFormat<entity::Package, Tag>::parsePatch(
- Global::get().packagestringconverter(),
- Global::get().tagstringconverter(),
- in);
- debtags.sendPatch(patch);
+ OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
+ for (OpSet<Tag>::const_iterator i = ts.begin();
+ i != ts.end(); i++)
+ printf("%.*s\n", PFSTR(i->fullname()));
+ return 0;
+ } else {
+ verbose("Package %.*s not found", PFSTR(name));
+ return 1;
}
- else
- debtags.sendPatch();
-
- break;
}
- // todo
- // Print a list of the installed packages that are not yet tagged
- case TODO:
+ else
+ throw ConsistencyCheckException("command " + cmd + " is not valid working with tags");
+ }
+ // submit
+ // Mail the local updates to the tag database to the central tag
+ // repository
+ else if (opts.lastCommand() == &opts.submit)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+
+ if (opts.hasNext())
{
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ StdioParserInput in(opts.next());
+ PatchList<entity::Package, Tag> patch =
+ TextFormat<entity::Package, Tag>::parsePatch(
+ Global::get().packagestringconverter(),
+ Global::get().tagstringconverter(),
+ in);
+ debtags.sendPatch(patch);
+ }
+ else
+ debtags.sendPatch();
- // Write the package names to stdout
- APTPrinter printer;
+ }
+ // todo
+ // Print a list of the installed packages that are not yet tagged
+ else if (opts.lastCommand() == &opts.todo)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- // Filter to select the right packages
- TODOFilter filter(printer);
+ // Write the package names to stdout
+ APTPrinter printer;
- debtags.outputPatched(filter);
+ // Filter to select the right packages
+ TODOFilter filter(printer);
- printer.flush();
+ debtags.outputPatched(filter);
- break;
- }
- // score
- // Score uninstalled packages according to how often their tags
- // appear in the packages that are installed already
- case SCORE:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ printer.flush();
- // Compute tag scores
- TagsScorer tscorer;
- debtags.outputPatched(tscorer);
-
- // Compute package scores
- PackageScorer pscorer(tscorer);
- debtags.outputPatched(pscorer);
-
- // Print the results
- for (PackageScorer::const_iterator i = pscorer.begin();
- i != pscorer.end(); i++)
- printf("%d %.*s - %.*s\n", i->first,
- PFSTR(i->second.name()), PFSTR(i->second.shortDescription(string("(short description not available)"))));
- break;
- }
- // facetcoll
- // Print the tagged collection where each package is tagged with
- // its facets only
- case FACETCOLL:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ }
+ // score
+ // Score uninstalled packages according to how often their tags
+ // appear in the packages that are installed already
+ else if (opts.lastCommand() == &opts.score)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- FacetcollPrinter<entity::Package> printer;
- TagToFacet<entity::Package> tagToFacet(printer);
- debtags.outputPatched(tagToFacet);
- break;
- }
- // stats
- // Print statistics about Debtags
- case STATS:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
+ // Compute tag scores
+ TagsScorer tscorer;
+ debtags.outputPatched(tscorer);
+
+ // Compute package scores
+ PackageScorer pscorer(tscorer);
+ debtags.outputPatched(pscorer);
+
+ // Print the results
+ for (PackageScorer::const_iterator i = pscorer.begin();
+ i != pscorer.end(); i++)
+ printf("%d %.*s - %.*s\n", i->first,
+ PFSTR(i->second.name()), PFSTR(i->second.shortDescription(string("(short description not available)"))));
+ }
+ // facetcoll
+ // Print the tagged collection where each package is tagged with
+ // its facets only
+ else if (opts.lastCommand() == &opts.facetcoll)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- int pkgCount = Global::get().packages().packageCount();
- printf("Total count of packages: %d\n", pkgCount);
+ FacetcollPrinter<entity::Package> printer;
+ TagToFacet<entity::Package> tagToFacet(printer);
+ debtags.outputPatched(tagToFacet);
+ }
+ // stats
+ // Print statistics about Debtags
+ else if (opts.lastCommand() == &opts.stats)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
- StatsCollector stats;
- debtags.outputPatched(stats);
+ int pkgCount = Global::get().packages().packageCount();
+ printf("Total count of packages: %d\n", pkgCount);
- printf("Total count of packages (according to APT): %d\n", pkgCount);
- printf("Total count of packages (according to Debtags): %d\n", stats.get_seen());
+ StatsCollector stats;
+ debtags.outputPatched(stats);
- const component::Tags& voc = Global::get().tags();
- printf("Number of facets: %d\n", voc.facets().size());
- printf("Number of tags: %d\n", voc.tags().size());
-
- // Copied from Debtags class: compute the toplevel facets
- // TODO: use Debtags instead of Environment throughout all Debtags
- CardinalityStore<entity::Package, Facet> coll;
- TagToFacet<entity::Package> tagStripper(coll);
- debtags.outputPatched(tagStripper);
- Facet f;
- SmartHierarchyNode<entity::Package, Facet> node(f, coll, 0);
- printf("Number of automatically computed toplevel facets: %d\n", node.size());
-
- printf("Number of packages with special::completely-tagged tags: %d (%.1f%%)\n",
- stats.get_complete(), (float)stats.get_complete()*100/stats.get_seen());
- printf("Number of packages with tags, but no special::not-yet-tagged tags: %d (%.1f%%)\n",
- stats.get_tagged(), (float)stats.get_tagged()*100/stats.get_seen());
- printf("Number of packages with special::not-yet-tagged tags: %d (%.1f%%)\n",
- stats.get_nyt(), (float)stats.get_nyt()*100/stats.get_seen());
- printf("Number of packages with only special::not-yet-tagged tags: %d (%.1f%%)\n",
- stats.get_onlynyt(), (float)stats.get_onlynyt()*100/stats.get_seen());
- printf("Number of packages with no tags: %d (%.1f%%)\n",
- stats.get_notags(), (float)stats.get_notags()*100/stats.get_seen());
-
- break;
- }
- // todoreport
- // Print a report of packages needing work
- case TODOREPORT:
- {
- debtagsInit();
- wantTagDatabase();
+ printf("Total count of packages (according to APT): %d\n", pkgCount);
+ printf("Total count of packages (according to Debtags): %d\n", stats.get_seen());
+
+ const component::Tags& voc = Global::get().tags();
+ printf("Number of facets: %d\n", voc.facets().size());
+ printf("Number of tags: %d\n", voc.tags().size());
+
+ // Copied from Debtags class: compute the toplevel facets
+ // TODO: use Debtags instead of Environment throughout all Debtags
+ CardinalityStore<entity::Package, Facet> coll;
+ TagToFacet<entity::Package> tagStripper(coll);
+ debtags.outputPatched(tagStripper);
+ Facet f;
+ SmartHierarchyNode<entity::Package, Facet> node(f, coll, 0);
+ printf("Number of automatically computed toplevel facets: %d\n", node.size());
+
+ printf("Number of packages with special::completely-tagged tags: %d (%.1f%%)\n",
+ stats.get_complete(), (float)stats.get_complete()*100/stats.get_seen());
+ printf("Number of packages with tags, but no special::not-yet-tagged tags: %d (%.1f%%)\n",
+ stats.get_tagged(), (float)stats.get_tagged()*100/stats.get_seen());
+ printf("Number of packages with special::not-yet-tagged tags: %d (%.1f%%)\n",
+ stats.get_nyt(), (float)stats.get_nyt()*100/stats.get_seen());
+ printf("Number of packages with only special::not-yet-tagged tags: %d (%.1f%%)\n",
+ stats.get_onlynyt(), (float)stats.get_onlynyt()*100/stats.get_seen());
+ printf("Number of packages with no tags: %d (%.1f%%)\n",
+ stats.get_notags(), (float)stats.get_notags()*100/stats.get_seen());
- unsigned int itemsPerGroup = 0;
- if (args.hasNext())
- itemsPerGroup = atoi(args.next().c_str());
-
- ReportMaker rm(itemsPerGroup);
- rm.printReport();
-
- break;
- }
- // ssearch <word [word1 [word2 ...]]>
- // Perform a keyword search integrated with related packages
- case SMARTSEARCH:
- {
- component::PackageTags& debtags = debtagsInit();
- wantTagDatabase();
- APTPrinter printer;
- SmartSearcher smart(debtags, &printer);
- Searcher searcher(debtags, &smart);
- predicate::Predicate<Package> p = predicate::True<Package>();
- //predicate::Factory<Package>::description(args.next());
- while (args.hasNext())
- {
- string arg = args.next();
- switch (arg[0])
- {
- case '+':
- p = p and predicate::Factory<Package>::tag(
- Global::get().tags().tagByName(arg.substr(1)));
- break;
- case '-':
- p = p and not predicate::Factory<Package>::tag(
- Global::get().tags().tagByName(arg.substr(1)));
- break;
- default:
- p = p and predicate::Factory<Package>::description(arg);
- break;
- }
- }
+ }
+ // todoreport
+ // Print a report of packages needing work
+ else if (opts.lastCommand() == &opts.todoreport)
+ {
+ debtagsInit();
+ wantTagDatabase();
- int step1 = searcher.output(p);
- int step2 = smart.outputRelated();
+ unsigned int itemsPerGroup = 0;
+ if (opts.hasNext())
+ itemsPerGroup = atoi(opts.next().c_str());
- cout << step1 << " normal matches plus " << step2 << " related packages." << endl;
- OpSet<Tag> topTags = smart.topTags();
- cout << "Top tags were: " << topTags << endl;
+ ReportMaker rm(itemsPerGroup);
+ rm.printReport();
- return step1 + step2 > 0 ? 0 : 1;
+ }
+ // ssearch <word [word1 [word2 ...]]>
+ // Perform a keyword search integrated with related packages
+ else if (opts.lastCommand() == &opts.smartsearch)
+ {
+ component::PackageTags& debtags = debtagsInit();
+ wantTagDatabase();
+ APTPrinter printer;
+ SmartSearcher smart(debtags, &printer);
+ Searcher searcher(debtags, &smart);
+ predicate::Predicate<Package> p = predicate::True<Package>();
+ //predicate::Factory<Package>::description(opts.next());
+ while (opts.hasNext())
+ {
+ string arg = opts.next();
+ switch (arg[0])
+ {
+ case '+':
+ p = p and predicate::Factory<Package>::tag(
+ Global::get().tags().tagByName(arg.substr(1)));
+ break;
+ case '-':
+ p = p and not predicate::Factory<Package>::tag(
+ Global::get().tags().tagByName(arg.substr(1)));
+ break;
+ default:
+ p = p and predicate::Factory<Package>::description(arg);
+ break;
+ }
}
-
+ int step1 = searcher.output(p);
+ int step2 = smart.outputRelated();
+
+ cout << step1 << " normal matches plus " << step2 << " related packages." << endl;
+ OpSet<Tag> topTags = smart.topTags();
+ cout << "Top tags were: " << topTags << endl;
+
+ return step1 + step2 > 0 ? 0 : 1;
}
+ else
+ throw commandline::BadOption(string("unhandled command ") +
+ (opts.lastCommand() ? opts.lastCommand()->name() : "(null)"));
return 0;
- }
- catch (Exception& e)
- {
+ } catch (commandline::BadOption& e) {
+ cerr << e.desc() << endl;
+ commandline::Help help(APPNAME, VERSION);
+ if (opts.lastCommand())
+ {
+ help.outputHelp(cerr, *opts.lastCommand());
+ } else {
+ help.outputHelp(cerr, opts);
+ }
+ exit(1);
+ } catch (Exception& e) {
fatal_error("%s: %.*s\n", e.type(), PFSTR(e.desc()));
return 1;
}
More information about the Debtags-commits
mailing list