From 45b242b91a2ed0688839ce6db83662562a3baf94 Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 24 Jan 2018 23:07:53 +0100 Subject: [PATCH] Simplify CLI code --- cli/application.cpp | 140 ++++++++++++++------------------------------ cli/application.h | 4 -- cli/args.cpp | 42 ++++++------- cli/args.h | 5 +- 4 files changed, 64 insertions(+), 127 deletions(-) diff --git a/cli/application.cpp b/cli/application.cpp index 23f60f8..3f8fd7f 100644 --- a/cli/application.cpp +++ b/cli/application.cpp @@ -74,20 +74,14 @@ Application::Application() m_args.rescanAll.setCallback(bind(&Application::requestRescanAll, this, _1)); m_args.pause.setCallback(bind(&Application::requestPauseResume, this, true)); m_args.resume.setCallback(bind(&Application::requestPauseResume, this, false)); - m_args.pauseAllDevs.setCallback(bind(&Application::requestPauseAllDevs, this, _1)); - m_args.pauseAllDirs.setCallback(bind(&Application::requestPauseAllDirs, this, _1)); - m_args.resumeAllDevs.setCallback(bind(&Application::requestResumeAllDevs, this, _1)); - m_args.resumeAllDirs.setCallback(bind(&Application::requestResumeAllDirs, this, _1)); m_args.waitForIdle.setCallback(bind(&Application::waitForIdle, this, _1)); m_args.pwd.setCallback(bind(&Application::checkPwdOperationPresent, this, _1)); m_args.statusPwd.setCallback(bind(&Application::printPwdStatus, this, _1)); m_args.rescanPwd.setCallback(bind(&Application::requestRescanPwd, this, _1)); m_args.pausePwd.setCallback(bind(&Application::requestPausePwd, this, _1)); m_args.resumePwd.setCallback(bind(&Application::requestResumePwd, this, _1)); - m_args.pauseDir.setCallback(bind(&Application::initDirCompletion, this, ref(m_args.pauseDir), _1)); - m_args.statusDir.setCallback(bind(&Application::initDirCompletion, this, ref(m_args.statusDir), _1)); - m_args.pauseDev.setCallback(bind(&Application::initDevCompletion, this, ref(m_args.pauseDev), _1)); - m_args.statusDev.setCallback(bind(&Application::initDevCompletion, this, ref(m_args.statusDev), _1)); + m_args.dir.setCallback(bind(&Application::initDirCompletion, this, ref(m_args.dir), _1)); + m_args.dev.setCallback(bind(&Application::initDevCompletion, this, ref(m_args.dev), _1)); // connect signals and slots connect(&m_connection, &SyncthingConnection::statusChanged, this, &Application::handleStatusChanged); @@ -129,8 +123,7 @@ int Application::exec(int argc, const char *const *argv) } // finally do the request or establish connection - if (m_args.status.isPresent() || m_args.rescan.isPresent() || m_args.rescanAll.isPresent() || m_args.pauseAllDirs.isPresent() - || m_args.pauseAllDevs.isPresent() || m_args.resumeAllDirs.isPresent() || m_args.resumeAllDevs.isPresent() || m_args.pause.isPresent() + if (m_args.status.isPresent() || m_args.rescan.isPresent() || m_args.rescanAll.isPresent() || m_args.pause.isPresent() || m_args.resume.isPresent() || m_args.waitForIdle.isPresent() || m_args.pwd.isPresent()) { // those arguments rquire establishing a connection first, the actual handler is called by handleStatusChanged() when // the connection has been established @@ -406,102 +399,59 @@ void Application::requestPauseResume(bool pause) cerr << flush; } -void Application::requestPauseAllDevs(const ArgumentOccurrence &) -{ - findRelevantDirsAndDevs(OperationType::PauseResume); - connect(&m_connection, &SyncthingConnection::devicePauseTriggered, this, &Application::handleResponse); - if (!m_connection.pauseAllDevs()) { - cerr << Phrases::Warning << "No devices to be paused." << Phrases::End << flush; - exit(0); - } - cerr << "Request pausing all devices ..." << endl; - m_expectedResponse = 1; -} - -void Application::requestPauseAllDirs(const ArgumentOccurrence &) -{ - connect(&m_connection, &SyncthingConnection::directoryPauseTriggered, this, &Application::handleResponse); - if (!m_connection.pauseAllDirs()) { - cerr << Phrases::Warning << "No directories to be paused." << Phrases::End << flush; - exit(0); - } - cerr << "Request pausing all directories ..." << endl; - m_expectedResponse = 1; -} - -void Application::requestResumeAllDevs(const ArgumentOccurrence &) -{ - connect(&m_connection, &SyncthingConnection::deviceResumeTriggered, this, &Application::handleResponse); - if (!m_connection.resumeAllDevs()) { - cerr << Phrases::Warning << "No devices to be resumed." << Phrases::End << flush; - exit(0); - } - cerr << "Request resuming all devices ..." << endl; - m_expectedResponse = 1; -} - -void Application::requestResumeAllDirs(const ArgumentOccurrence &) -{ - connect(&m_connection, &SyncthingConnection::deviceResumeTriggered, this, &Application::handleResponse); - if (!m_connection.resumeAllDirs()) { - cerr << Phrases::Warning << "No directories to be resumed." << Phrases::End << flush; - exit(0); - } - cerr << "Request resuming all directories ..." << endl; - m_expectedResponse = 1; -} - void Application::findRelevantDirsAndDevs(OperationType operationType) { int dummy; - Argument *dirArg, *devArg; - switch (operationType) { - case OperationType::Status: - dirArg = &m_args.statusDir; - devArg = &m_args.statusDev; - break; - case OperationType::PauseResume: - dirArg = &m_args.pauseDir; - devArg = &m_args.pauseDev; + // find relevant dirs + const bool allDirs = m_args.allDirs.isPresent(); + if (!allDirs) { + const Argument &dirArg = m_args.dir; + if (dirArg.isPresent()) { + m_relevantDirs.reserve(dirArg.occurrences()); + for (size_t i = 0; i != dirArg.occurrences(); ++i) { + const QString dirIdentifier(argToQString(dirArg.values(i).front())); + const RelevantDir relevantDir(findDirectory(dirIdentifier)); + if (relevantDir.dirObj) { + m_relevantDirs.emplace_back(move(relevantDir)); + } + } + } } - if (dirArg->isPresent()) { - m_relevantDirs.reserve(dirArg->occurrences()); - for (size_t i = 0; i != dirArg->occurrences(); ++i) { - const QString dirIdentifier(argToQString(dirArg->values(i).front())); - const RelevantDir relevantDir(findDirectory(dirIdentifier)); - if (relevantDir.dirObj) { - m_relevantDirs.emplace_back(move(relevantDir)); + // find relevant devs + const bool allDevs = m_args.allDevs.isPresent(); + if (!allDevs) { + Argument &devArg = m_args.dev; + if (devArg.isPresent()) { + m_relevantDevs.reserve(devArg.occurrences()); + for (size_t i = 0; i != devArg.occurrences(); ++i) { + const SyncthingDev *dev = m_connection.findDevInfo(argToQString(devArg.values(i).front()), dummy); + if (!dev) { + dev = m_connection.findDevInfoByName(argToQString(devArg.values(i).front()), dummy); + } + if (dev) { + m_relevantDevs.emplace_back(dev); + } else { + cerr << Phrases::Warning << "Specified device \"" << devArg.values(i).front() << "\" does not exist and will be ignored." + << Phrases::End; + } } } } - if (devArg->isPresent()) { - m_relevantDevs.reserve(devArg->occurrences()); - for (size_t i = 0; i != devArg->occurrences(); ++i) { - const SyncthingDev *dev = m_connection.findDevInfo(argToQString(devArg->values(i).front()), dummy); - if (!dev) { - dev = m_connection.findDevInfoByName(argToQString(devArg->values(i).front()), dummy); - } - if (dev) { - m_relevantDevs.emplace_back(dev); - } else { - cerr << Phrases::Warning << "Specified device \"" << devArg->values(i).front() << "\" does not exist and will be ignored." - << Phrases::End; - } + + // when displaying status information and no dirs/devs have been specified, just print information for all + const bool displayEverything = operationType == OperationType::Status && m_relevantDirs.empty() && m_relevantDevs.empty(); + if (allDirs || (!allDevs && displayEverything)) { + m_relevantDirs.reserve(m_connection.dirInfo().size()); + for (const SyncthingDir &dir : m_connection.dirInfo()) { + m_relevantDirs.emplace_back(&dir, QString()); } } - if (operationType == OperationType::Status) { - // when displaying status information and no dirs/devs have been specified, just print information for all - if (m_relevantDirs.empty() && m_relevantDevs.empty()) { - m_relevantDirs.reserve(m_connection.dirInfo().size()); - for (const SyncthingDir &dir : m_connection.dirInfo()) { - m_relevantDirs.emplace_back(&dir, QString()); - } - m_relevantDevs.reserve(m_connection.devInfo().size()); - for (const SyncthingDev &dev : m_connection.devInfo()) { - m_relevantDevs.emplace_back(&dev); - } + if (allDevs || (!allDirs && displayEverything)) { + m_relevantDevs.reserve(m_connection.devInfo().size()); + for (const SyncthingDev &dev : m_connection.devInfo()) { + m_relevantDevs.emplace_back(&dev); } } } diff --git a/cli/application.h b/cli/application.h index 610c8c3..55970f1 100644 --- a/cli/application.h +++ b/cli/application.h @@ -61,10 +61,6 @@ private: void requestRescan(const ArgumentOccurrence &occurrence); void requestRescanAll(const ArgumentOccurrence &); void requestPauseResume(bool pause); - void requestPauseAllDevs(const ArgumentOccurrence &); - void requestPauseAllDirs(const ArgumentOccurrence &); - void requestResumeAllDevs(const ArgumentOccurrence &); - void requestResumeAllDirs(const ArgumentOccurrence &); static void printDir(const RelevantDir &relevantDir); static void printDev(const Data::SyncthingDev *dev); void printStatus(const ArgumentOccurrence &); diff --git a/cli/args.cpp b/cli/args.cpp index ddd158a..cd9b24f 100644 --- a/cli/args.cpp +++ b/cli/args.cpp @@ -13,21 +13,17 @@ Args::Args() , rescan("rescan", 'r', "rescans the specified directories") , rescanAll("rescan-all", '\0', "rescans all directories") , pause("pause", '\0', "pauses the specified devices") - , pauseAllDevs("pause-all-devs", '\0', "pauses all devices") - , pauseAllDirs("pause-all-dirs", '\0', "pauses all directories") , resume("resume", '\0', "resumes the specified devices") - , resumeAllDevs("resume-all-devs", '\0', "resumes all devices") - , resumeAllDirs("resume-all-dirs", '\0', "resumes all directories") , waitForIdle("wait-for-idle", 'w', "waits until the specified dirs/devs are idling") , pwd("pwd", 'p', "operates in the current working directory") , statusPwd("status", 's', "prints the status of the current working directory") , rescanPwd("rescan", 'r', "rescans the current working directory") , pausePwd("pause", 'p', "pauses the current working directory") , resumePwd("resume", '\0', "resumes the current working directory") - , statusDir("dir", 'd', "specifies the directories, default is all dirs", { "ID" }) - , statusDev("dev", '\0', "specifies the devices, default is all devs", { "ID" }) - , pauseDir("dir", 'd', "specifies the directories", { "ID" }) - , pauseDev("dev", '\0', "specifies the devices", { "ID" }) + , dir("dir", 'd', "specifies a directory", { "ID" }) + , dev("dev", '\0', "specifies a device", { "ID" }) + , allDirs("all-dirs", '\0', "apply operation for all directories") + , allDevs("all-devs", '\0', "apply operation for all devices") , atLeast("at-least", 'a', "specifies for how many milliseconds Syncthing must idle (prevents exiting to early in case of flaky status)", { "number" }) , timeout("timeout", 't', "specifies how many milliseconds to wait at most", { "number" }) @@ -37,18 +33,14 @@ Args::Args() , credentials("credentials", 'c', "specifies user name and password", { "user name", "password" }) , certificate("cert", '\0', "specifies the certificate used by the Syncthing instance", { "path" }) { - for (Argument *arg : { &statusDir, &pauseDir }) { - arg->setConstraints(0, Argument::varValueCount); - arg->setValueCompletionBehavior( - ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::Directories | ValueCompletionBehavior::InvokeCallback); - } - for (Argument *arg : { &statusDev, &pauseDev }) { - arg->setConstraints(0, Argument::varValueCount); - arg->setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::InvokeCallback); - } - status.setSubArguments({ &statusDir, &statusDev }); + dir.setConstraints(0, Argument::varValueCount); + dir.setValueCompletionBehavior( + ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::Directories | ValueCompletionBehavior::InvokeCallback); + dev.setConstraints(0, Argument::varValueCount); + dev.setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::InvokeCallback); + status.setSubArguments({ &dir, &dev, &allDirs, &allDevs }); status.setExample(PROJECT_NAME " status # shows all dirs and devs\n" PROJECT_NAME " status --dir dir1 --dir dir2 --dev dev1 --dev dev2"); - waitForIdle.setSubArguments({ &statusDir, &statusDev, &atLeast, &timeout }); + waitForIdle.setSubArguments({ &dir, &dev, &atLeast, &timeout }); waitForIdle.setExample(PROJECT_NAME " wait-for-idle --timeout 1800000 --at-least 5000 && systemctl poweroff\n" PROJECT_NAME " wait-for-idle --dir dir1 --dir dir2 --dev dev1 --dev dev2 --at-least 5000"); pwd.setSubArguments({ &statusPwd, &rescanPwd, &pausePwd, &resumePwd }); @@ -58,16 +50,16 @@ Args::Args() rescan.setValueCompletionBehavior( ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::Directories | ValueCompletionBehavior::InvokeCallback); rescan.setExample(PROJECT_NAME " rescan dir1 dir2 dir4 dir5"); - pause.setSubArguments({ &pauseDir, &pauseDev }); - pause.setExample(PROJECT_NAME " pause --dir dir1 --dir dir2 --dev dev1 --dev dev2"); - resume.setSubArguments({ &pauseDir, &pauseDev }); - resume.setExample(PROJECT_NAME " resume --dir dir1 --dir dir2 --dev dev1 --dev dev2"); + pause.setSubArguments({ &dir, &dev, &allDirs, &allDevs }); + pause.setExample(PROJECT_NAME " pause --dir dir1 --dir dir2 --dev dev1 --dev dev2\n" PROJECT_NAME " pause --all-dirs"); + resume.setSubArguments({ &dir, &dev, &allDirs, &allDevs }); + resume.setExample(PROJECT_NAME " resume --dir dir1 --dir dir2 --dev dev1 --dev dev2\n" PROJECT_NAME " resume --all-devs"); configFile.setExample(PROJECT_NAME " status --dir dir1 --config-file ~/.config/syncthing/config.xml"); credentials.setExample(PROJECT_NAME " status --dir dir1 --credentials name supersecret"); - parser.setMainArguments({ &status, &log, &stop, &restart, &rescan, &rescanAll, &pause, &pauseAllDevs, &pauseAllDirs, &resume, &resumeAllDevs, - &resumeAllDirs, &waitForIdle, &pwd, &configFile, &apiKey, &url, &credentials, &certificate, &noColor, &help }); + parser.setMainArguments({ &status, &log, &stop, &restart, &rescan, &rescanAll, &pause, &resume, &waitForIdle, &pwd, &configFile, &apiKey, &url, + &credentials, &certificate, &noColor, &help }); // allow setting default values via environment configFile.setEnvironmentVariable("SYNCTHING_CTL_CONFIG_FILE"); diff --git a/cli/args.h b/cli/args.h index bb631d8..2ac37ed 100644 --- a/cli/args.h +++ b/cli/args.h @@ -12,10 +12,9 @@ struct Args { ArgumentParser parser; HelpArgument help; NoColorArgument noColor; - OperationArgument status, log, stop, restart, rescan, rescanAll, pause, pauseAllDevs, pauseAllDirs, resume, resumeAllDevs, resumeAllDirs, - waitForIdle, pwd; + OperationArgument status, log, stop, restart, rescan, rescanAll, pause, resume, waitForIdle, pwd; OperationArgument statusPwd, rescanPwd, pausePwd, resumePwd; - ConfigValueArgument statusDir, statusDev, pauseDir, pauseDev; + ConfigValueArgument dir, dev, allDirs, allDevs; ConfigValueArgument atLeast, timeout; ConfigValueArgument configFile, apiKey, url, credentials, certificate; };