1091
class CommandlineParserWithCommand : public CommandlineParser
1094
map<string, int> command_map;
1097
CommandlineParserWithCommand(const std::string& argv0,
1098
const std::string& cmdline_summary,
1099
const std::string& description) throw ()
1100
: CommandlineParser(argv0, cmdline_summary, description)
1102
add("version", 'V', "version", "print the program version, then exit");
1105
void addCommand(const std::string name, int id) throw ()
1107
command_map[name] = id;
1110
int parse(int& argc, const char**& argv) throw ()
1112
if (!CommandlineParser::parse(argc, argv))
1117
if (get("help").defined())
1122
if (get("version").defined())
1124
printf("%s ver." PACKAGE_VERSION "\n", APPNAME);
1133
string command_string = argv[1];
1134
map<string, int>::const_iterator cmap_i = command_map.find(command_string);
1135
if (cmap_i == command_map.end())
1137
fprintf(stderr, "Invalid command: \"%.*s\"\n", PFSTR(command_string));
1142
for (int i = 1; i < argc; i++)
1143
argv[i] = argv[i + 1];
1146
return cmap_i->second;
1150
class CommandlineArgs
1158
CommandlineArgs(int argc, const char* argv[]) throw () : argc(argc), argv(argv), _next(1) {}
1160
// Return true if there is another argument left in the list
1161
bool hasNext() const throw () { return argc >= _next + 1; }
1163
// Return the next argument in the list
1164
string next() throw ()
1168
return argv[_next++];
1175
enum valid_command { UPDATE, CHECK, TAGSHOW, TAGSEARCH, TAGCAT, SHOW, RELATED, CAT, SEARCH, GREP, INSTALL, MKPATCH, MAINTAINERS, TAG, SUBMIT, TODO, SCORE, FACETCOLL, STATS, TODOREPORT, SMARTSEARCH };
1177
1099
int main(int argc, const char* argv[])
1101
commandline::DebtagsOptions opts;
1180
1104
// Install the handler for unexpected exceptions
1181
1105
InstallUnexpected installUnexpected;
1183
CommandlineParserWithCommand opts(APPNAME, "[options] [command] [file1|-] [file2|-]",
1184
"Perform various operations on a tagged collection\n\n"
1186
" update Updates the package tag database (requires root)\n"
1187
" check <file> Check that all the tags in the given tagged collection are present\n"
1188
" in the tag vocabulary. Checks the main database if no file is\n"
1190
" tagcat <tag> Output the tag vocabulary\n"
1191
" tagshow <tag> Show the vocabulary informations about a tag\n"
1192
" tagsearch <string [string [string [...]]]>\n"
1193
" Show a summary of all tags whose data contains the given strings\n"
1194
" show <pkg> Call apt-cache show <pkg>, but add tag informations to the output.\n"
1195
" related <pkg1[,pkg2[,pkg2,[...]]]>\n"
1196
" Show packages related to the specified ones.\n"
1197
" cat Output the full package tag database\n"
1198
" search [-v] <tag expression>\n"
1199
" Output the names and description of the packages that match\n"
1200
" the given tag expression\n"
1201
" grep [-v] [-q] <tag expression>\n"
1202
" Output the lines of the full package tag database that match\n"
1203
" the given tag expression\n"
1204
" install [-v] [-q] <tag expression>\n"
1205
" apt-get install the packages that match the given tag expression\n"
1206
" mkpatch [filename]\n"
1207
" Create a tag patch between the current tag database and the tag\n"
1208
" collection [filename]\n"
1209
" maintainers Create a tagged collection of maintainers and the tags of the\n"
1210
" packages they maintain\n"
1211
" tag [add <package> <tags...>\n"
1212
" tag [rm <package> <tags...>\n"
1213
" tag [ls <package>\n"
1214
" View and edit the tags for a package\n"
1216
" Mail the given patch file to the central tag repository.\n"
1217
" If [patch] is omitted, mail the local tag modifications.\n"
1218
" todo Print a list of the installed packages that are not yet tagged\n"
1219
" score Score uninstalled packages according to how often their tags\n"
1220
" appear in the packages that are installed already\n"
1221
" facetcoll Print the tagged collection where each package is tagged with\n"
1222
" its facets only\n"
1223
" stats Print statistics about Debtags\n"
1224
" todoreport Print a report of packages needing work\n"
1225
" ssearch <word [word1 [+tag [-tag1 ...]]]>\n"
1226
" Perform a keyword search integrated with related packages.\n"
1227
" A + prefix indicates a wanted tag. A - prefix indicates\n"
1228
" an unwanted tag. Other words indicate keywords to search.\n"
1229
" Remember to use '--' before unwanted tags to avoid to have\n"
1230
" them interpreted as commandline switches.\n");
1234
opts.add("hierarchy", 's', "smart-hierarchy", "build a smart hierarchy");
1235
opts.add("implications", 'm', "show-implications", "output a list of tag implications");
1236
opts.add("copy", 'c', "copy", "output the collection");
1237
opts.add("diff", 'd', "diff", "output a tag patch file with the differences between two files (requires two file arguments)");
1240
//opts.add("expanded", 'x', "expanded-output", "produce full (and redundant) output data instead of compact");
1241
opts.add("groupitems", 'g', "group-items", "group items with the same tagset in the output collection");
1242
opts.add("distance", 'd', "distance", "set the maximum distance to use for the \"related\" command (defaults to 0)", "num");
1244
opts.add("invert-match", 'v', "invert-match", "invert the sense of matching, to select non-matching lines");
1245
opts.add("quiet", 'q', "quiet", "do not write anything to standard output, but exit with 0 if any match is found");
1247
opts.add("verbose", 'V', "verbose", "enable verbose output");
1248
opts.add("debug", 0, "debug", "enable debugging output (including verbose output)");
1250
opts.addCommand("update", (int)UPDATE);
1251
opts.addCommand("check", (int)CHECK);
1252
opts.addCommand("tagcat", (int)TAGCAT);
1253
opts.addCommand("tagshow", (int)TAGSHOW);
1254
opts.addCommand("tagsearch", (int)TAGSEARCH);
1255
opts.addCommand("show", (int)SHOW);
1256
opts.addCommand("related", (int)RELATED);
1257
opts.addCommand("cat", (int)CAT);
1258
opts.addCommand("search", (int)SEARCH);
1259
opts.addCommand("grep", (int)GREP);
1260
opts.addCommand("install", (int)INSTALL);
1261
opts.addCommand("mkpatch", (int)MKPATCH);
1262
opts.addCommand("maintainers", (int)MAINTAINERS);
1263
opts.addCommand("tag", (int)TAG);
1264
opts.addCommand("submit", (int)SUBMIT);
1265
opts.addCommand("todo", (int)TODO);
1266
opts.addCommand("score", (int)SCORE);
1267
opts.addCommand("facetcoll", (int)FACETCOLL);
1268
opts.addCommand("stats", (int)STATS);
1269
opts.addCommand("todoreport", (int)TODOREPORT);
1270
opts.addCommand("ssearch", (int)SMARTSEARCH);
1272
// Process the commandline
1273
valid_command cmd = (valid_command)opts.parse(argc, argv);
1275
CommandlineArgs args(argc, argv);
1277
if (opts.get("verbose").defined())
1107
opts.parse(argc, argv);
1108
if (!opts.lastCommand())
1109
throw commandline::BadOption("could not understand the command to execute");
1111
if (opts.outputGroup.verbose->boolValue())
1278
1112
::Environment::get().verbose(true);
1280
if (opts.get("debug").defined())
1114
if (opts.outputGroup.debug->boolValue())
1281
1115
::Environment::get().debug(true);
1284
if (cmd != UPDATE && cmd != CAT && cmd != GREP && cmd != INSTALL && cmd != TAGSHOW)
1285
Debtags::Environment::init(false);
1288
1117
// Perform the correct operation
1291
// Output the full package tag database
1294
component::PackageTags& debtags = debtagsInit();
1296
auto_ptr< Printer<Package, Tag> > printer;
1298
if (opts.get("groupitems").defined())
1299
printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
1301
printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
1303
Searcher searcher(debtags, printer.get());
1309
// search [-v] <tag expression>\n"
1310
// Output the names and description of the packages that match\n"
1311
// the given tag expression\n"
1314
component::PackageTags& debtags = debtagsInit();
1118
if (opts.helpGroup.help->boolValue())
1120
// Provide help as requested
1121
commandline::Help help(APPNAME, VERSION);
1122
commandline::OptionParser* o = opts.lastCommand();
1124
if (o && !o->name().empty())
1125
// Help on a specific command
1126
help.outputHelp(cout, *o);
1129
help.outputHelp(cout, opts);
1131
else if (opts.helpGroup.version->boolValue())
1133
// Print the program version
1134
commandline::Help help(APPNAME, VERSION);
1135
help.outputVersion(cout);
1137
else if (opts.lastCommand() == &opts.generic)
1139
commandline::Help help(APPNAME, VERSION);
1140
help.outputHelp(cout, opts);
1142
else if (opts.lastCommand() == &opts.help)
1144
commandline::Help help(APPNAME, VERSION);
1145
commandline::OptionParser* o = 0;
1147
o = opts.command(opts.next());
1150
// Help on a specific command
1151
help.outputHelp(cout, *o);
1154
help.outputHelp(cout, opts);
1156
else if (opts.lastCommand() == &opts.selfcheck)
1159
component::Tags& voc = Global::get().tags();
1161
// ensure that all facets are readable
1162
FacetSet facets = voc.facets();
1163
for (FacetSet::const_iterator i = facets.begin(); i != facets.end(); i++)
1165
cout << "Checking facet " << i->name(string("<invalid name>")) << "..." << endl;
1166
i->name(string("foo"));
1167
i->shortDescription(string("foo"));
1168
i->longDescription(string("foo"));
1172
// ensure that all tags are readable
1173
TagSet tags = voc.tags();
1174
for (TagSet::const_iterator i = tags.begin(); i != tags.end(); i++)
1176
cout << "Checking tag " << i->fullname(string("<invalid name>")) << "..." << endl;
1177
i->name(string("foo"));
1178
i->fullname(string("foo"));
1179
i->shortDescription(string("foo"));
1180
i->longDescription(string("foo"));
1185
// Output the full package tag database
1186
else if (opts.lastCommand() == &opts.cat)
1188
component::PackageTags& debtags = debtagsInit();
1190
auto_ptr< Printer<Package, Tag> > printer;
1192
if (opts.outputGroup.group->boolValue())
1193
printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
1195
printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
1197
Searcher searcher(debtags, printer.get());
1202
// Output the full package database
1203
else if (opts.lastCommand() == &opts.dumpavail)
1205
component::PackageTags& debtags = debtagsInit();
1207
FullAPTPrinter printer;
1317
1212
Searcher searcher(debtags, &printer);
1318
string expression = args.next();
1321
searcher.output(expression, opts.get("invert-match").defined());
1323
return matched > 0 ? 0 : 1;
1327
// grep [-v] [-q] <tag expression>
1328
// Output the lines of the full package tag database that match the
1329
// given tag expression
1332
component::PackageTags& debtags = debtagsInit();
1334
auto_ptr< Printer<Package, Tag> > printer;
1336
if (opts.get("quiet").defined())
1337
printer = auto_ptr< Printer<Package, Tag> >(new NullPrinter);
1338
if (opts.get("groupitems").defined())
1339
printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
1341
printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
1343
Searcher searcher(debtags, printer.get());
1344
string expression = args.next();
1347
searcher.output(expression, opts.get("invert-match").defined());
1349
return matched > 0 ? 0 : 1;
1352
// install [-v] [-q] <tag expression>
1353
// apt-get install the packages that match the given tag expression
1356
component::PackageTags& debtags = debtagsInit();
1358
Installer installer;
1360
Searcher searcher(debtags, &installer);
1361
string expression = args.next();
1363
searcher.output(expression, opts.get("invert-match").defined());
1213
matched = searcher.output(opts.next(), opts.matchGroup.invert->boolValue());
1215
if (!opts.matchGroup.invert->boolValue())
1216
for (component::Packages::iterator i = Global::get().packages().packagesBegin();
1217
i != Global::get().packages().packagesEnd(); ++i)
1218
printer.consume(*i);
1219
matched = printer.count();
1222
return matched > 0 ? 0 : 1;
1224
// search [-v] <tag expression>\n"
1225
// Output the names and description of the packages that match\n"
1226
// the given tag expression\n"
1227
else if (opts.lastCommand() == &opts.search)
1229
component::PackageTags& debtags = debtagsInit();
1232
Searcher searcher(debtags, &printer);
1233
string expression = opts.next();
1236
searcher.output(expression, opts.matchGroup.invert->boolValue());
1238
return matched > 0 ? 0 : 1;
1240
// grep [-v] [-q] <tag expression>
1241
// Output the lines of the full package tag database that match the
1242
// given tag expression
1243
else if (opts.lastCommand() == &opts.grep)
1245
component::PackageTags& debtags = debtagsInit();
1247
auto_ptr< Printer<Package, Tag> > printer;
1249
if (opts.outputGroup.quiet->boolValue())
1250
printer = auto_ptr< Printer<Package, Tag> >(new NullPrinter);
1251
if (opts.outputGroup.group->boolValue())
1252
printer = auto_ptr< Printer<Package, Tag> >(new GroupedTagcollPrinter);
1254
printer = auto_ptr< Printer<Package, Tag> >(new TagcollPrinter);
1256
Searcher searcher(debtags, printer.get());
1257
string expression = opts.next();
1260
searcher.output(expression, opts.matchGroup.invert->boolValue());
1262
return matched > 0 ? 0 : 1;
1264
// install [-v] [-q] <tag expression>
1265
// apt-get install the packages that match the given tag expression
1266
else if (opts.lastCommand() == &opts.install)
1268
component::PackageTags& debtags = debtagsInit();
1270
Installer installer;
1272
Searcher searcher(debtags, &installer);
1273
string expression = opts.next();
1275
searcher.output(expression, opts.matchGroup.invert->boolValue());
1280
// Output the entire tag vocabulary
1281
else if (opts.lastCommand() == &opts.tagcat)
1286
component::Tags& voc = Global::get().tags();
1288
OpSet<Facet> facets = voc.facets();
1289
for (OpSet<Facet>::const_iterator i = facets.begin();
1290
i != facets.end(); i++)
1292
printVocabularyItem(*i);
1294
OpSet<Tag> tags = i->tags();
1295
for (OpSet<Tag>::const_iterator j = tags.begin();
1296
j != tags.end(); j++)
1297
printVocabularyItem(*j);
1302
// Show the vocabulary informations about a tag
1303
else if (opts.lastCommand() == &opts.tagshow)
1307
string tag = opts.next();
1309
Tag t = Global::get().tags().tagByName(tag);
1312
verbose("Tag `%.*s' was not found in tag vocabulary\n", PFSTR(tag));
1369
// Output the entire tag vocabulary
1375
component::Tags& voc = Global::get().tags();
1377
OpSet<Facet> facets = voc.facets();
1378
for (OpSet<Facet>::const_iterator i = facets.begin();
1379
i != facets.end(); i++)
1381
printVocabularyItem(*i);
1383
OpSet<Tag> tags = i->tags();
1384
for (OpSet<Tag>::const_iterator j = tags.begin();
1385
j != tags.end(); j++)
1386
printVocabularyItem(*j);
1317
printVocabularyItem(t);
1391
// Show the vocabulary informations about a tag
1396
string tag = args.next();
1398
Tag t = Global::get().tags().tagByName(tag);
1401
verbose("Tag `%.*s' was not found in tag vocabulary\n", PFSTR(tag));
1406
printVocabularyItem(t);
1410
// tagsearch <pattern [pattern [pattern [...]]]>
1411
// Show a summary of all tags matching the given patterns
1417
SubstringTagMatcher match;
1419
// Get the patterns to be matched
1421
while (args.hasNext())
1423
string pattern = args.next();
1430
error("No patterns given in commandline\n");
1434
component::Tags& voc = Global::get().tags();
1438
OpSet<Facet> facets = voc.facets();
1439
for (OpSet<Facet>::const_iterator i = facets.begin();
1440
i != facets.end(); i++)
1321
// tagsearch <pattern [pattern [pattern [...]]]>
1322
// Show a summary of all tags matching the given patterns
1323
else if (opts.lastCommand() == &opts.tagsearch)
1328
SubstringTagMatcher match;
1330
// Get the patterns to be matched
1332
while (opts.hasNext())
1334
string pattern = opts.next();
1341
error("No patterns given in commandline\n");
1345
component::Tags& voc = Global::get().tags();
1349
OpSet<Facet> facets = voc.facets();
1350
for (OpSet<Facet>::const_iterator i = facets.begin();
1351
i != facets.end(); i++)
1356
printShortVocabularyItem(*i);
1359
OpSet<Tag> tags = i->tags();
1360
for (OpSet<Tag>::const_iterator j = tags.begin();
1361
j != tags.end(); j++)
1445
printShortVocabularyItem(*i);
1448
OpSet<Tag> tags = i->tags();
1449
for (OpSet<Tag>::const_iterator j = tags.begin();
1450
j != tags.end(); j++)
1454
printShortVocabularyItem(*j);
1458
return matched > 0 ? 0 : 1;
1461
// Call apt-cache show <pkg>, but add tag informations to the output.\n"
1464
component::PackageTags& debtags = debtagsInit();
1467
while (args.hasNext())
1469
string name = args.next();
1471
entity::Package pkg = packageByName(name);
1474
cout << pkg.candidateVersion().completeRecord() << endl;
1476
OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
1477
for (OpSet<Tag>::const_iterator i = ts.begin();
1479
if (i == ts.begin())
1480
cout << i->fullname();
1482
cout << ", " + i->fullname();
1486
verbose("Package %.*s not found", PFSTR(name));
1491
// related <pkg1[,pkg2[,pkg2,[...]]]>
1492
// Show packages related to the specified ones
1495
component::PackageTags& debtags = debtagsInit();
1499
if (opts.get("distance").defined())
1500
maxdist = opts.get("distance").intVal();
1501
string pkg = args.next();
1503
// Split the items on commas
1505
OpSet<entity::Package> splititems;
1506
for (string::const_iterator c = pkg.begin(); c != pkg.end(); c++)
1509
entity::Package p = packageByName(splititem);
1512
splititems.insert(p);
1514
error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
1517
splititem = string();
1520
entity::Package p = packageByName(splititem);
1523
splititems.insert(p);
1525
error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
1529
// Get the tagset as the intersection of the tagsets of all input items
1530
OpSet<entity::Package>::const_iterator i = splititems.begin();
1531
OpSet<Tag> ts = debtags.tagdb().getTags(*i);
1532
for (++i; i != splititems.end(); i++)
1533
ts = ts ^ debtags.tagdb().getTags(*i);
1537
if (splititems.size() > 1)
1538
fprintf(stderr, "The packages %.*s are unrelated: cannot find a barycenter to start computing relationships from.\n", PFSTR(pkg));
1540
fprintf(stderr, "The package %.*s has no tags attached.\n", PFSTR(pkg));
1544
APTPrinter printer(splititems);
1545
OpSet<entity::Package> related(debtags.tagdb().getRelatedItems(ts, maxdist));
1546
printer.print(related);
1549
if (printer.count() > 50 && maxdist == 0 && isatty(1))
1365
printShortVocabularyItem(*j);
1369
return matched > 0 ? 0 : 1;
1372
// Call apt-cache show <pkg>, but add tag informations to the output.\n"
1373
else if (opts.lastCommand() == &opts.show)
1375
component::PackageTags& debtags = debtagsInit();
1378
while (opts.hasNext())
1380
string name = opts.next();
1382
entity::Package pkg = packageByName(name);
1385
cout << pkg.candidateVersion().completeRecord() << endl;
1387
OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
1552
1388
for (OpSet<Tag>::const_iterator i = ts.begin();
1553
1389
i != ts.end(); i++)
1554
1390
if (i == ts.begin())
1555
tags += i->fullname();
1391
cout << i->fullname();
1557
tags += "%2C" + i->fullname();
1558
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));
1393
cout << ", " + i->fullname();
1397
verbose("Package %.*s not found", PFSTR(name));
1402
// related <pkg1[,pkg2[,pkg2,[...]]]>
1403
// Show packages related to the specified ones
1404
else if (opts.lastCommand() == &opts.related)
1406
component::PackageTags& debtags = debtagsInit();
1410
if (opts.related.distance->boolValue())
1411
maxdist = opts.related.distance->intValue();
1412
string pkg = opts.next();
1414
// Split the items on commas
1416
OpSet<entity::Package> splititems;
1417
for (string::const_iterator c = pkg.begin(); c != pkg.end(); c++)
1420
entity::Package p = packageByName(splititem);
1423
splititems.insert(p);
1425
error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
1428
splititem = string();
1431
entity::Package p = packageByName(splititem);
1434
splititems.insert(p);
1436
error("Item \"%.*s\" does not exist in the collection\n", PFSTR(splititem));
1440
// Get the tagset as the intersection of the tagsets of all input items
1441
OpSet<entity::Package>::const_iterator i = splititems.begin();
1442
OpSet<Tag> ts = debtags.tagdb().getTags(*i);
1443
for (++i; i != splititems.end(); i++)
1444
ts = ts ^ debtags.tagdb().getTags(*i);
1448
if (splititems.size() > 1)
1449
fprintf(stderr, "The packages %.*s are unrelated: cannot find a barycenter to start computing relationships from.\n", PFSTR(pkg));
1451
fprintf(stderr, "The package %.*s has no tags attached.\n", PFSTR(pkg));
1455
APTPrinter printer(splititems);
1456
OpSet<entity::Package> related(debtags.tagdb().getRelatedItems(ts, maxdist));
1457
printer.print(related);
1460
if (printer.count() > 50 && maxdist == 0 && isatty(1))
1463
for (OpSet<Tag>::const_iterator i = ts.begin();
1465
if (i == ts.begin())
1466
tags += i->fullname();
1468
tags += "%2C" + i->fullname();
1469
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));
1474
// Check that all the tags in the given tagged collection are
1475
// present in the tag vocabulary. Checks the main database if no
1476
// file is specified
1477
else if (opts.lastCommand() == &opts.check)
1486
file = utils::Path::tagdb();
1488
TagcollChecker checker;
1489
readCollection(file, checker);
1491
if (checker.missingCount() > 0)
1563
// Check that all the tags in the given tagged collection are
1564
// present in the tag vocabulary. Checks the main database if no
1565
// file is specified
1500
// Updates the package tag database (requires root)
1501
else if (opts.lastCommand() == &opts.update)
1505
throw ConsistencyCheckException("You must be root to update the system debtags database");
1508
unsigned int ScreenWidth;
1510
if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
1511
ScreenWidth = ws.ws_col - 1;
1513
AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
1514
//Debtags::Environment::get().updateDebtagsDatabase(&Stat);
1515
mode_t prev_umask = umask(022);
1516
//debtags::updateDatabase(&Stat);
1517
if (!opts.update.local->boolValue())
1518
debtags::fetchNewData(&Stat);
1522
// mkpatch [filename]
1523
// Create a tag patch between the current tag database and the tag
1524
// collection [filename]
1525
else if (opts.lastCommand() == &opts.diff)
1527
component::PackageTags& debtags = debtagsInit();
1530
string file = opts.next();
1532
InputMerger<entity::Package, Tag> coll;
1534
Global::get().packagestringconverter(),
1535
Global::get().tagstringconverter(),
1538
PatchList<entity::Package, Tag> newpatches;
1539
newpatches.addPatch(debtags.tagdb(), coll);
1541
TextFormat<entity::Package, Tag>::outputPatch(
1542
Global::get().packagestringconverter(),
1543
Global::get().tagstringconverter(),
1544
newpatches, stdout);
1547
// Create a tagged collection of maintainers and the tags of the
1548
// packages they maintain
1549
else if (opts.lastCommand() == &opts.maintainers)
1554
// Gather maintainer informations
1555
InputMerger<string, Tag> maints;
1556
for (component::Packages::iterator i = Global::get().packages().packagesBegin();
1557
i != Global::get().packages().packagesEnd(); ++i)
1561
entity::Version v = i->candidateVersion();
1564
maints.consume(v.maintainer(), i->tags());
1566
MaintPrinter printer;
1567
maints.output(printer);
1570
// tag [add <package> <tags...>\n"
1571
// tag [rm <package> <tags...>\n"
1572
// tag [ls <package>\n"
1573
// View and edit the tags for a package\n");
1574
else if (opts.lastCommand() == &opts.tag)
1576
std::string cmd = opts.next();
1578
if (cmd == "add" || cmd == "rm")
1580
component::PackageTags& debtags = debtagsInit(true);
1569
1581
wantTagDatabase();
1575
file = utils::Path::tagdb();
1577
TagcollChecker checker;
1578
readCollection(file, checker);
1580
if (checker.missingCount() > 0)
1583
string name = opts.next();
1585
entity::Package pkg = packageByName(name);
1588
error("Package %.*s not found\n", PFSTR(name));
1594
while (opts.hasNext())
1596
string tag = opts.next();
1597
Tag t = Global::get().tags().tagByName(tag);
1601
error("Tag `%.*s' not found: ignored\n", PFSTR(tag));
1604
if (!tagset.empty())
1606
PatchList<entity::Package, Tag> change;
1608
change.addPatch(Patch<entity::Package, Tag>(pkg, tagset, OpSet<Tag>()));
1610
change.addPatch(Patch<entity::Package, Tag>(pkg, OpSet<Tag>(), tagset));
1611
debtags.tagdb().applyChange(change);
1612
debtags.savePatch();
1614
verbose("No tags to add\n");
1616
else if (cmd == "ls")
1618
component::PackageTags& debtags = debtagsInit();
1621
string name = opts.next();
1622
entity::Package pkg = packageByName(name);
1625
OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
1626
for (OpSet<Tag>::const_iterator i = ts.begin();
1628
printf("%.*s\n", PFSTR(i->fullname()));
1589
// Updates the package tag database (requires root)
1594
throw ConsistencyCheckException("You must be root to update the system debtags database");
1597
unsigned int ScreenWidth;
1599
if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
1600
ScreenWidth = ws.ws_col - 1;
1602
AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
1603
//Debtags::Environment::get().updateDebtagsDatabase(&Stat);
1604
mode_t prev_umask = umask(022);
1605
debtags::updateDatabase(&Stat);
1607
feedback("Done.\n");
1610
// mkpatch [filename]
1611
// Create a tag patch between the current tag database and the tag
1612
// collection [filename]
1615
component::PackageTags& debtags = debtagsInit();
1618
string file = args.next();
1620
InputMerger<entity::Package, Tag> coll;
1621
Converter<string, Package> toitem;
1622
Converter<string, Tag> totag;
1623
readCollection(toitem, totag, file, coll);
1625
PatchList<entity::Package, Tag> newpatches;
1626
newpatches.addPatch(debtags.tagdb(), coll);
1628
Converter<entity::Package, string> fromitem;
1629
Converter<Tag, string> fromtag;
1630
TextFormat<entity::Package, Tag>::outputPatch(fromitem, fromtag, newpatches, stdout);
1634
// Create a tagged collection of maintainers and the tags of the
1635
// packages they maintain
1641
// Gather maintainer informations
1642
InputMerger<string, Tag> maints;
1643
for (component::Packages::iterator i = Global::get().packages().packagesBegin();
1644
i != Global::get().packages().packagesEnd(); i++)
1648
entity::Version v = i->candidateVersion();
1649
maints.consume(v.maintainer(), i->tags());
1651
MaintPrinter printer;
1652
maints.output(printer);
1656
// tag [add <package> <tags...>\n"
1657
// tag [rm <package> <tags...>\n"
1658
// tag [ls <package>\n"
1659
// View and edit the tags for a package\n");
1662
std::string cmd = args.next();
1664
if (cmd == "add" || cmd == "rm")
1666
component::PackageTags& debtags = debtagsInit(true);
1669
string name = args.next();
1671
entity::Package pkg = packageByName(name);
1674
error("Package %.*s not found\n", PFSTR(name));
1680
while (args.hasNext())
1682
string tag = args.next();
1683
Tag t = Global::get().tags().tagByName(tag);
1687
error("Tag `%.*s' not found: ignored\n", PFSTR(tag));
1690
if (!tagset.empty())
1692
PatchList<entity::Package, Tag> change;
1694
change.addPatch(Patch<entity::Package, Tag>(pkg, tagset, OpSet<Tag>()));
1696
change.addPatch(Patch<entity::Package, Tag>(pkg, OpSet<Tag>(), tagset));
1697
debtags.tagdb().applyChange(change);
1698
debtags.savePatch();
1700
verbose("No tags to add\n");
1702
else if (cmd == "ls")
1704
component::PackageTags& debtags = debtagsInit();
1707
string name = args.next();
1708
entity::Package pkg = packageByName(name);
1711
OpSet<Tag> ts = debtags.tagdb().getTags(pkg);
1712
for (OpSet<Tag>::const_iterator i = ts.begin();
1714
printf("%.*s\n", PFSTR(i->fullname()));
1717
verbose("Package %.*s not found", PFSTR(name));
1722
throw ConsistencyCheckException("command " + cmd + " is not valid working with tags");
1726
// Mail the local updates to the tag database to the central tag
1730
component::PackageTags& debtags = debtagsInit();
1735
StdioParserInput in(args.next());
1736
Converter<string, Package> toitem;
1737
Converter<string, Tag> totag;
1738
PatchList<entity::Package, Tag> patch =
1739
TextFormat<entity::Package, Tag>::parsePatch(toitem, totag, in);
1740
debtags.sendPatch(patch);
1743
debtags.sendPatch();
1748
// Print a list of the installed packages that are not yet tagged
1751
component::PackageTags& debtags = debtagsInit();
1754
// Write the package names to stdout
1757
// Filter to select the right packages
1758
TODOFilter filter(printer);
1760
debtags.outputPatched(filter);
1767
// Score uninstalled packages according to how often their tags
1768
// appear in the packages that are installed already
1771
component::PackageTags& debtags = debtagsInit();
1774
// Compute tag scores
1776
debtags.outputPatched(tscorer);
1778
// Compute package scores
1779
PackageScorer pscorer(tscorer);
1780
debtags.outputPatched(pscorer);
1782
// Print the results
1783
for (PackageScorer::const_iterator i = pscorer.begin();
1784
i != pscorer.end(); i++)
1785
printf("%d %.*s - %.*s\n", i->first,
1786
PFSTR(i->second.name()), PFSTR(i->second.shortDescription("(short description not available)")));
1790
// Print the tagged collection where each package is tagged with
1794
component::PackageTags& debtags = debtagsInit();
1797
FacetcollPrinter<entity::Package> printer;
1798
TagToFacet<entity::Package> tagToFacet(printer);
1799
debtags.outputPatched(tagToFacet);
1803
// Print statistics about Debtags
1806
component::PackageTags& debtags = debtagsInit();
1809
int pkgCount = Global::get().packages().packageCount();
1810
printf("Total count of packages: %d\n", pkgCount);
1812
StatsCollector stats;
1813
debtags.outputPatched(stats);
1815
printf("Total count of packages (according to APT): %d\n", pkgCount);
1816
printf("Total count of packages (according to Debtags): %d\n", stats.get_seen());
1818
const component::Tags& voc = Global::get().tags();
1819
printf("Number of facets: %d\n", voc.facets().size());
1820
printf("Number of tags: %d\n", voc.tags().size());
1822
// Copied from Debtags class: compute the toplevel facets
1823
// TODO: use Debtags instead of Environment throughout all Debtags
1824
CardinalityStore<entity::Package, Facet> coll;
1825
TagToFacet<entity::Package> tagStripper(coll);
1826
debtags.outputPatched(tagStripper);
1828
SmartHierarchyNode<entity::Package, Facet> node(f, coll, 0);
1829
printf("Number of automatically computed toplevel facets: %d\n", node.size());
1831
printf("Number of packages with special::completely-tagged tags: %d (%.1f%%)\n",
1832
stats.get_complete(), (float)stats.get_complete()*100/stats.get_seen());
1833
printf("Number of packages with tags, but no special::not-yet-tagged tags: %d (%.1f%%)\n",
1834
stats.get_tagged(), (float)stats.get_tagged()*100/stats.get_seen());
1835
printf("Number of packages with special::not-yet-tagged tags: %d (%.1f%%)\n",
1836
stats.get_nyt(), (float)stats.get_nyt()*100/stats.get_seen());
1837
printf("Number of packages with only special::not-yet-tagged tags: %d (%.1f%%)\n",
1838
stats.get_onlynyt(), (float)stats.get_onlynyt()*100/stats.get_seen());
1839
printf("Number of packages with no tags: %d (%.1f%%)\n",
1840
stats.get_notags(), (float)stats.get_notags()*100/stats.get_seen());
1845
// Print a report of packages needing work
1851
unsigned int itemsPerGroup = 0;
1853
itemsPerGroup = atoi(args.next().c_str());
1855
ReportMaker rm(itemsPerGroup);
1860
// ssearch <word [word1 [word2 ...]]>
1861
// Perform a keyword search integrated with related packages
1864
component::PackageTags& debtags = debtagsInit();
1867
SmartSearcher smart(debtags, &printer);
1868
Searcher searcher(debtags, &smart);
1869
predicate::Predicate<Package> p = predicate::True<Package>();
1870
//predicate::Factory<Package>::description(args.next());
1871
while (args.hasNext())
1873
string arg = args.next();
1877
p = p and predicate::Factory<Package>::tag(
1878
Global::get().tags().tagByName(arg.substr(1)));
1881
p = p and not predicate::Factory<Package>::tag(
1882
Global::get().tags().tagByName(arg.substr(1)));
1885
p = p and predicate::Factory<Package>::description(arg);
1890
int step1 = searcher.output(p);
1891
int step2 = smart.outputRelated();
1893
cout << step1 << " normal matches plus " << step2 << " related packages." << endl;
1894
OpSet<Tag> topTags = smart.topTags();
1895
cout << "Top tags were: " << topTags << endl;
1897
return step1 + step2 > 0 ? 0 : 1;
1631
verbose("Package %.*s not found", PFSTR(name));
1636
throw ConsistencyCheckException("command " + cmd + " is not valid working with tags");
1639
// Mail the local updates to the tag database to the central tag
1641
else if (opts.lastCommand() == &opts.submit)
1643
component::PackageTags& debtags = debtagsInit();
1648
StdioParserInput in(opts.next());
1649
PatchList<entity::Package, Tag> patch =
1650
TextFormat<entity::Package, Tag>::parsePatch(
1651
Global::get().packagestringconverter(),
1652
Global::get().tagstringconverter(),
1654
debtags.sendPatch(patch);
1657
debtags.sendPatch();
1661
// Print a list of the installed packages that are not yet tagged
1662
else if (opts.lastCommand() == &opts.todo)
1664
component::PackageTags& debtags = debtagsInit();
1667
// Write the package names to stdout
1670
// Filter to select the right packages
1671
TODOFilter filter(printer);
1673
debtags.outputPatched(filter);
1679
// Score uninstalled packages according to how often their tags
1680
// appear in the packages that are installed already
1681
else if (opts.lastCommand() == &opts.score)
1683
component::PackageTags& debtags = debtagsInit();
1686
// Compute tag scores
1688
debtags.outputPatched(tscorer);
1690
// Compute package scores
1691
PackageScorer pscorer(tscorer);
1692
debtags.outputPatched(pscorer);
1694
// Print the results
1695
for (PackageScorer::const_iterator i = pscorer.begin();
1696
i != pscorer.end(); i++)
1697
printf("%d %.*s - %.*s\n", i->first,
1698
PFSTR(i->second.name()), PFSTR(i->second.shortDescription(string("(short description not available)"))));
1701
// Print the tagged collection where each package is tagged with
1703
else if (opts.lastCommand() == &opts.facetcoll)
1705
component::PackageTags& debtags = debtagsInit();
1708
FacetcollPrinter<entity::Package> printer;
1709
TagToFacet<entity::Package> tagToFacet(printer);
1710
debtags.outputPatched(tagToFacet);
1713
// Print statistics about Debtags
1714
else if (opts.lastCommand() == &opts.stats)
1716
component::PackageTags& debtags = debtagsInit();
1719
int pkgCount = Global::get().packages().packageCount();
1720
printf("Total count of packages: %d\n", pkgCount);
1722
StatsCollector stats;
1723
debtags.outputPatched(stats);
1725
printf("Total count of packages (according to APT): %d\n", pkgCount);
1726
printf("Total count of packages (according to Debtags): %d\n", stats.get_seen());
1728
const component::Tags& voc = Global::get().tags();
1729
printf("Number of facets: %d\n", voc.facets().size());
1730
printf("Number of tags: %d\n", voc.tags().size());
1732
// Copied from Debtags class: compute the toplevel facets
1733
// TODO: use Debtags instead of Environment throughout all Debtags
1734
CardinalityStore<entity::Package, Facet> coll;
1735
TagToFacet<entity::Package> tagStripper(coll);
1736
debtags.outputPatched(tagStripper);
1738
SmartHierarchyNode<entity::Package, Facet> node(f, coll, 0);
1739
printf("Number of automatically computed toplevel facets: %d\n", node.size());
1741
printf("Number of packages with special::completely-tagged tags: %d (%.1f%%)\n",
1742
stats.get_complete(), (float)stats.get_complete()*100/stats.get_seen());
1743
printf("Number of packages with tags, but no special::not-yet-tagged tags: %d (%.1f%%)\n",
1744
stats.get_tagged(), (float)stats.get_tagged()*100/stats.get_seen());
1745
printf("Number of packages with special::not-yet-tagged tags: %d (%.1f%%)\n",
1746
stats.get_nyt(), (float)stats.get_nyt()*100/stats.get_seen());
1747
printf("Number of packages with only special::not-yet-tagged tags: %d (%.1f%%)\n",
1748
stats.get_onlynyt(), (float)stats.get_onlynyt()*100/stats.get_seen());
1749
printf("Number of packages with no tags: %d (%.1f%%)\n",
1750
stats.get_notags(), (float)stats.get_notags()*100/stats.get_seen());
1754
// Print a report of packages needing work
1755
else if (opts.lastCommand() == &opts.todoreport)
1760
unsigned int itemsPerGroup = 0;
1762
itemsPerGroup = atoi(opts.next().c_str());
1764
ReportMaker rm(itemsPerGroup);
1768
// ssearch <word [word1 [word2 ...]]>
1769
// Perform a keyword search integrated with related packages
1770
else if (opts.lastCommand() == &opts.smartsearch)
1772
component::PackageTags& debtags = debtagsInit();
1775
SmartSearcher smart(debtags, &printer);
1776
Searcher searcher(debtags, &smart);
1777
predicate::Predicate<Package> p = predicate::True<Package>();
1778
//predicate::Factory<Package>::description(opts.next());
1779
while (opts.hasNext())
1781
string arg = opts.next();
1785
p = p and predicate::Factory<Package>::tag(
1786
Global::get().tags().tagByName(arg.substr(1)));
1789
p = p and not predicate::Factory<Package>::tag(
1790
Global::get().tags().tagByName(arg.substr(1)));
1793
p = p and predicate::Factory<Package>::description(arg);
1798
int step1 = searcher.output(p);
1799
int step2 = smart.outputRelated();
1801
cout << step1 << " normal matches plus " << step2 << " related packages." << endl;
1802
OpSet<Tag> topTags = smart.topTags();
1803
cout << "Top tags were: " << topTags << endl;
1805
return step1 + step2 > 0 ? 0 : 1;
1808
throw commandline::BadOption(string("unhandled command ") +
1809
(opts.lastCommand() ? opts.lastCommand()->name() : "(null)"));
1905
catch (Exception& e)
1812
} catch (commandline::BadOption& e) {
1813
cerr << e.desc() << endl;
1814
commandline::Help help(APPNAME, VERSION);
1815
if (opts.lastCommand())
1817
help.outputHelp(cerr, *opts.lastCommand());
1819
help.outputHelp(cerr, opts);
1822
} catch (Exception& e) {
1907
1823
fatal_error("%s: %.*s\n", e.type(), PFSTR(e.desc()));