mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-03 07:35:48 +08:00
Ref T195, application restart functions
* allow to get current arguments joined with new ones * removed old inheritedArguments function * unregisterAsRunning (for restart) * restart function
This commit is contained in:
@@ -48,9 +48,11 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QSslSocket>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
#include <QStringList>
|
||||
#include <QTemporaryDir>
|
||||
#include <QThread>
|
||||
#include <QTime>
|
||||
@@ -164,7 +166,7 @@ namespace BlackCore
|
||||
connect(m_setupReader.data(), &CSetupReader::distributionInfoAvailable, this, &CApplication::distributionInfoAvailable, Qt::QueuedConnection);
|
||||
connect(m_setupReader.data(), &CSetupReader::successfullyReadSharedUrl, m_networkWatchDog.data(), &CNetworkWatchdog::setWorkingSharedUrl, Qt::QueuedConnection);
|
||||
|
||||
m_parser.addOptions(m_setupReader->getCmdLineOptions()); // add options from reader
|
||||
this->addParserOptions(m_setupReader->getCmdLineOptions()); // add options from reader
|
||||
|
||||
// startup done
|
||||
connect(this, &CApplication::startUpCompleted, this, &CApplication::onStartUpCompleted, Qt::QueuedConnection);
|
||||
@@ -177,6 +179,7 @@ namespace BlackCore
|
||||
|
||||
bool CApplication::registerAsRunning()
|
||||
{
|
||||
//! \fixme KB 2017-11 maybe this code can be encapsulated somewhere
|
||||
CApplicationInfoList apps = CApplication::getRunningApplications();
|
||||
const CApplicationInfo myself = CApplication::instance()->getApplicationInfo();
|
||||
if (!apps.contains(myself)) { apps.insert(myself); }
|
||||
@@ -185,6 +188,18 @@ namespace BlackCore
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CApplication::unregisterAsRunning()
|
||||
{
|
||||
//! \fixme KB 2017-11 maybe this code can be encapsulated somewhere
|
||||
CApplicationInfoList apps = CApplication::getRunningApplications();
|
||||
const CApplicationInfo myself = CApplication::instance()->getApplicationInfo();
|
||||
if (!apps.contains(myself)) { return true; }
|
||||
apps.remove(myself);
|
||||
const bool ok = CFileUtils::writeStringToLockedFile(apps.toJsonString(), CFileUtils::appendFilePaths(swiftDataRoot(), "apps.json"));
|
||||
if (!ok) { CLogMessage(static_cast<CApplication *>(nullptr)).error("Failed to write to application list file"); }
|
||||
return ok;
|
||||
}
|
||||
|
||||
int CApplication::exec()
|
||||
{
|
||||
Q_ASSERT_X(instance(), Q_FUNC_INFO, "missing application");
|
||||
@@ -192,11 +207,12 @@ namespace BlackCore
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
||||
void CApplication::restartApplication()
|
||||
void CApplication::restartApplication(const QStringList &newArguments, const QStringList &removeArguments)
|
||||
{
|
||||
this->gracefulShutdown();
|
||||
CApplication::unregisterAsRunning();
|
||||
const QString prg = QCoreApplication::applicationFilePath();
|
||||
const QStringList args = CApplication::arguments();
|
||||
const QStringList args = this->argumentsJoined(newArguments, removeArguments);
|
||||
this->gracefulShutdown();
|
||||
QProcess::startDetached(prg, args);
|
||||
this->exit(0);
|
||||
}
|
||||
@@ -208,7 +224,7 @@ namespace BlackCore
|
||||
|
||||
CApplicationInfo CApplication::getApplicationInfo() const
|
||||
{
|
||||
CApplicationInfo::ApplicationMode mode;
|
||||
CApplicationInfo::ApplicationMode mode = CApplicationInfo::None;
|
||||
if (isRunningInDeveloperEnvironment()) { mode |= CApplicationInfo::Developer; }
|
||||
if (CBuildConfig::isDevBranch()) { mode |= CApplicationInfo::BetaTest; }
|
||||
return { CApplication::getSwiftApplication(), mode, QCoreApplication::applicationFilePath(), CBuildConfig::getVersionString(), CProcessInfo::currentProcess() };
|
||||
@@ -298,10 +314,19 @@ namespace BlackCore
|
||||
static const QString launcher = CApplication::getExecutableForApplication(CApplicationInfo::Application::Laucher);
|
||||
if (launcher.isEmpty() || CApplication::isApplicationRunning(CApplicationInfo::Laucher)) { return false; }
|
||||
|
||||
const QStringList args = this->inheritedArguments(true);
|
||||
const QStringList args = this->argumentsJoined({}, { "--dbus" });
|
||||
return QProcess::startDetached(launcher, args);
|
||||
}
|
||||
|
||||
bool CApplication::startLauncherAndQuit()
|
||||
{
|
||||
const bool started = CApplication::startLauncher();
|
||||
if (!started) { return false; }
|
||||
this->gracefulShutdown();
|
||||
CApplication::exit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CApplication::isUnitTest() const
|
||||
{
|
||||
return m_unitTest;
|
||||
@@ -752,6 +777,34 @@ namespace BlackCore
|
||||
return QCoreApplication::arguments();
|
||||
}
|
||||
|
||||
int CApplication::indexOfCommandLineOption(const QCommandLineOption &option, const QStringList &args)
|
||||
{
|
||||
const QStringList names = option.names();
|
||||
if (names.isEmpty() || args.isEmpty()) { return -1; }
|
||||
int i = -1;
|
||||
for (const QString &arg : args)
|
||||
{
|
||||
i++;
|
||||
QString a;
|
||||
if (arg.startsWith("--")) { a = arg.mid(2); }
|
||||
else if (arg.startsWith("-")) { a = arg.mid(1); }
|
||||
else { continue; }
|
||||
|
||||
if (names.contains(a, Qt::CaseInsensitive)) { return i; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CApplication::argumentsWithoutOption(const QCommandLineOption &option, QStringList &args)
|
||||
{
|
||||
const int index = indexOfCommandLineOption(option, args);
|
||||
if (index < 0) { return; }
|
||||
|
||||
// remove argument and its value
|
||||
args.removeAt(index);
|
||||
if (!option.valueName().isEmpty() && args.size() > index) { args.removeAt(index); }
|
||||
}
|
||||
|
||||
void CApplication::processEventsFor(int milliseconds)
|
||||
{
|
||||
// sApp check allows to use in test cases without sApp
|
||||
@@ -857,6 +910,8 @@ namespace BlackCore
|
||||
m_parser.setApplicationDescription(m_applicationName);
|
||||
m_cmdHelp = m_parser.addHelpOption();
|
||||
m_cmdVersion = m_parser.addVersionOption();
|
||||
m_allOptions.append(m_cmdHelp);
|
||||
m_allOptions.append(m_cmdVersion);
|
||||
|
||||
// dev. system
|
||||
m_cmdDevelopment = QCommandLineOption({ "dev", "development" },
|
||||
@@ -1067,11 +1122,13 @@ namespace BlackCore
|
||||
|
||||
bool CApplication::addParserOption(const QCommandLineOption &option)
|
||||
{
|
||||
m_allOptions.append(option);
|
||||
return m_parser.addOption(option);
|
||||
}
|
||||
|
||||
bool CApplication::addParserOptions(const QList<QCommandLineOption> &options)
|
||||
{
|
||||
m_allOptions.append(options);
|
||||
return m_parser.addOptions(options);
|
||||
}
|
||||
|
||||
@@ -1090,16 +1147,10 @@ namespace BlackCore
|
||||
|
||||
QString CApplication::getCmdDBusAddressValue() const
|
||||
{
|
||||
if (this->isParserOptionSet(m_cmdDBusAddress))
|
||||
{
|
||||
const QString v(this->getParserValue(m_cmdDBusAddress));
|
||||
const QString dBusAddress(CDBusServer::normalizeAddress(v));
|
||||
return dBusAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (!this->isParserOptionSet(m_cmdDBusAddress)) { return ""; }
|
||||
const QString v(this->getParserValue(m_cmdDBusAddress));
|
||||
const QString dBusAddress(CDBusServer::normalizeAddress(v));
|
||||
return dBusAddress;
|
||||
}
|
||||
|
||||
QString CApplication::getCmdSwiftPrivateSharedDir() const
|
||||
@@ -1139,7 +1190,7 @@ namespace BlackCore
|
||||
// checks
|
||||
if (CBuildConfig::isLifetimeExpired())
|
||||
{
|
||||
this->cmdLineErrorMessage("Program exired " + CBuildConfig::getEol().toString());
|
||||
this->cmdLineErrorMessage("Program expired " + CBuildConfig::getEol().toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1216,18 +1267,6 @@ namespace BlackCore
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList CApplication::inheritedArguments(bool withVatlibArgs) const
|
||||
{
|
||||
QStringList args;
|
||||
if (this->isSet(m_cmdDevelopment))
|
||||
{
|
||||
args.append("--" + m_cmdDevelopment.names().first());
|
||||
args.append("true");
|
||||
}
|
||||
if (withVatlibArgs) { args.append(CNetworkVatlib::inheritedArguments()); }
|
||||
return args;
|
||||
}
|
||||
|
||||
QString CApplication::cmdLineArgumentsAsString(bool withExecutable)
|
||||
{
|
||||
QStringList args = QCoreApplication::arguments();
|
||||
@@ -1247,6 +1286,40 @@ namespace BlackCore
|
||||
printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), qPrintable(QCoreApplication::applicationVersion()));
|
||||
}
|
||||
|
||||
QStringList CApplication::argumentsJoined(const QStringList &newArguments, const QStringList &removeArguments) const
|
||||
{
|
||||
QStringList joinedArguments = CApplication::arguments();
|
||||
QStringList newArgumentsChecked = newArguments;
|
||||
|
||||
// remove the executable argument if it exists at position 0
|
||||
if (!joinedArguments.isEmpty() && !joinedArguments.at(0).startsWith("-")) { joinedArguments.removeFirst(); } // was cmd line argument
|
||||
if (!newArgumentsChecked.isEmpty() && !newArgumentsChecked.at(0).startsWith("-")) { newArgumentsChecked.removeFirst(); } // was cmd line argument
|
||||
|
||||
// remove all values before checking options
|
||||
static const QRegularExpression regExp("^-");
|
||||
QStringList toBeRemoved(newArgumentsChecked.filter(regExp));
|
||||
toBeRemoved.append(removeArguments.filter(regExp));
|
||||
toBeRemoved.append("--installer");
|
||||
toBeRemoved.removeDuplicates();
|
||||
|
||||
if (!joinedArguments.isEmpty() && !toBeRemoved.isEmpty())
|
||||
{
|
||||
// remove all options from removeArguments
|
||||
// consider alias names, that is why we check on option
|
||||
for (const QCommandLineOption &option : m_allOptions)
|
||||
{
|
||||
const int n = indexOfCommandLineOption(option, toBeRemoved);
|
||||
if (n >= 0)
|
||||
{
|
||||
argumentsWithoutOption(option, joinedArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
joinedArguments.append(newArgumentsChecked);
|
||||
return joinedArguments;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Contexts
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
@@ -144,6 +144,9 @@ namespace BlackCore
|
||||
//! Start the launcher
|
||||
bool startLauncher();
|
||||
|
||||
//! Start the launcher and quit
|
||||
bool startLauncherAndQuit();
|
||||
|
||||
//! Unit test?
|
||||
bool isUnitTest() const;
|
||||
|
||||
@@ -247,12 +250,19 @@ namespace BlackCore
|
||||
QString getTemporaryDirectory() const;
|
||||
|
||||
//! Stop and restart application
|
||||
void restartApplication();
|
||||
void restartApplication(const QStringList &newArguments = {}, const QStringList &removeArguments = {});
|
||||
|
||||
//! Current parameters replaced by new arguments without the cmd line argument
|
||||
virtual QStringList argumentsJoined(const QStringList &newArguments = {}, const QStringList &removeArguments = {}) const;
|
||||
|
||||
//! Register as running
|
||||
//! \note Normally done automatically when CApplication::exec is called
|
||||
static bool registerAsRunning();
|
||||
|
||||
//! Unregister from running
|
||||
//! \note Normally done automatically, needed for restart
|
||||
static bool unregisterAsRunning();
|
||||
|
||||
//! Run event loop
|
||||
static int exec();
|
||||
|
||||
@@ -264,6 +274,7 @@ namespace BlackCore
|
||||
|
||||
//! Process all events for some time
|
||||
//! \remark unlike QCoreApplication::processEvents this will spend at least the given time in the function, using QThread::msleep
|
||||
//! \remark using processEventsFor can lead to undesired behaviour: A function may be called again before it is finished, even with only one thread
|
||||
//! \sa BlackMisc::CEventLoop
|
||||
static void processEventsFor(int milliseconds);
|
||||
|
||||
@@ -326,9 +337,6 @@ namespace BlackCore
|
||||
//! Display error message
|
||||
virtual bool cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs, bool retry = false) const;
|
||||
|
||||
//! Arguments to be passed to another swift appplication
|
||||
QStringList inheritedArguments(bool withVatlibArgs = true) const;
|
||||
|
||||
//! cmd line arguments as string
|
||||
virtual QString cmdLineArgumentsAsString(bool withExecutable = true);
|
||||
//! @}
|
||||
@@ -408,7 +416,6 @@ namespace BlackCore
|
||||
|
||||
// ------------------------- network -----------------------------------------------
|
||||
|
||||
public:
|
||||
static constexpr int NoRedirects = -1; //!< network request not allowing redirects
|
||||
static constexpr int NoLogRequestId = -1; //!< network request without logging
|
||||
static constexpr int DefaultMaxRedirects = 2; //!< network request, default for max.redirects
|
||||
@@ -503,6 +510,12 @@ namespace BlackCore
|
||||
//! Display version message
|
||||
virtual void cmdLineVersionMessage() const;
|
||||
|
||||
//! Is the command line option represented in the given arguments?
|
||||
static int indexOfCommandLineOption(const QCommandLineOption &option, const QStringList &args = CApplication::arguments());
|
||||
|
||||
//! Arguments without that given option
|
||||
static void argumentsWithoutOption(const QCommandLineOption &option, QStringList &args);
|
||||
|
||||
//! Can be used to parse specialized arguments
|
||||
virtual bool parsingHookIn() { return true; }
|
||||
|
||||
@@ -534,6 +547,7 @@ namespace BlackCore
|
||||
static void registerMetadata();
|
||||
|
||||
// cmd parsing
|
||||
QList<QCommandLineOption> m_allOptions; //!< all registered options
|
||||
QCommandLineParser m_parser; //!< cmd parser
|
||||
QCommandLineOption m_cmdHelp {"help"}; //!< help option
|
||||
QCommandLineOption m_cmdVersion {"version"}; //!< version option
|
||||
|
||||
@@ -545,12 +545,12 @@ namespace BlackCore
|
||||
return m_interimPositionReceivers;
|
||||
}
|
||||
|
||||
QStringList CNetworkVatlib::inheritedArguments()
|
||||
QStringList CNetworkVatlib::vatlibArguments()
|
||||
{
|
||||
QStringList args;
|
||||
int id = 0;
|
||||
QString key;
|
||||
if (!getCmdLineClientIdAndKey(id, key)) return args;
|
||||
if (!getCmdLineClientIdAndKey(id, key)) { return args; }
|
||||
args << "--idAndKey";
|
||||
args << sApp->getParserValue("clientIdAndKey"); // as typed in
|
||||
return args;
|
||||
@@ -723,6 +723,11 @@ namespace BlackCore
|
||||
|
||||
bool CNetworkVatlib::getCmdLineClientIdAndKey(int &id, QString &key)
|
||||
{
|
||||
// init values
|
||||
id = 0;
|
||||
key = "";
|
||||
|
||||
// split parser values
|
||||
const QString clientIdAndKey = sApp->getParserValue("clientIdAndKey").toLower();
|
||||
if (clientIdAndKey.isEmpty() || !clientIdAndKey.contains(':')) { return false; }
|
||||
const auto stringList = clientIdAndKey.split(':');
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace BlackCore
|
||||
//! @}
|
||||
|
||||
//! Arguments to be passed to another swift appplication
|
||||
static QStringList inheritedArguments();
|
||||
static QStringList vatlibArguments();
|
||||
|
||||
//! \name Weather functions
|
||||
//! @{
|
||||
|
||||
Reference in New Issue
Block a user