[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