Allow printing current config

This commit is contained in:
Martchus 2018-04-01 20:21:51 +02:00
parent e9e85e6ba9
commit 754cd0c2e1
6 changed files with 50 additions and 22 deletions

View File

@ -17,6 +17,7 @@
#include <QCoreApplication>
#include <QDir>
#include <QJsonDocument>
#include <QNetworkAccessManager>
#include <QStringBuilder>
#include <QTimer>
@ -57,6 +58,7 @@ Application::Application()
: m_expectedResponse(0)
, m_preventDisconnect(false)
, m_callbacksInvoked(false)
, m_requiresMainEventLoop(true)
, m_idleDuration(0)
, m_idleTimeout(0)
, m_argsRead(false)
@ -76,6 +78,7 @@ Application::Application()
m_args.resume.setCallback(bind(&Application::requestPauseResume, this, false));
m_args.waitForIdle.setCallback(bind(&Application::waitForIdle, this, _1));
m_args.pwd.setCallback(bind(&Application::checkPwdOperationPresent, this, _1));
m_args.cat.setCallback(bind(&Application::printConfig, 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));
@ -125,7 +128,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.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
// those arguments require establishing a connection first, the actual handler is called by handleStatusChanged() when
// the connection has been established
m_connection.reconnect(m_settings);
cerr << "Connecting to " << m_settings.syncthingUrl.toLocal8Bit().data() << " ...";
@ -136,23 +139,26 @@ int Application::exec(int argc, const char *const *argv)
m_args.parser.invokeCallbacks();
}
// enter event loop
// enter main event loop
if (!m_requiresMainEventLoop) {
return 0;
}
return QCoreApplication::exec();
}
int assignIntegerFromArg(const Argument &arg, int &integer)
{
if (arg.isPresent()) {
try {
integer = stringToNumber<int>(arg.firstValue());
if (integer < 0) {
throw ConversionException();
}
} catch (const ConversionException &) {
cerr << Phrases::Error << "The specified number of milliseconds \"" << arg.firstValue() << "\" is no unsigned integer." << Phrases::End
<< flush;
return -4;
if (!arg.isPresent()) {
return 0;
}
try {
integer = stringToNumber<int>(arg.firstValue());
if (integer < 0) {
throw ConversionException();
}
} catch (const ConversionException &) {
cerr << Phrases::Error << "The specified number of milliseconds \"" << arg.firstValue() << "\" is no unsigned integer." << Phrases::EndFlush;
return -4;
}
return 0;
}
@ -171,10 +177,10 @@ int Application::loadConfig()
const char *apiKeyArgValue = m_args.apiKey.firstValue();
if (!config.restore(configFile)) {
if (configFileArgValue) {
cerr << Phrases::Error << "Unable to locate specified Syncthing config file \"" << configFileArgValue << "\"" << Phrases::End << flush;
cerr << Phrases::Error << "Unable to locate specified Syncthing config file \"" << configFileArgValue << "\"" << Phrases::EndFlush;
return -1;
} else if (!apiKeyArgValue) {
cerr << Phrases::Error << "Unable to locate Syncthing config file and no API key specified" << Phrases::End << flush;
cerr << Phrases::Error << "Unable to locate Syncthing config file and no API key specified" << Phrases::EndFlush;
return -2;
}
}
@ -583,6 +589,15 @@ void Application::printLog(const std::vector<SyncthingLogEntry> &logEntries)
QCoreApplication::exit();
}
void Application::printConfig(const ArgumentOccurrence &)
{
waitForConfig();
eraseLine(cout);
cout << '\r' << QJsonDocument(m_connection.rawConfig()).toJson().data() << flush;
// disable main event loop since this method is invoked directly as argument callback and we've done all async operations during the waitForConfig() call already
m_requiresMainEventLoop = false;
}
void Application::waitForIdle(const ArgumentOccurrence &)
{
m_preventDisconnect = true;
@ -733,7 +748,7 @@ void Application::initDirCompletion(Argument &arg, const ArgumentOccurrence &)
}
// load config and wait for connected
loadConfig();
waitForConfig(2000);
waitForConfig();
// set directory IDs as completion values
m_dirCompletion = m_connection.directoryIds().join(QChar(' ')).toUtf8();
arg.setPreDefinedCompletionValues(m_dirCompletion.data());
@ -747,7 +762,7 @@ void Application::initDevCompletion(Argument &arg, const ArgumentOccurrence &)
}
// load config and wait for connected
loadConfig();
waitForConfig(2000);
waitForConfig();
// set device IDs and names as completion values
QStringList completionValues;
const size_t valueCount = m_connection.devInfo().size() << 2;

View File

@ -53,8 +53,8 @@ private slots:
private:
int loadConfig();
bool waitForConnected(int timeout);
bool waitForConfig(int timeout);
bool waitForConnected(int timeout = 2000);
bool waitForConfig(int timeout = 2000);
void requestLog(const ArgumentOccurrence &);
void requestShutdown(const ArgumentOccurrence &);
void requestRestart(const ArgumentOccurrence &);
@ -65,6 +65,7 @@ private:
void printDev(const Data::SyncthingDev *dev) const;
void printStatus(const ArgumentOccurrence &);
static void printLog(const std::vector<Data::SyncthingLogEntry> &logEntries);
void printConfig(const ArgumentOccurrence &);
void waitForIdle(const ArgumentOccurrence &);
bool checkWhetherIdle() const;
void checkPwdOperationPresent(const ArgumentOccurrence &occurrence);
@ -82,6 +83,7 @@ private:
size_t m_expectedResponse;
bool m_preventDisconnect;
bool m_callbacksInvoked;
bool m_requiresMainEventLoop;
std::vector<RelevantDir> m_relevantDirs;
std::vector<const Data::SyncthingDev *> m_relevantDevs;
RelevantDir m_pwd;

View File

@ -16,6 +16,7 @@ Args::Args()
, resume("resume", '\0', "resumes the specified directories and devices")
, waitForIdle("wait-for-idle", 'w', "waits until the specified dirs/devs are idling")
, pwd("pwd", 'p', "operates in the current working directory")
, cat("cat", '\0', "prints the current configuration")
, 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")
@ -58,8 +59,8 @@ Args::Args()
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, &resume, &waitForIdle, &pwd, &configFile, &apiKey, &url,
&credentials, &certificate, &noColor, &help });
parser.setMainArguments({ &status, &log, &stop, &restart, &rescan, &rescanAll, &pause, &resume, &waitForIdle, &pwd, &cat, &configFile, &apiKey,
&url, &credentials, &certificate, &noColor, &help });
// allow setting default values via environment
configFile.setEnvironmentVariable("SYNCTHING_CTL_CONFIG_FILE");

View File

@ -12,7 +12,7 @@ struct Args {
ArgumentParser parser;
HelpArgument help;
NoColorArgument noColor;
OperationArgument status, log, stop, restart, rescan, rescanAll, pause, resume, waitForIdle, pwd;
OperationArgument status, log, stop, restart, rescan, rescanAll, pause, resume, waitForIdle, pwd, cat;
OperationArgument statusPwd, rescanPwd, pausePwd, resumePwd;
ConfigValueArgument dir, dev, allDirs, allDevs;
ConfigValueArgument atLeast, timeout;

View File

@ -129,6 +129,7 @@ public:
QStringList deviceIds() const;
QString deviceNameOrId(const QString &deviceId) const;
std::size_t connectedDevices() const;
const QJsonObject &rawConfig() const;
public Q_SLOTS:
bool loadSelfSignedCertificate();
@ -560,6 +561,15 @@ inline const QList<QSslError> &SyncthingConnection::expectedSslErrors()
{
return m_expectedSslErrors;
}
/*!
* \brief Returns the raw Syncthing configuration.
* \remarks The referenced object is updated when newConfig() is emitted.
*/
inline const QJsonObject &SyncthingConnection::rawConfig() const
{
return m_rawConfig;
}
} // namespace Data
Q_DECLARE_METATYPE(Data::SyncthingLogEntry)

View File

@ -315,7 +315,7 @@ template <typename Action, typename... SignalInfos> bool waitForSignals(Action a
/*!
* \brief Waits until the specified signals have been emitted when performing async operations triggered by \a action. Aborts when \a failure is emitted.
* \arg action Specifies a method to trigger the action to run when waiting.
* \arg timeout Specifies the max. time to wait. Set to zero to wait forever.
* \arg timeout Specifies the max. time to wait in ms. Set to zero to wait forever.
* \arg failure Specifies the signal indicating an error occured.
* \arg signalInfos Specifies the signals to wait for.
* \throws Fails if not all signals have been emitted in at least \a timeout milliseconds or when at least one of the