Make bash completion faster by requesting only config
This commit is contained in:
parent
6be44cc93f
commit
914aac6e39
|
@ -216,14 +216,23 @@ int Application::loadConfig()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::waitForConnected(int timeout)
|
bool Application::waitForConnected(int timeout)
|
||||||
{
|
{
|
||||||
using namespace TestUtilities;
|
using namespace TestUtilities;
|
||||||
bool isConnected = m_connection.isConnected();
|
bool isConnected = m_connection.isConnected();
|
||||||
const function<void(SyncthingStatus)> checkStatus([this, &isConnected](SyncthingStatus) { isConnected = m_connection.isConnected(); });
|
const function<void(SyncthingStatus)> checkStatus([this, &isConnected](SyncthingStatus) { isConnected = m_connection.isConnected(); });
|
||||||
waitForSignals(bind(static_cast<void (SyncthingConnection::*)(SyncthingConnectionSettings &)>(&SyncthingConnection::reconnect), ref(m_connection),
|
return waitForSignalsOrFail(bind(static_cast<void (SyncthingConnection::*)(SyncthingConnectionSettings &)>(&SyncthingConnection::reconnect),
|
||||||
ref(m_settings)),
|
ref(m_connection), ref(m_settings)),
|
||||||
timeout, signalInfo(&m_connection, &SyncthingConnection::statusChanged, checkStatus, &isConnected));
|
timeout, signalInfo(&m_connection, &SyncthingConnection::error),
|
||||||
|
signalInfo(&m_connection, &SyncthingConnection::statusChanged, checkStatus, &isConnected));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::waitForConfig(int timeout)
|
||||||
|
{
|
||||||
|
using namespace TestUtilities;
|
||||||
|
return waitForSignalsOrFail(bind(&SyncthingConnection::requestConfig, ref(m_connection)), timeout,
|
||||||
|
signalInfo(&m_connection, &SyncthingConnection::error), signalInfo(&m_connection, &SyncthingConnection::newConfig),
|
||||||
|
signalInfo(&m_connection, &SyncthingConnection::newDirs), signalInfo(&m_connection, &SyncthingConnection::newDevices));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::handleStatusChanged(SyncthingStatus newStatus)
|
void Application::handleStatusChanged(SyncthingStatus newStatus)
|
||||||
|
@ -723,9 +732,10 @@ void Application::initDirCompletion(Argument &arg, const ArgumentOccurrence &)
|
||||||
}
|
}
|
||||||
// load config and wait for connected
|
// load config and wait for connected
|
||||||
loadConfig();
|
loadConfig();
|
||||||
waitForConnected(2000);
|
waitForConfig(2000);
|
||||||
// set directory IDs as completion values
|
// set directory IDs as completion values
|
||||||
arg.setPreDefinedCompletionValues(m_connection.directoryIds().join(QChar(' ')).toUtf8().data());
|
m_dirCompletion = m_connection.directoryIds().join(QChar(' ')).toUtf8();
|
||||||
|
arg.setPreDefinedCompletionValues(m_dirCompletion.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::initDevCompletion(Argument &arg, const ArgumentOccurrence &)
|
void Application::initDevCompletion(Argument &arg, const ArgumentOccurrence &)
|
||||||
|
@ -736,7 +746,7 @@ void Application::initDevCompletion(Argument &arg, const ArgumentOccurrence &)
|
||||||
}
|
}
|
||||||
// load config and wait for connected
|
// load config and wait for connected
|
||||||
loadConfig();
|
loadConfig();
|
||||||
waitForConnected(2000);
|
waitForConfig(2000);
|
||||||
// set device IDs and names as completion values
|
// set device IDs and names as completion values
|
||||||
QStringList completionValues;
|
QStringList completionValues;
|
||||||
const size_t valueCount = m_connection.devInfo().size() << 2;
|
const size_t valueCount = m_connection.devInfo().size() << 2;
|
||||||
|
@ -747,7 +757,8 @@ void Application::initDevCompletion(Argument &arg, const ArgumentOccurrence &)
|
||||||
for (const SyncthingDev &dev : m_connection.devInfo()) {
|
for (const SyncthingDev &dev : m_connection.devInfo()) {
|
||||||
completionValues << dev.id << dev.name;
|
completionValues << dev.id << dev.name;
|
||||||
}
|
}
|
||||||
arg.setPreDefinedCompletionValues(completionValues.join(QChar(' ')).toUtf8().data());
|
m_devCompletion = completionValues.join(QChar(' ')).toUtf8();
|
||||||
|
arg.setPreDefinedCompletionValues(m_devCompletion.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
RelevantDir Application::findDirectory(const QString &dirIdentifier)
|
RelevantDir Application::findDirectory(const QString &dirIdentifier)
|
||||||
|
|
|
@ -53,7 +53,8 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int loadConfig();
|
int loadConfig();
|
||||||
void waitForConnected(int timeout);
|
bool waitForConnected(int timeout);
|
||||||
|
bool waitForConfig(int timeout);
|
||||||
void requestLog(const ArgumentOccurrence &);
|
void requestLog(const ArgumentOccurrence &);
|
||||||
void requestShutdown(const ArgumentOccurrence &);
|
void requestShutdown(const ArgumentOccurrence &);
|
||||||
void requestRestart(const ArgumentOccurrence &);
|
void requestRestart(const ArgumentOccurrence &);
|
||||||
|
@ -84,6 +85,8 @@ private:
|
||||||
std::vector<RelevantDir> m_relevantDirs;
|
std::vector<RelevantDir> m_relevantDirs;
|
||||||
std::vector<const Data::SyncthingDev *> m_relevantDevs;
|
std::vector<const Data::SyncthingDev *> m_relevantDevs;
|
||||||
RelevantDir m_pwd;
|
RelevantDir m_pwd;
|
||||||
|
QByteArray m_dirCompletion;
|
||||||
|
QByteArray m_devCompletion;
|
||||||
int m_idleDuration;
|
int m_idleDuration;
|
||||||
int m_idleTimeout;
|
int m_idleTimeout;
|
||||||
bool m_argsRead;
|
bool m_argsRead;
|
||||||
|
|
|
@ -182,7 +182,7 @@ void SyncthingConnection::connect(SyncthingConnectionSettings &connectionSetting
|
||||||
*/
|
*/
|
||||||
void SyncthingConnection::disconnect()
|
void SyncthingConnection::disconnect()
|
||||||
{
|
{
|
||||||
m_reconnecting = m_hasConfig = m_hasStatus = false;
|
m_reconnecting = m_hasConfig = m_hasStatus = m_keepPolling = false;
|
||||||
m_autoReconnectTries = 0;
|
m_autoReconnectTries = 0;
|
||||||
abortAllRequests();
|
abortAllRequests();
|
||||||
}
|
}
|
||||||
|
@ -1007,9 +1007,15 @@ void SyncthingConnection::readConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rawConfig = replyDoc.object();
|
m_rawConfig = replyDoc.object();
|
||||||
emit newConfig(m_rawConfig);
|
|
||||||
m_hasConfig = true;
|
m_hasConfig = true;
|
||||||
concludeReadingConfigAndStatus();
|
emit newConfig(m_rawConfig);
|
||||||
|
|
||||||
|
if (m_keepPolling) {
|
||||||
|
concludeReadingConfigAndStatus();
|
||||||
|
} else {
|
||||||
|
readDevs(m_rawConfig.value(QStringLiteral("devices")).toArray());
|
||||||
|
readDirs(m_rawConfig.value(QStringLiteral("folders")).toArray());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QNetworkReply::OperationCanceledError:
|
case QNetworkReply::OperationCanceledError:
|
||||||
|
@ -1124,7 +1130,10 @@ void SyncthingConnection::readStatus()
|
||||||
emitMyIdChanged(replyDoc.object().value(QStringLiteral("myID")).toString());
|
emitMyIdChanged(replyDoc.object().value(QStringLiteral("myID")).toString());
|
||||||
// other values are currently not interesting
|
// other values are currently not interesting
|
||||||
m_hasStatus = true;
|
m_hasStatus = true;
|
||||||
concludeReadingConfigAndStatus();
|
|
||||||
|
if (m_keepPolling) {
|
||||||
|
concludeReadingConfigAndStatus();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QNetworkReply::OperationCanceledError:
|
case QNetworkReply::OperationCanceledError:
|
||||||
|
|
|
@ -152,6 +152,16 @@ public Q_SLOTS:
|
||||||
void shutdown();
|
void shutdown();
|
||||||
void considerAllNotificationsRead();
|
void considerAllNotificationsRead();
|
||||||
|
|
||||||
|
void requestConfig();
|
||||||
|
void requestStatus();
|
||||||
|
void requestErrors();
|
||||||
|
void requestConnections();
|
||||||
|
void requestClearingErrors();
|
||||||
|
void requestDirStatistics();
|
||||||
|
void requestDirStatus(const QString &dirId);
|
||||||
|
void requestCompletion(const QString &devId, const QString &dirId);
|
||||||
|
void requestDeviceStatistics();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void newConfig(const QJsonObject &config);
|
void newConfig(const QJsonObject &config);
|
||||||
void newDirs(const std::vector<SyncthingDir> &dirs);
|
void newDirs(const std::vector<SyncthingDir> &dirs);
|
||||||
|
@ -177,16 +187,6 @@ Q_SIGNALS:
|
||||||
void shutdownTriggered();
|
void shutdownTriggered();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void requestConfig();
|
|
||||||
void requestStatus();
|
|
||||||
void requestConnections();
|
|
||||||
void requestErrors();
|
|
||||||
void requestClearingErrors();
|
|
||||||
void requestDirStatistics();
|
|
||||||
void requestDirStatus(const QString &dirId);
|
|
||||||
void requestCompletion(const QString &devId, const QString &dirId);
|
|
||||||
|
|
||||||
void requestDeviceStatistics();
|
|
||||||
void requestEvents();
|
void requestEvents();
|
||||||
void abortAllRequests();
|
void abortAllRequests();
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,17 @@ private:
|
||||||
*/
|
*/
|
||||||
template <typename Signal, typename Handler> class SignalInfo {
|
template <typename Signal, typename Handler> class SignalInfo {
|
||||||
public:
|
public:
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a dummy SignalInfo which will never be considered emitted.
|
||||||
|
*/
|
||||||
|
SignalInfo()
|
||||||
|
: m_sender(nullptr)
|
||||||
|
, m_signal(nullptr)
|
||||||
|
, m_correctSignalEmitted(nullptr)
|
||||||
|
, m_signalEmitted(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a SignalInfo with handler and automatically connects the handler to the signal.
|
* \brief Constructs a SignalInfo with handler and automatically connects the handler to the signal.
|
||||||
* \param sender Specifies the object which will emit \a signal.
|
* \param sender Specifies the object which will emit \a signal.
|
||||||
|
@ -182,6 +193,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void connectToLoop(QEventLoop *loop) const
|
void connectToLoop(QEventLoop *loop) const
|
||||||
{
|
{
|
||||||
|
if (!m_sender) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QObject::disconnect(m_loopConnection);
|
QObject::disconnect(m_loopConnection);
|
||||||
m_loopConnection = QObject::connect(m_sender, m_signal, loop, &QEventLoop::quit, Qt::DirectConnection);
|
m_loopConnection = QObject::connect(m_sender, m_signal, loop, &QEventLoop::quit, Qt::DirectConnection);
|
||||||
#ifndef SYNCTHINGTESTHELPER_FOR_CLI
|
#ifndef SYNCTHINGTESTHELPER_FOR_CLI
|
||||||
|
@ -205,12 +219,28 @@ private:
|
||||||
* \brief Constructs a new SignalInfo.
|
* \brief Constructs a new SignalInfo.
|
||||||
*/
|
*/
|
||||||
template <typename Signal, typename Handler>
|
template <typename Signal, typename Handler>
|
||||||
inline SignalInfo<Signal, Handler> signalInfo(typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal,
|
inline auto signalInfo(typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal, const Handler &handler = Handler(),
|
||||||
const Handler &handler = Handler(), bool *correctSignalEmitted = nullptr)
|
bool *correctSignalEmitted = nullptr)
|
||||||
{
|
{
|
||||||
return SignalInfo<Signal, Handler>(sender, signal, handler, correctSignalEmitted);
|
return SignalInfo<Signal, Handler>(sender, signal, handler, correctSignalEmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new SignalInfo.
|
||||||
|
*/
|
||||||
|
template <typename Signal> inline auto signalInfo(typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal)
|
||||||
|
{
|
||||||
|
return SignalInfo<Signal, std::function<void(void)>>(sender, signal, std::function<void(void)>(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new SignalInfo.
|
||||||
|
*/
|
||||||
|
inline auto dummySignalInfo()
|
||||||
|
{
|
||||||
|
return SignalInfo<decltype(&QObject::destroyed), std::function<void(void)>>();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Connects the specified signal infos the \a loop via SignalInfo::connectToLoop().
|
* \brief Connects the specified signal infos the \a loop via SignalInfo::connectToLoop().
|
||||||
*/
|
*/
|
||||||
|
@ -275,13 +305,31 @@ inline QByteArray failedSignalNames(const SignalInfo &firstSignalInfo, const Sig
|
||||||
* \arg signalInfos Specifies the signals to wait for.
|
* \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
|
* \throws Fails if not all signals have been emitted in at least \a timeout milliseconds or when at least one of the
|
||||||
* required connections can not be established.
|
* required connections can not be established.
|
||||||
|
* \returns Returns true if all \a signalInfos have been omitted before the \a timeout exceeded.
|
||||||
*/
|
*/
|
||||||
template <typename Action, typename... SignalInfos> void waitForSignals(Action action, int timeout, const SignalInfos &... signalInfos)
|
template <typename Action, typename... SignalInfos> bool waitForSignals(Action action, int timeout, const SignalInfos &... signalInfos)
|
||||||
|
{
|
||||||
|
return waitForSignalsOrFail(action, timeout, dummySignalInfo(), signalInfos...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \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 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
|
||||||
|
* required connections can not be established.
|
||||||
|
* \returns Returns true if all \a signalInfos have been omitted before \a failure as been emitted or the \a timeout exceeded.
|
||||||
|
*/
|
||||||
|
template <typename Action, typename SignalInfo, typename... SignalInfos>
|
||||||
|
bool waitForSignalsOrFail(Action action, int timeout, const SignalInfo &failure, const SignalInfos &... signalInfos)
|
||||||
{
|
{
|
||||||
// use loop for waiting
|
// use loop for waiting
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
|
|
||||||
// connect all signals to loop so loop is interrupted when one of the signals is emitted
|
// connect all signals to loop so loop is interrupted when one of the signals is emitted
|
||||||
|
connectSignalInfosToLoop(&loop, failure);
|
||||||
connectSignalInfosToLoop(&loop, signalInfos...);
|
connectSignalInfosToLoop(&loop, signalInfos...);
|
||||||
|
|
||||||
// perform specified action
|
// perform specified action
|
||||||
|
@ -289,7 +337,10 @@ template <typename Action, typename... SignalInfos> void waitForSignals(Action a
|
||||||
|
|
||||||
// no reason to enter event loop when all signals have been emitted directly
|
// no reason to enter event loop when all signals have been emitted directly
|
||||||
if (checkWhetherAllSignalsEmitted(signalInfos...)) {
|
if (checkWhetherAllSignalsEmitted(signalInfos...)) {
|
||||||
return;
|
return true;
|
||||||
|
}
|
||||||
|
if (checkWhetherAllSignalsEmitted(failure)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also connect and start a timer if a timeout has been specified
|
// also connect and start a timer if a timeout has been specified
|
||||||
|
@ -302,19 +353,26 @@ template <typename Action, typename... SignalInfos> void waitForSignals(Action a
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec event loop as long as the right signal has not been emitted yet and there is still time
|
// exec event loop as long as the right signal has not been emitted yet and there is still time
|
||||||
bool allSignalsEmitted = false;
|
bool allSignalsEmitted = false, failureEmitted = false;
|
||||||
do {
|
do {
|
||||||
loop.exec();
|
loop.exec();
|
||||||
} while (!(allSignalsEmitted = checkWhetherAllSignalsEmitted(signalInfos...)) && (!timeout || timer.isActive()));
|
} while (!(failureEmitted = checkWhetherAllSignalsEmitted(failure)) && !(allSignalsEmitted = checkWhetherAllSignalsEmitted(signalInfos...))
|
||||||
|
&& (!timeout || timer.isActive()));
|
||||||
|
|
||||||
// check whether a timeout occured
|
// check whether a timeout occured
|
||||||
|
const bool timeoutFailed(!allSignalsEmitted && timeout && !timer.isActive());
|
||||||
#ifndef SYNCTHINGTESTHELPER_FOR_CLI
|
#ifndef SYNCTHINGTESTHELPER_FOR_CLI
|
||||||
if (!allSignalsEmitted && timeout && !timer.isActive()) {
|
if (failureEmitted) {
|
||||||
|
CPPUNIT_FAIL(
|
||||||
|
argsToString("Signal(s) ", failedSignalNames(signalInfos...).data(), " has/have not emmitted before ", failure.signalName().data(), '.'));
|
||||||
|
} else if (timeoutFailed) {
|
||||||
CPPUNIT_FAIL(argsToString("Signal(s) ", failedSignalNames(signalInfos...).data(), " has/have not emmitted within at least ", timer.interval(),
|
CPPUNIT_FAIL(argsToString("Signal(s) ", failedSignalNames(signalInfos...).data(), " has/have not emmitted within at least ", timer.interval(),
|
||||||
" ms.", timeoutFactor != 1.0 ? argsToString(" (original timeout: ", timeout, " ms)") : std::string()));
|
" ms.", timeoutFactor != 1.0 ? argsToString(" (original timeout: ", timeout, " ms)") : std::string()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return !failureEmitted && !timeoutFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace TestUtilities
|
} // namespace TestUtilities
|
||||||
|
|
||||||
#endif // SYNCTHINGTESTHELPER_H
|
#endif // SYNCTHINGTESTHELPER_H
|
||||||
|
|
Loading…
Reference in New Issue