diff --git a/src/tools/balooctl/main.cpp b/src/tools/balooctl/main.cpp index 3a8d2b88..b56a02f7 100644 --- a/src/tools/balooctl/main.cpp +++ b/src/tools/balooctl/main.cpp @@ -1,333 +1,343 @@ /* Copyright (c) 2012-2015 Vishesh Handa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" #include "database.h" #include "transaction.h" #include "databasesize.h" #include "indexer.h" #include "indexerconfig.h" #include "idutils.h" #include "fileindexerconfig.h" #include "monitorcommand.h" #include "schedulerinterface.h" #include "maininterface.h" #include "indexerstate.h" #include "configcommand.h" #include "statuscommand.h" using namespace Baloo; void start() { const QString exe = QStandardPaths::findExecutable(QStringLiteral("baloo_file")); QProcess::startDetached(exe); } int main(int argc, char* argv[]) { QCoreApplication app(argc, argv); KAboutData aboutData(QStringLiteral("baloo"), i18n("balooctl"), PROJECT_VERSION); aboutData.addAuthor(i18n("Vishesh Handa"), i18n("Maintainer"), QStringLiteral("vhanda@kde.org")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; parser.addPositionalArgument(QStringLiteral("command"), i18n("The command to execute")); parser.addPositionalArgument(QStringLiteral("status"), i18n("Print the status of the indexer")); parser.addPositionalArgument(QStringLiteral("enable"), i18n("Enable the file indexer")); parser.addPositionalArgument(QStringLiteral("disable"), i18n("Disable the file indexer")); parser.addPositionalArgument(QStringLiteral("start"), i18n("Start the file indexer")); parser.addPositionalArgument(QStringLiteral("stop"), i18n("Stop the file indexer")); parser.addPositionalArgument(QStringLiteral("restart"), i18n("Restart the file indexer")); parser.addPositionalArgument(QStringLiteral("suspend"), i18n("Suspend the file indexer")); parser.addPositionalArgument(QStringLiteral("resume"), i18n("Resume the file indexer")); parser.addPositionalArgument(QStringLiteral("check"), i18n("Check for any unindexed files and index them")); parser.addPositionalArgument(QStringLiteral("checkDb"), i18n("Check database for consistency")); parser.addPositionalArgument(QStringLiteral("index"), i18n("Index the specified files")); parser.addPositionalArgument(QStringLiteral("clear"), i18n("Forget the specified files")); parser.addPositionalArgument(QStringLiteral("config"), i18n("Modify the Baloo configuration")); parser.addPositionalArgument(QStringLiteral("monitor"), i18n("Monitor the file indexer")); parser.addPositionalArgument(QStringLiteral("indexSize"), i18n("Display the disk space used by index")); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("f") << QStringLiteral("format"), + i18n("Output format <%1|%2|%3>.\nOnly applies to \"%4\"", + QStringLiteral("json"), + QStringLiteral("simple"), + QStringLiteral("multiline (default)"), + QStringLiteral("balooctl status ") + ) + , i18n("format") + + , QStringLiteral("multiline"))); parser.addVersionOption(); parser.addHelpOption(); parser.process(app); if (parser.positionalArguments().isEmpty()) { parser.showHelp(1); } QTextStream err(stderr); QTextStream out(stdout); QString command = parser.positionalArguments().first(); org::kde::baloo::main mainInterface(QStringLiteral("org.kde.baloo"), QStringLiteral("/"), QDBusConnection::sessionBus()); org::kde::baloo::scheduler schedulerinterface(QStringLiteral("org.kde.baloo"), QStringLiteral("/scheduler"), QDBusConnection::sessionBus()); if (command == QStringLiteral("config")) { ConfigCommand command; return command.exec(parser); } if (command == QLatin1String("status")) { StatusCommand command; return command.exec(parser); } if (command == QLatin1String("enable") || command == QLatin1String("disable")) { bool isEnabled = false; if (command == QLatin1String("enable")) { isEnabled = true; } else if (command == QLatin1String("disable")) { isEnabled = false; } IndexerConfig cfg; cfg.setFileIndexingEnabled(isEnabled); if (isEnabled) { out << "Enabling the File Indexer\n"; cfg.setFirstRun(true); start(); } else { out << "Disabling the File Indexer\n"; mainInterface.quit(); const QString path = fileIndexDbPath() + QStringLiteral("/index"); QFile(path).remove(); } return 0; } if (command == QLatin1String("start") || command == QLatin1String("stop") || command == QLatin1String("restart")) { bool shouldStart = false; bool shouldStop = false; if (command == QLatin1String("start")) shouldStart = true; else if (command == QLatin1String("stop")) shouldStop = true; else if (command == QLatin1String("restart")) { shouldStart = true; shouldStop = true; } if (shouldStop) mainInterface.quit(); if (shouldStart) start(); return 0; } if (command == QStringLiteral("suspend")) { schedulerinterface.suspend(); out << "File Indexer suspended\n"; return 0; } if (command == QStringLiteral("resume")) { schedulerinterface.resume(); out << "File Indexer resumed\n"; return 0; } if (command == QStringLiteral("check")) { schedulerinterface.checkUnindexedFiles(); out << "Started search for unindexed files\n"; return 0; } if (command == QStringLiteral("index")) { if (parser.positionalArguments().size() < 2) { out << "Please enter a filename to index\n"; return 1; } Database *db = globalDatabaseInstance(); if (!db->open(Database::ReadWriteDatabase)) { out << "Baloo Index could not be opened\n"; return 1; } Transaction tr(db, Transaction::ReadWrite); for (int i = 1; i < parser.positionalArguments().size(); ++i) { const QString url = QFileInfo(parser.positionalArguments().at(i)).absoluteFilePath(); quint64 id = filePathToId(QFile::encodeName(url)); if (id == 0) { out << "Could not stat file: " << url << endl; continue; } if (tr.inPhaseOne(id)) { out << "Skipping: " << url << " Reason: Already scheduled for indexing\n"; continue; } if (!tr.documentData(id).isEmpty()) { out << "Skipping: " << url << " Reason: Already indexed\n"; continue; } Indexer indexer(url, &tr); out << "Indexing " << url << endl; indexer.index(); } tr.commit(); out << "File(s) indexed\n"; return 0; } if (command == QStringLiteral("clear")) { if (parser.positionalArguments().size() < 2) { out << "Please enter a filename to index\n"; return 1; } Database *db = globalDatabaseInstance(); if (!db->open(Database::ReadWriteDatabase)) { out << "Baloo Index could not be opened\n"; return 1; } Transaction tr(db, Transaction::ReadWrite); for (int i = 1; i < parser.positionalArguments().size(); ++i) { const QString url = QFileInfo(parser.positionalArguments().at(i)).absoluteFilePath(); quint64 id = filePathToId(QFile::encodeName(url)); if (id == 0) { out << "Could not stat file: " << url << endl; continue; } if (tr.documentData(id).isEmpty()) { out << "Skipping: " << url << " Reason: Not yet indexed\n"; continue; } Indexer indexer(url, &tr); out << "Clearing " << url << endl; tr.removeDocument(id); } tr.commit(); out << "File(s) cleared\n"; return 0; } if (command == QStringLiteral("indexSize")) { Database *db = globalDatabaseInstance(); if (!db->open(Database::ReadOnlyDatabase)) { out << "Baloo Index could not be opened\n"; return 1; } DatabaseSize size; { Transaction tr(db, Transaction::ReadOnly); size = tr.dbSize(); } KFormat format(QLocale::system()); auto prFunc = [&](const QString& name, uint size, uint totalSize) { out.setFieldWidth(20); out << name; out.setFieldWidth(0); out << ":"; out.setFieldWidth(15); out << format.formatByteSize(size, 2); out.setFieldWidth(10); out << QString::number((100.0 * size / totalSize), 'f', 3); out.setFieldWidth(0); out << " %\n"; }; uint ts = size.expectedSize; out << "Actual Size: " << format.formatByteSize(size.actualSize, 2) << "\n"; out << "Expected Size: " << format.formatByteSize(size.expectedSize, 2) << "\n\n"; prFunc(QStringLiteral("PostingDB"), size.postingDb, ts); prFunc(QStringLiteral("PosistionDB"), size.positionDb, ts); prFunc(QStringLiteral("DocTerms"), size.docTerms, ts); prFunc(QStringLiteral("DocFilenameTerms"), size.docFilenameTerms, ts); prFunc(QStringLiteral("DocXattrTerms"), size.docXattrTerms, ts); prFunc(QStringLiteral("IdTree"), size.idTree, ts); prFunc(QStringLiteral("IdFileName"), size.idFilename, ts); prFunc(QStringLiteral("DocTime"), size.docTime, ts); prFunc(QStringLiteral("DocData"), size.docData, ts); prFunc(QStringLiteral("ContentIndexingDB"), size.contentIndexingIds, ts); prFunc(QStringLiteral("FailedIdsDB"), size.failedIds, ts); prFunc(QStringLiteral("MTimeDB"), size.mtimeDb, ts); return 0; } if (command == QStringLiteral("monitor")) { MonitorCommand mon; return mon.exec(parser); } if (command == QStringLiteral("checkDb")) { Database *db = globalDatabaseInstance(); if (!db->open(Database::ReadOnlyDatabase)) { out << "Baloo Index could not be opened\n"; return 1; } Transaction tr(db, Transaction::ReadOnly); tr.checkPostingDbinTermsDb(); tr.checkTermsDbinPostingDb(); out << "Checking file paths .. " << endl; tr.checkFsTree(); return 0; } parser.showHelp(1); return 0; } diff --git a/src/tools/balooctl/statuscommand.cpp b/src/tools/balooctl/statuscommand.cpp index 30a22fea..41ee3b6c 100644 --- a/src/tools/balooctl/statuscommand.cpp +++ b/src/tools/balooctl/statuscommand.cpp @@ -1,136 +1,245 @@ /* * This file is part of the KDE Baloo project. * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "statuscommand.h" #include "indexerconfig.h" #include "global.h" #include "database.h" #include "transaction.h" #include "idutils.h" #include "schedulerinterface.h" #include "maininterface.h" #include "indexerstate.h" #include #include using namespace Baloo; QString StatusCommand::command() { return QStringLiteral("status"); } QString StatusCommand::description() { return i18n("Print the status of the Indexer"); } +void printMultiLine(Transaction& tr, IndexerConfig& cfg, const QStringList& args) { + QTextStream out(stdout); + QTextStream err(stderr); + for (const QString& arg : args) { + QString filePath = QFileInfo(arg).absoluteFilePath(); + quint64 id = filePathToId(QFile::encodeName(filePath)); + if (id == 0) { + err << i18n("Ignoring non-existent file %1", filePath) << endl; + continue; + } + + + out << i18n("File: %1", filePath) << endl; + if (tr.hasDocument(id)) { + out << i18n("Basic Indexing: Done") << endl; + } else if (cfg.shouldBeIndexed(filePath)) { + out << i18n("Basic Indexing: Scheduled") << endl; + continue; + } else { + // FIXME: Add why it is not being indexed! + out << i18n("Basic Indexing: Disabled") << endl; + continue; + } + + if (QFileInfo(arg).isDir()) { + continue; + } + + if (tr.inPhaseOne(id)) { + out << i18n("Content Indexing: Scheduled") << endl; + } else if (tr.hasFailed(id)) { + out << i18n("Content Indexing: Failed") << endl; + } else { + out << i18n("Content Indexing: Done") << endl; + } + } +} + +void printSimpleFormat(Transaction& tr, IndexerConfig& cfg, const QStringList& args) { + QTextStream out(stdout); + QTextStream err(stderr); + for (const QString& arg : args) { + QString filePath = QFileInfo(arg).absoluteFilePath(); + quint64 id = filePathToId(QFile::encodeName(filePath)); + if (id == 0) { + err << i18n("Ignoring non-existent file %1", filePath) << endl; + continue; + } + + if (QFileInfo(arg).isDir()) { + if (tr.hasDocument(id)) { + out << QLatin1String("Basic indexing done"); + } else if (cfg.shouldBeIndexed(filePath)) { + out << QLatin1String("Basic indexing scheduled"); + + } else { + out << QLatin1String("Indexing disabled"); + } + + } else if (tr.hasDocument(id)) { + if (tr.inPhaseOne(id)) { + out << QLatin1String("Content indexing scheduled"); + } else if (tr.hasFailed(id)) { + out << QLatin1String("Content indexing failed"); + } else { + out << QLatin1String("Content indexing done"); + } + + } else if (cfg.shouldBeIndexed(filePath)) { + out << QLatin1String("Basic indexing scheduled"); + } else { + out << QLatin1String("Indexing disabled"); + } + + out << ":" << filePath << endl; + } +} + +void printJSON(Transaction& tr, IndexerConfig& cfg, const QStringList& args) { + + QJsonArray filesInfo; + for (const QString& arg : args) { + QString filePath = QFileInfo(arg).absoluteFilePath(); + quint64 id = filePathToId(QFile::encodeName(filePath)); + + if (id == 0) { + QTextStream err(stderr); + err << i18n("Ignoring non-existent file %1", filePath) << endl; + continue; + } + QJsonObject fileInfo; + fileInfo["file"] = filePath; + if (!tr.hasDocument(id)) { + fileInfo["indexing"] = "basic"; + if (cfg.shouldBeIndexed(filePath)) { + fileInfo["status"] = "scheduled"; + } else { + fileInfo["status"] = "disabled"; + } + + } else if (QFileInfo(arg).isDir()) { + fileInfo["indexing"] = "basic"; + fileInfo["status"] = "done"; + + } else { + fileInfo["indexing"] = "content"; + if (tr.inPhaseOne(id)) { + fileInfo["status"] = "scheduled"; + } else if (tr.hasFailed(id)) { + fileInfo["status"] = "failed"; + } else { + fileInfo["status"] = "done"; + } + } + + filesInfo.append(fileInfo); + } + + QJsonDocument json; + json.setArray(filesInfo); + QTextStream out(stdout); + out << json.toJson(QJsonDocument::Indented); +} + int StatusCommand::exec(const QCommandLineParser& parser) { QTextStream out(stdout); QTextStream err(stderr); + const QStringList allowedFormats({"simple", "json", "multiline"}); + const QString format = parser.value(QStringLiteral("format")); + + if (!allowedFormats.contains(format)) { + err << i18n("Output format \"%1\" is invalid", format) << endl; + return 1; + } + IndexerConfig cfg; if (!cfg.fileIndexingEnabled()) { err << i18n("Baloo is currently disabled. To enable, please run %1", QStringLiteral("balooctl enable")) << endl; return 1; } Database *db = globalDatabaseInstance(); if (!db->open(Database::ReadOnlyDatabase)) { err << i18n("Baloo Index could not be opened") << endl; return 1; } Transaction tr(db, Transaction::ReadOnly); QStringList args = parser.positionalArguments(); args.pop_front(); if (args.isEmpty()) { org::kde::baloo::main mainInterface(QStringLiteral("org.kde.baloo"), QStringLiteral("/"), QDBusConnection::sessionBus()); org::kde::baloo::scheduler schedulerinterface(QStringLiteral("org.kde.baloo"), QStringLiteral("/scheduler"), QDBusConnection::sessionBus()); bool running = mainInterface.isValid(); if (running) { out << i18n("Baloo File Indexer is running") << endl; out << i18n("Indexer state: %1", stateString(schedulerinterface.state())) << endl; } else { out << i18n("Baloo File Indexer is not running") << endl; } uint phaseOne = tr.phaseOneSize(); uint total = tr.size(); out << i18n("Indexed %1 / %2 files", total - phaseOne, total) << endl; const QString path = fileIndexDbPath(); const QFileInfo indexInfo(path + QLatin1String("/index")); const auto size = indexInfo.size(); KFormat format(QLocale::system()); if (size) { out << i18n("Current size of index is %1", format.formatByteSize(size, 2)) << endl; } else { out << i18n("Index does not exist yet") << endl; } + } else if (format == allowedFormats[0]){ + printSimpleFormat(tr, cfg, args); + } else if (format == allowedFormats[1]){ + printJSON(tr, cfg, args); } else { - for (const QString& arg : args) { - QString filePath = QFileInfo(arg).absoluteFilePath(); - quint64 id = filePathToId(QFile::encodeName(filePath)); - - out << i18n("File: %1", filePath) << endl; - if (tr.hasDocument(id)) { - out << i18n("Basic Indexing: Done") << endl; - } else if (cfg.shouldBeIndexed(filePath)) { - out << i18n("Basic Indexing: Scheduled") << endl; - continue; - } else { - // FIXME: Add why it is not being indexed! - out << i18n("Basic Indexing: Disabled") << endl; - continue; - } - - if (QFileInfo(arg).isDir()) { - continue; - } - - if (tr.inPhaseOne(id)) { - out << i18n("Content Indexing: Scheduled") << endl; - } else if (tr.hasFailed(id)) { - out << i18n("Content Indexing: Failed") << endl; - } else { - out << i18n("Content Indexing: Done") << endl; - } - } + printMultiLine(tr, cfg, args); } return 0; }