Baloo

tools/experimental/baloodb/main.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Michael Heidelbach <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6 
7 #include "global.h"
8 #include "experimental/databasesanitizer.h"
9 
10 #include <KAboutData>
11 #include <KLocalizedString>
12 
13 #include <QCoreApplication>
14 #include <QCommandLineOption>
15 #include <QCommandLineParser>
16 #include <QStandardPaths>
17 #include <QTextStream>
18 #include <QList>
19 #include <QElapsedTimer>
20 
21 using namespace Baloo;
22 
23 struct Command {
24  const QString name;
25  const QString description;
26  const QStringList args;
27  const QStringList options;
28 };
29 
30 const auto options = QList<QCommandLineOption>{
32  QStringList{QStringLiteral("i"), QStringLiteral("device-id")},
33  i18n("Filter by device id."
34  "\n0 (default) does not filter and everything is printed."
35  "\nPositive numbers are including filters printing only the mentioned device id."
36  "\nNegative numbers are excluding filters printing everything but the mentioned device id."
37  "\nMay be given multiple times."),
38  i18n("integer"),
39  nullptr
40  },
42  QStringList{QStringLiteral("m"), QStringLiteral("missing-only")},
43  i18n("List only inaccessible entries.\nOnly applies to \"%1\"", QStringLiteral("list"))
44  },
46  QStringList{QStringLiteral("u"), QStringLiteral("mounted-only")},
47  i18n("Act only on item on mounted devices")
48  },
50  QStringList{QStringLiteral("D"), QStringLiteral("dry-run")},
51  i18n("Print results of a cleaning operation, but do not change anything."
52  "\nOnly applies to \"%1\" command", QStringLiteral("clean"))
53  }
54 };
55 
56 const auto commands = std::vector<Command>{
57  Command{
58  QStringLiteral("list"),
59  i18n("List database contents. Use a regular expression as argument to filter output"),
61  QStringLiteral("pattern")
62  },
64  QStringLiteral("missing-only"),
65  QStringLiteral("device-id")
66  }
67  },
68  Command{
69  QStringLiteral("devices"),
70  i18n("List devices"),
71  QStringList{},
72  QStringList{QStringLiteral("missing-only")}
73  },
74  /*TODO:
75  Command{
76  QStringLiteral("check"),
77  i18n("Check database contents. "
78  "Beware this may take very long to execute"),
79  QStringList{},
80  QStringList{}
81  },
82  */
83  Command{
84  QStringLiteral("clean"),
85  i18n("Remove stale database entries"),
87  QStringLiteral("pattern")
88  },
90  QStringLiteral("dry-run"),
91  QStringLiteral("device-id"),
92  QStringLiteral("mounted-only")
93  }
94  }
95 };
96 
97 const QStringList allowedCommands()
98 {
99  QStringList names;
100  for (const auto& c : commands) {
101  names.append(c.name);
102  }
103  return names;
104 }
105 const QStringList getOptions(const QString& name)
106 {
107  for (const auto& c : commands) {
108  if (c.name == name) {
109  return c.options;
110  }
111  }
112  return QStringList();
113 }
114 QString createDescription()
115 {
116  QStringList allowedcommands;
117  for (const auto& c: commands) {
118  auto options = getOptions(c.name);
119  const QString optionStr = options.isEmpty()
120  ? QString()
121  : QStringLiteral(" [--%1]").arg(options.join(QLatin1String("] [--")));
122 
123  QString argumentStr;
124  if (!c.args.isEmpty() ) {
125  argumentStr = QStringLiteral(" [%1]").arg(c.args.join(QStringLiteral("] [")));
126  }
127 
128  const QString commandStr = QStringLiteral("%1%2%3")
129  .arg(c.name)
130  .arg(optionStr)
131  .arg(argumentStr);
132 
133  const QString str = QStringLiteral("%1 %2")
134  .arg(commandStr, -58)
135  .arg(c.description);
136 
137  allowedcommands.append(str);
138  }
139  const QString allCommandsStr = allowedcommands.join(QLatin1String("\n "));
140  return i18n("\n\nCommands:\n %1", allCommandsStr);
141 }
142 
143 int main(int argc, char* argv[])
144 {
145  QCoreApplication app(argc, argv);
146  KAboutData aboutData(QStringLiteral("baloodb"),
147  i18n("Baloo Database Sanitizer"),
148  PROJECT_VERSION,
149  i18n("The Baloo Database Lister & Sanitizer"),
151  i18n("(c) 2018, Michael Heidelbach"));
152  aboutData.addAuthor(i18n("Michael Heidelbach"), i18n("Maintainer"), QStringLiteral("[email protected]"));
154 
155  QCommandLineParser parser;
156  parser.addOptions(options);
157  parser.addPositionalArgument(QStringLiteral("command"),
158  i18n("The command to execute"),
159  allowedCommands().join(QLatin1Char('|'))
160  );
161  parser.addPositionalArgument(QStringLiteral("pattern"),
162  i18nc("Command", "A regular expression applied to the URL of database items"
163  "\nExample: %1"
164  , "baloodb list '^/media/videos/series'"
165  )
166  );
167  const QString warnExperiment = QStringLiteral(
168  "===\nPlease note: This is an experimental tool. Command line switches or their meaning may change.\n===");
169 
170  parser.setApplicationDescription(warnExperiment + createDescription());
171  parser.addVersionOption();
172  parser.addHelpOption();
173 
174  parser.process(app);
175  if (parser.positionalArguments().isEmpty()) {
176  qDebug() << "No command";
177  parser.showHelp(1);
178  }
179 
180  auto args = parser.positionalArguments();
181  auto command = args.at(0);
182  args.removeFirst();
183 
184  if(!allowedCommands().contains(command)) {
185  qDebug() << "Unknown command" << command;
186  parser.showHelp(1);
187  }
188 
189  const auto optNames = parser.optionNames();
190  const auto allowedOptions = getOptions(command);
191 
192  QVector<qint64> deviceIds;
193  for (const auto& dev : parser.values(QStringLiteral("device-id"))) {
194  deviceIds.append(dev.toInt());
195  }
196  const DatabaseSanitizer::ItemAccessFilters accessFilter = (
197  parser.isSet(QStringLiteral("missing-only"))
198  ? DatabaseSanitizer::IgnoreAvailable
199  : DatabaseSanitizer::IgnoreNone
200  ) | (
201  parser.isSet(QStringLiteral("mounted-only"))
202  ? DatabaseSanitizer::IgnoreUnmounted
203  : DatabaseSanitizer::IgnoreNone
204  );
205  const QString pattern = args.isEmpty()
206  ? QString()
207  : args.at(0);
209  ? nullptr
210  : new QRegularExpression{pattern});
211 
212  auto db = globalDatabaseInstance();
213  QTextStream err(stderr);
214  QElapsedTimer timer;
215  timer.start();
216 
217  if (command == QLatin1String("list")) {
218  if (!db->open(Database::ReadOnlyDatabase)) {
219  err << i18n("Baloo Index could not be opened") << endl;
220  return 1;
221  }
222  DatabaseSanitizer san(db, Transaction::ReadOnly);
223  err << i18n("Listing database contents...") << endl;
224  san.printList(deviceIds, accessFilter, urlFilter);
225  } else if (command == QLatin1String("devices")) {
226  if (!db->open(Database::ReadOnlyDatabase)) {
227  err << i18n("Baloo Index could not be opened") << endl;
228  return 1;
229  }
230  DatabaseSanitizer san(db, Transaction::ReadOnly);
231  err << i18n("Listing database contents...") << endl;
232  san.printDevices(deviceIds, accessFilter);
233 
234  } else if (command == QLatin1String("clean")) {
235  auto dbMode = Database::ReadWriteDatabase;
236  if (!db->open(dbMode)) {
237  err << i18n("Baloo Index could not be opened") << endl;
238  return 1;
239  }
240  DatabaseSanitizer san(db, Transaction::ReadWrite);
241  err << i18n("Removing stale database contents...") << endl;
242  san.removeStaleEntries(deviceIds, accessFilter, parser.isSet(QStringLiteral("dry-run")), urlFilter);
243 
244  } else if (command == QLatin1String("check")) {
245  parser.showHelp(1);
246  /* TODO: After check methods are improved
247  Database *db = globalDatabaseInstance();
248  if (!db->open(Database::ReadOnlyDatabase)) {
249  err << i18n("Baloo Index could not be opened") << endl;
250  return 1;
251  }
252  Transaction tr(db, Transaction::ReadOnly);
253  err << i18n("Checking file paths ... ") << endl;
254  tr.checkFsTree();
255 
256  err << i18n("Checking postings ... ") << endl;
257  tr.checkTermsDbinPostingDb();
258 
259  err << i18n("Checking terms ... ") << endl;
260  tr.checkPostingDbinTermsDb();
261  */
262  }
263  err << i18n("Elapsed: %1 secs", timer.nsecsElapsed() / 1000000000.0) << endl;
264 
265  return 0;
266 }
void append(const T &value)
QTextStream & endl(QTextStream &stream)
QString pattern(Mode mode=Reading)
void setApplicationDescription(const QString &description)
static void setApplicationData(const KAboutData &aboutData)
void append(const T &value)
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
QStringList positionalArguments() const const
Provide methods to show database problems and sanitize them.
QStringList optionNames() const const
void showHelp(int exitCode)
QString i18n(const char *text, const TYPE &arg...)
void process(const QStringList &arguments)
QCommandLineOption addVersionOption()
qint64 nsecsElapsed() const const
Implements storage for docIds without any associated data Instantiated for:
Definition: coding.cpp:11
bool isEmpty() const const
const T & at(int i) const const
bool isEmpty() const const
QString join(const QString &separator) const const
QStringList values(const QString &optionName) const const
bool isSet(const QString &name) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool addOptions(const QList< QCommandLineOption > &options)
const char * name(StandardAction id)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QCommandLineOption addHelpOption()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Dec 11 2023 03:53:57 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.