[Debtags-commits] [svn] r1636 - tagcoll/trunk/tools
Enrico Zini
enrico at costa.debian.org
Sat Mar 4 18:16:30 UTC 2006
Author: enrico
Date: Sat Mar 4 18:16:28 2006
New Revision: 1636
Modified:
tagcoll/trunk/tools/manpage.cc
tagcoll/trunk/tools/tagidx.cc
Log:
Converted tagidx to the new commandline parser
Modified: tagcoll/trunk/tools/manpage.cc
==============================================================================
--- tagcoll/trunk/tools/manpage.cc (original)
+++ tagcoll/trunk/tools/manpage.cc Sat Mar 4 18:16:28 2006
@@ -54,7 +54,7 @@
}
else if (cmd == "tagidx")
{
- commandline::TagcollOptions opts;
+ commandline::TagidxOptions opts;
commandline::Manpage help("tagidx", VERSION);
if (!hooks.empty())
help.readHooks(hooks);
Modified: tagcoll/trunk/tools/tagidx.cc
==============================================================================
--- tagcoll/trunk/tools/tagidx.cc (original)
+++ tagcoll/trunk/tools/tagidx.cc Sat Mar 4 18:16:28 2006
@@ -34,7 +34,8 @@
#define APPNAME "tagidx"
-#include "CommandlineParser.h"
+#include "TagidxOptions.h"
+
#include <tagcoll/BasicStringDiskIndex.h>
#include <tagcoll/ItemGrouper.h>
#include <tagcoll/Consumer.h>
@@ -451,92 +452,6 @@
};
#endif
-class CommandlineParserWithCommand : public CommandlineParser
-{
-protected:
- map<string, int> command_map;
-
-public:
- CommandlineParserWithCommand(const std::string& argv0,
- const std::string& cmdline_summary,
- const std::string& description) throw ()
- : CommandlineParser(argv0, cmdline_summary, description)
- {
- add("version", 0, "version", "print the program version, then exit");
- }
-
- void addCommand(const std::string name, int id) throw ()
- {
- command_map[name] = id;
- }
-
- int parse(int& argc, const char**& argv) throw ()
- {
- if (!CommandlineParser::parse(argc, argv))
- {
- printHelp();
- return false;
- }
- if (get("help").defined())
- {
- printHelp();
- exit(0);
- }
- if (get("version").defined())
- {
- printf("%s ver." VERSION "\n", APPNAME);
- exit(0);
- }
- if (argc == 1)
- {
- printHelp();
- exit(1);
- }
-
- string command_string = argv[1];
- map<string, int>::const_iterator cmap_i = command_map.find(command_string);
- if (cmap_i == command_map.end())
- {
- fprintf(stderr, "Invalid command: \"%.*s\"\n", PFSTR(command_string));
- printHelp();
- exit(1);
- }
-
- for (int i = 1; i < argc; i++)
- argv[i] = argv[i + 1];
- --argc;
-
- return cmap_i->second;
- }
-};
-
-class CommandlineArgs
-{
-protected:
- int argc;
- const char** argv;
- int _next;
-
-public:
- CommandlineArgs(int argc, const char* argv[]) throw () : argc(argc), argv(argv), _next(1) {}
-
- // Return true if there is another argument left in the list
- bool hasNext() const throw () { return argc >= _next + 1; }
-
- // Return the next argument in the list
- string next() throw ()
- {
- if (hasNext())
- {
- return argv[_next++];
- } else {
- return "-";
- }
- }
-};
-
-enum valid_command { CREATE, REMOVE, ADDPATCH, COMPACT, CAT /*, DIFF, RELATED, IMPLICATIONS, HIERARCHY, CLEANHIERARCHY, REVERSE, FINDSPECIALS, GREP, ITEMS */ };
-
#if 0
class Reader
{
@@ -637,9 +552,9 @@
};
#endif
-void output(CommandlineParserWithCommand& opts, ReadonlyCollection<string, string>& coll)
+void output(commandline::TagidxOptions& opts, ReadonlyCollection<string, string>& coll)
{
- if (opts.get("quiet").defined())
+ if (opts.outputGroup.quiet->boolValue())
{
Sink<string, string> sink;
coll.output(sink);
@@ -647,7 +562,7 @@
TrivialConverter<string, string> conv;
TextFormat<string, string> writer(conv, conv, stdout);
- if (opts.get("groupitems").defined())
+ if (opts.outputGroup.group->boolValue())
{
ItemGrouper<string, string> grouper;
coll.output(grouper);
@@ -657,10 +572,10 @@
}
}
-string indexname(CommandlineParserWithCommand& opts)
+string indexname(commandline::TagidxOptions& opts)
{
- if (opts.get("index").defined())
- return opts.get("index").stringVal();
+ if (opts.indexGroup.index->boolValue())
+ return opts.indexGroup.index->stringValue();
if (getenv("TAGIDX") != NULL)
return getenv("TAGIDX");
struct passwd* pw = getpwuid(getuid());
@@ -671,425 +586,140 @@
int main(int argc, const char* argv[])
{
+ commandline::TagidxOptions opts;
+
try {
- CommandlineParserWithCommand opts(APPNAME, "[options] [command] [file1|-] [file2|-]",
- "Access an indexed tagged collection\n\n"
- "Commands are:\n"
- " create create the index from a tagged collection\n"
- " remove deletes the disk index\n"
- " addpatch [file1 [file2 [...]]]\n"
- " installs the given files as patches to the collection\n"
- " compact merge the patches into the index (can cause race conditions if invoked\n"
- " concurrently with other tagidx accessing the same index)\n"
- " cat output the collection\n"
-/*
- " reverse \"reverse\" the collection, outputting one with items\n"
- " associated to tags\n"
- " diff output a tag patch file with the differences between two files\n"
- " related <item> print a list of items related to the given one\n"
- " implications compute a list of tag implications\n"
- " hierarchy build a smart hierarchy with the collection data\n"
- " cleanhierarchy build a cleaned smart hierarchy with the collection data\n"
- " findspecials generate a smart hierarchy and print, for each toplevel tag,\n"
- " what are the items that make it toplevel instead of going below\n"
- " another tag.\n"
- " grep <expr> output the collection of tags that match the given tag expression\n"
- " items output only the items of the input collection\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("index", 'I', "index", "directory where the index files are stored", "dir");
- opts.add("groupitems", 'g', "group-items", "group items with the same tagset in the output collection");
- opts.add("quiet", 'q', "quiet", "produce no output");
- opts.add("force", 'f', "force", "force overwrite");
-#if 0
- opts.add("derived", 'e', "derived-tags-from", "use an external list of derived tags", "file");
- opts.add("extimpl", 'i', "implications-from", "use an external list of implications", "file");
- opts.add("rename", 'r', "rename-from", "rename tags using the given mapping list", "file");
- opts.add("patch", 'p', "patch-with", "apply patches from the given tag patch file", "file");
-
- opts.add("expanded", 'x', "expanded-output", "produce full (and redundant) output data instead of compact");
- opts.add("distance", 'd', "distance", "set the maximum distance to use for the \"related\" command (defaults to 0)", "num");
- opts.add("flatten", 0, "flatten-threshold", "set the number of total items below which a branch is flattened when using the \"hierarchy\" command (defaults to 0, meaning \"don't flatten\")", "num");
- opts.add("filter", 'f', "filter", "filter out the tags with cardinality less than the given value (defaults to not filter; currently only works when building hierarchies)", "num");
- opts.add("untagged-tag", 0, "untagged-tag", "set item name to use for associating untagged items when using the \"reverse\" command. If not specified, untagged items are not included in the output.", "tag");
- opts.add("remove-unfaceted", 0, "remove-unfaceted", "while parsing, remove all tags with no facet part.");
- opts.add("remove-tags", 0, "remove-tags", "while parsing, remove all tags matching the given tag expression.", "expression");
+ opts.parse(argc, argv);
+ if (!opts.lastCommand())
+ throw commandline::BadOption("could not understand the command to execute");
- //opts.add("verbose", 'v', "verbose", "enable verbose output");
- //opts.add("debug", 0, "debug", "enable debugging output (including verbose output)");
-#endif
+ if (opts.helpGroup.help->boolValue())
+ {
+ // 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);
+ }
+ else if (opts.helpGroup.version->boolValue())
+ {
+ // Print the program version
+ commandline::Help help(APPNAME, VERSION);
+ help.outputVersion(cout);
+ }
+ else if (opts.lastCommand() == &opts.generic)
+ {
+ commandline::Help help(APPNAME, VERSION);
+ help.outputHelp(cout, opts);
+ }
+ else if (opts.lastCommand() == &opts.help)
+ {
+ commandline::Help help(APPNAME, VERSION);
+ commandline::OptionParser* o = 0;
+ if (opts.hasNext())
+ o = opts.command(opts.next());
- opts.addCommand("create", (int)CREATE);
- opts.addCommand("cat", (int)CAT);
- opts.addCommand("remove", (int)REMOVE);
- opts.addCommand("addpatch", (int)ADDPATCH);
- opts.addCommand("compact", (int)COMPACT);
-#if 0
- opts.addCommand("copy", (int)COPY);
- opts.addCommand("reverse", (int)REVERSE);
- opts.addCommand("diff", (int)DIFF);
- opts.addCommand("related", (int)RELATED);
- opts.addCommand("implications", (int)IMPLICATIONS);
- opts.addCommand("hierarchy", (int)HIERARCHY);
- opts.addCommand("cleanhierarchy", (int)CLEANHIERARCHY);
- opts.addCommand("findspecials", (int)FINDSPECIALS);
- opts.addCommand("grep", (int)GREP);
- opts.addCommand("items", (int)ITEMS);
-#endif
+ if (o)
+ // Help on a specific command
+ help.outputHelp(cout, *o);
+ else
+ // General help
+ help.outputHelp(cout, opts);
+ }
+ else if (opts.lastCommand() == &opts.create)
+ {
+ string fname = indexname(opts);
- // Process the commandline
- valid_command cmd = (valid_command)opts.parse(argc, argv);
+ Indexer indexer;
- CommandlineArgs args(argc, argv);
+ if (opts.hasNext())
+ while (opts.hasNext())
+ readCollection(opts.next(), indexer);
+ else
+ readCollection("-", indexer);
-#if 0
- Reader reader(opts, cmd);
-#endif
-
- // Perform the correct operation
- switch (cmd)
+ indexer.write(fname);
+ }
+ else if (opts.lastCommand() == &opts.remove)
{
- case CREATE:
- {
- string fname = indexname(opts);
-
- Indexer indexer;
-
- if (args.hasNext())
- while (args.hasNext())
- readCollection(args.next(), indexer);
- else
- readCollection("-", indexer);
-
- indexer.write(fname);
+ string fname = indexname(opts);
+ Index::remove(fname);
+ }
+ else if (opts.lastCommand() == &opts.addpatch)
+ {
+ string fname = indexname(opts);
+ Index idx(fname);
- break;
- }
- case ADDPATCH:
+ if (opts.hasNext())
{
- string fname = indexname(opts);
- Index idx(fname);
-
- if (args.hasNext())
+ while (opts.hasNext())
{
- while (args.hasNext())
+ string filename = opts.next();
+ size_t pos = filename.rfind('/');
+ string name = pos == string::npos ? filename : filename.substr(pos + 1);
+
+ PatchList<string, string> patch = readPatchFromFile(filename);
+ if (patch.size() > 0)
{
- string filename = args.next();
- size_t pos = filename.rfind('/');
- string name = pos == string::npos ? filename : filename.substr(pos + 1);
-
- PatchList<string, string> patch = readPatchFromFile(filename);
- if (patch.size() > 0)
- {
- idx.addPatch(patch, name, opts.get("force").defined());
- } else {
- cerr << "skipped empty patch file " << filename << endl;
- }
+ idx.addPatch(patch, name, opts.addpatch.force->boolValue());
+ } else {
+ cerr << "skipped empty patch file " << filename << endl;
}
- } else {
- TrivialConverter<string, string> conv;
- StdioParserInput input(stdin, "(stdin)");
- PatchList<string, string> patch = TextFormat<string, string>::parsePatch(conv, conv, input);
-
- addPatch(idx, patch);
}
+ } else {
+ TrivialConverter<string, string> conv;
+ StdioParserInput input(stdin, "(stdin)");
+ PatchList<string, string> patch = TextFormat<string, string>::parsePatch(conv, conv, input);
- break;
+ addPatch(idx, patch);
}
- case COMPACT:
- {
- string fname = indexname(opts);
-
- Indexer indexer;
-
- // Output the patched collection to the indexer
- {
- Index idx(fname);
- idx.output(indexer);
- }
+ }
+ else if (opts.lastCommand() == &opts.compact)
+ {
+ string fname = indexname(opts);
- // Delete the old index and patches
- Index::remove(fname);
-
- // Write the new index
- indexer.write(fname);
+ Indexer indexer;
- break;
- }
- case REMOVE:
- {
- string fname = indexname(opts);
- Index::remove(fname);
- break;
- }
- case CAT:
+ // Output the patched collection to the indexer
{
- string fname = indexname(opts);
Index idx(fname);
-
- output(opts, idx);
- break;
- }
-#if 0
- case IMPLICATIONS:
- {
- CardinalityStore<string, string> coll;
- reader.output(args, coll);
-
- Implications<string> newImpls;
-
- // Find tag implications
- OpSet<string> allTags = coll.getAllTags();
- for (OpSet<string>::const_iterator t = allTags.begin();
- t != allTags.end(); t++)
- {
- OpSet<string> implied = coll.getImpliedBy(*t);
- if (!implied.empty())
- newImpls.consume(*t, implied);
- }
-
- newImpls.pack();
-
- Converter<string, string> conv;
- TextFormat<string, string> output(conv, conv, stdout);
- if (opts.get("expanded").defined())
- newImpls.outputFull(output);
- else
- newImpls.output(output);
- break;
- }
- case HIERARCHY:
- {
- int flattenThreshold = 0;
- if (opts.get("flatten").defined())
- flattenThreshold = opts.get("flatten").intVal();
-
- CardinalityStore<string, string> coll;
- reader.output(args, coll);
-
- if (opts.get("filter").defined())
- coll.removeTagsWithCardinalityLessThan(opts.get("filter").intVal());
-
- // Default operation: build the smart hierarchy
- HierarchyNode<string, string>* root =
- new SmartHierarchyNode<string, string>("_top", coll, flattenThreshold);
- printNode(root, "/");
- break;
- }
- case CLEANHIERARCHY:
- {
- int flattenThreshold = 0;
- if (opts.get("flatten").defined())
- flattenThreshold = opts.get("flatten").intVal();
-
- CardinalityStore<string, string> coll;
- reader.output(args, coll);
-
- if (opts.get("filter").defined())
- coll.removeTagsWithCardinalityLessThan(opts.get("filter").intVal());
-
- // Default operation: build the smart hierarchy
- HierarchyNode<string, string>* root = new CleanSmartHierarchyNode<string, string>("_top", coll, flattenThreshold);
- printNode(root, "/");
- break;
- }
- case DIFF:
- {
- InputMerger<string, string> merger1;
- reader.output(args.next(), merger1);
-
- InputMerger<string, string> merger2;
- reader.output(args.next(), merger2);
-
- PatchList<string, string> newpatches;
- newpatches.addPatch(merger1, merger2);
-
- Converter<string, string> conv;
- TextFormat<string, string>::outputPatch(conv, conv, newpatches, stdout);
- break;
- }
- case RELATED:
- {
- string item = args.next();
- InputMerger<string, string> merger;
- reader.output(args, merger);
-
- int maxdist = 0;
- if (opts.get("distance").defined())
- maxdist = opts.get("distance").intVal();
-
- // Split the items on commas
- string splititem;
- set<string> splititems;
- for (string::const_iterator c = item.begin();
- c != item.end(); c++)
- if (*c == ',')
- {
- if (!merger.hasItem(splititem))
- {
- fprintf(stderr, "Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
- return 1;
- }
- splititems.insert(splititem);
- splititem = string();
- } else
- splititem += *c;
- if (!merger.hasItem(splititem))
- {
- fprintf(stderr, "Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
- return 1;
- }
- splititems.insert(splititem);
-
- // Get the tagset as the intersection of the tagsets of all input items
- set<string>::const_iterator i = splititems.begin();
- OpSet<string> ts = merger.getTags(*i);
- for (++i; i != splititems.end(); i++)
- ts = ts ^ merger.getTags(*i);
-
- if (ts.empty())
- {
- if (splititems.size() > 1)
- fprintf(stderr, "The items %.*s are unrelated: cannot find a barycenter to start computing relationships from.\n", PFSTR(item));
- else
- fprintf(stderr, "The items %.*s has no tags attached.\n", PFSTR(item));
- return 1;
- }
-
- // Build a full TagCollection
- CardinalityStore<string, string> coll;
- merger.output(coll);
-
- printItems(coll.getItemsExactMatch(ts));
-
- if (maxdist)
- {
- // Get the related tagsets
- list< OpSet<string> > rel = coll.getRelatedTagsets(ts, maxdist);
-
- // Print the output list
- for (list< OpSet<string> >::const_iterator i = rel.begin();
- i != rel.end(); i++)
- printItems(coll.getItemsExactMatch(*i));
- }
- break;
- }
- case REVERSE:
- {
- ItemGrouper<string, string> reverser;
- reader.output(args, reverser);
-
- /*
- if (opts.get("untagged-tag").defined())
- reverser.setUntaggedItemName(opts.get("untagged-tag").stringVal());
- */
-
- Converter<string, string> conv;
- TextFormat<string, string> writer(conv, conv, stdout);
- if (opts.get("groupitems").defined())
- {
- reverser.outputReversed(writer);
- } else
- // FIXME: we need a filter that does the opposite of ItemGrouper
- reverser.outputReversed(writer);
- break;
+ idx.output(indexer);
}
- case FINDSPECIALS:
- {
- int flattenThreshold = 0;
- if (opts.get("flatten").defined())
- flattenThreshold = opts.get("flatten").intVal();
-
- CardinalityStore<string, string> coll;
- reader.output(args, coll);
-
- if (opts.get("filter").defined())
- coll.removeTagsWithCardinalityLessThan(opts.get("filter").intVal());
-
- // Default operation: build the smart hierarchy
- SmartHierarchyNode<string, string> root("_top", coll, flattenThreshold);
-
- OpSet<string> seen;
- for (HierarchyNode<string, string>::iterator i = root.begin();
- i != root.end(); i++)
- {
- OpSet<string> items = getItems(*i);
- // Find the items in this branch that are not present in
- // any of the previous ones
- OpSet<string> newItems;
- if (!seen.empty())
- {
- for (OpSet<string>::const_iterator j = items.begin();
- j != items.end(); j++)
- {
- OpSet<string> tags = coll.getTags(*j) ^ seen;
- if (tags.empty())
- newItems += *j;
- }
-
- printf("%.*s: %d items, %d special items:\n",
- PFSTR((*i)->tag()), items.size(), newItems.size());
-
- int indent = (*i)->tag().size() + 2;
- for (OpSet<string>::const_iterator j = newItems.begin(); j != newItems.end(); j++)
- printf("%*s%.*s\n", indent, "", PFSTR(*j));
- }
-
- seen += (*i)->tag();
- }
+ // Delete the old index and patches
+ Index::remove(fname);
- break;
- }
- case GREP:
- {
- FilterItemsByExpression<string, string> filter(args.next());
+ // Write the new index
+ indexer.write(fname);
+ }
+ else if (opts.lastCommand() == &opts.cat)
+ {
+ string fname = indexname(opts);
+ Index idx(fname);
- Converter<string, string> conv;
- TextFormat<string, string> writer(conv, conv, stdout);
- if (opts.get("groupitems").defined())
- {
- ItemGrouper<string, string> grouper;
- filter.setConsumer(grouper);
- reader.output(args, filter);
- grouper.output(writer);
- } else {
- filter.setConsumer(writer);
- reader.output(args, filter);
- }
- break;
- }
- case ITEMS:
- {
- ItemsOnly<string, string> filter;
- Converter<string, string> conv;
- TextFormat<string, string> writer(conv, conv, stdout);
- if (opts.get("groupitems").defined())
- {
- ItemGrouper<string, string> grouper;
- filter.setConsumer(grouper);
- reader.output(args, filter);
- grouper.output(writer);
- } else {
- filter.setConsumer(writer);
- reader.output(args, filter);
- }
- break;
- }
-#endif
+ output(opts, idx);
}
+ 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("tagidx", VERSION);
+ if (opts.lastCommand())
+ {
+ help.outputHelp(cerr, *opts.lastCommand());
+ } else {
+ help.outputHelp(cerr, opts);
+ }
+ exit(1);
+ } catch (Exception& e)
{
fprintf(stderr, "%s: %.*s\n", e.type(), PFSTR(e.desc()));
return 1;
More information about the Debtags-commits
mailing list