Simplify CLI code

This commit is contained in:
Martchus 2018-01-24 23:07:53 +01:00
parent 447928a018
commit 45b242b91a
4 changed files with 64 additions and 127 deletions

View File

@ -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);
}
}
}

View File

@ -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 &);

View File

@ -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");

View File

@ -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;
};