From c7d8b3a40765cb44cb5f3b993323b39be2b73230 Mon Sep 17 00:00:00 2001 From: Holden Date: Sun, 14 Apr 2024 13:12:20 -0400 Subject: [PATCH] Use QCommandLineParser --- src/CmdLineOptParser.cc | 120 +++++++++++++++++++++++------------ src/CmdLineOptParser.h | 37 +++++++---- src/QGCApplication.cc | 67 ++++++++++++------- src/QGCApplication.h | 2 +- src/main.cc | 59 +++++------------ test/qgcunittest/UnitTest.cc | 2 +- test/qgcunittest/UnitTest.h | 2 +- 7 files changed, 167 insertions(+), 122 deletions(-) diff --git a/src/CmdLineOptParser.cc b/src/CmdLineOptParser.cc index cc387868a0c9..5327408a0555 100644 --- a/src/CmdLineOptParser.cc +++ b/src/CmdLineOptParser.cc @@ -14,45 +14,85 @@ #include "CmdLineOptParser.h" -#include - -/// @brief Implements a simple command line parser which sets booleans to true if the option is found. -void ParseCmdLineOptions(int& argc, ///< count of arguments in argv - char* argv[], ///< command line arguments - CmdLineOpt_t* prgOpts, ///< command line options - size_t cOpts, ///< count of command line options - bool removeParsedOptions) ///< true: remove parsed option from argc/argv +CommandLineParseResult parseCommandLine(QCommandLineParser &parser) { - // Start with all options off - for (size_t iOption=0; iOptionnameServer = QHostAddress(nameserver); + // if (query->nameServer.isNull() + // || query->nameServer.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { + // return { Status::Error, + // u"Bad nameserver address: %1"_s.arg(nameserver) }; + // } + // } + + // if (parser.isSet(typeOption)) { + // const QString typeParameter = parser.value(typeOption); + // if (std::optional type = typeFromParameter(typeParameter)) + // query->type = *type; + // else + // return { Status::Error, u"Bad record type: %1"_s.arg(typeParameter) }; + // } + + // const QStringList positionalArguments = parser.positionalArguments(); + // if (positionalArguments.isEmpty()) + // return { Status::Error, u"Argument 'name' missing."_s }; + // if (positionalArguments.size() > 1) + // return { Status::Error, u"Several 'name' arguments specified."_s }; + // query->name = positionalArguments.first(); + + return { Status::Ok }; } diff --git a/src/CmdLineOptParser.h b/src/CmdLineOptParser.h index bca3c3d52602..94d8059745b1 100644 --- a/src/CmdLineOptParser.h +++ b/src/CmdLineOptParser.h @@ -14,19 +14,30 @@ #pragma once -#include -#include +#include -/// @brief Structure used to pass command line options to the ParseCmdLineOptions function. -typedef struct { - const char* optionStr; ///< Command line option, for example "--foo" - bool* optionFound; ///< If option is found this variable will be set to true - QString* optionArg; ///< Option has additional argument, form is option:arg -} CmdLineOpt_t; +struct CommandLineParseResult +{ + enum class Status { + Ok, + Error, + VersionRequested, + HelpRequested + }; + Status statusCode = Status::Ok; + std::optional errorString = std::nullopt; -void ParseCmdLineOptions(int& argc, - char* argv[], - CmdLineOpt_t* prgOpts, - size_t cOpts, - bool removeParsedOptions); + bool runningUnitTests = false; + QStringList unitTests = {}; + bool stressUnitTests = false; + int stressUnitTestsCount = 0; + bool fClearSettingsOptions = false; + bool fClearCache = false; + bool logging = false; + QString loggingOptions = ""; + bool fakeMobile = false; + bool logOutput = false; + bool quietWindowsAsserts = false; +}; +CommandLineParseResult parseCommandLine(QCommandLineParser &parser); diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 968a6d646919..b609f15c1d72 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -184,13 +184,18 @@ static QObject* shapeFileHelperSingletonFactory(QQmlEngine*, QJSEngine*) return new ShapeFileHelper; } -QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) - : QApplication (argc, argv) - , _runningUnitTests (unitTesting) +QGCApplication::QGCApplication(int &argc, char* argv[]) + : QApplication(argc, argv) { _app = this; _msecsElapsedTime.start(); + (void) _parseCommandLine(); + // TODO: put in main and rearrange following code into init + // if(app->parseCommands()) { + // app->exec(); + // } + #ifdef Q_OS_LINUX #ifndef __mobile__ if (!_runningUnitTests) { @@ -211,24 +216,6 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) // Setup for network proxy support QNetworkProxyFactory::setUseSystemConfiguration(true); - // Parse command line options - - bool fClearSettingsOptions = false; // Clear stored settings - bool fClearCache = false; // Clear parameter/airframe caches - bool logging = false; // Turn on logging - QString loggingOptions; - - CmdLineOpt_t rgCmdLineOptions[] = { - { "--clear-settings", &fClearSettingsOptions, nullptr }, - { "--clear-cache", &fClearCache, nullptr }, - { "--logging", &logging, &loggingOptions }, - { "--fake-mobile", &_fakeMobile, nullptr }, - { "--log-output", &_logOutput, nullptr }, - // Add additional command line option flags here - }; - - ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false); - // Set up timer for delayed missing fact display _missingParamsDelayedDisplayTimer.setSingleShot(true); _missingParamsDelayedDisplayTimer.setInterval(_missingParamsDelayedDisplayTimerTimeout); @@ -302,8 +289,10 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) parameter.remove(); } - // Set up our logging filters - QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(loggingOptions); + if(logging) { + // Set up our logging filters + QGCLoggingCategoryRegister::instance()->setFilterRulesFromSettings(loggingOptions); + } // Initialize Bluetooth #ifdef QGC_ENABLE_BLUETOOTH @@ -336,6 +325,38 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) _checkForNewVersion(); } +bool QGCApplication::_parseCommandLine() +{ + QCommandLineParser parser; + // const CommandLineParseResult cmdLineResult = parseCommandLine(&parser); + // _cmdLineResult = parseCommandLine(&parser); + + switch (parseResult.statusCode) { + case Status::Ok: + _runningUnitTests = cmdLineResult.runningUnitTests; + _fakeMobile = cmdLineResult.fakeMobile; + _logOutput = cmdLineResult.logOutput; + break; + + case Status::Error: + std::fputs(qPrintable(parseResult.errorString.value_or(u"Unknown error occurred"_s)), + stderr); + std::fputs("\n\n", stderr); + std::fputs(qPrintable(parser.helpText()), stderr); + return false; + + case Status::VersionRequested: + parser.showVersion(); + break; + + case Status::HelpRequested: + parser.showHelp(); + break; + } + + return true; +} + void QGCApplication::_exitWithError(QString errorMessage) { _error = true; diff --git a/src/QGCApplication.h b/src/QGCApplication.h index b15e63706f31..3d8bf02e2b06 100644 --- a/src/QGCApplication.h +++ b/src/QGCApplication.h @@ -57,7 +57,7 @@ class QGCApplication : public QApplication { Q_OBJECT public: - QGCApplication(int &argc, char* argv[], bool unitTesting); + QGCApplication(int &argc, char* argv[]); ~QGCApplication(); /// @brief Sets the persistent flag to delete all settings the next time QGroundControl is started. diff --git a/src/main.cc b/src/main.cc index c1048790e9cb..3598e2326f17 100644 --- a/src/main.cc +++ b/src/main.cc @@ -46,7 +46,6 @@ #endif #ifdef QT_DEBUG - #include "CmdLineOptParser.h" #ifdef Q_OS_WIN #include #endif @@ -201,51 +200,13 @@ int main(int argc, char *argv[]) Q_IMPORT_PLUGIN(QGeoServiceProviderFactoryQGC) - bool runUnitTests = false; // Run unit tests - -#ifdef QT_DEBUG - // We parse a small set of command line options here prior to QGCApplication in order to handle the ones - // which need to be handled before a QApplication object is started. - - bool stressUnitTests = false; // Stress test unit tests - bool quietWindowsAsserts = false; // Don't let asserts pop dialog boxes - - QString unitTestOptions; - CmdLineOpt_t rgCmdLineOptions[] = { - { "--unittest", &runUnitTests, &unitTestOptions }, - { "--unittest-stress", &stressUnitTests, &unitTestOptions }, - { "--no-windows-assert-ui", &quietWindowsAsserts, nullptr }, - // Add additional command line option flags here - }; - - ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false); - if (stressUnitTests) { - runUnitTests = true; - } - - if (quietWindowsAsserts) { -#ifdef Q_OS_WIN - _CrtSetReportHook(WindowsCrtReportHook); -#endif - } - -#ifdef Q_OS_WIN - if (runUnitTests) { - // Don't pop up Windows Error Reporting dialog when app crashes. This prevents TeamCity from - // hanging. - DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX); - SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX); - } -#endif -#endif // QT_DEBUG - #ifdef Q_OS_DARWIN // Gstreamer video playback requires OpenGL QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); #endif QQuickStyle::setStyle("Basic"); - QGCApplication* app = new QGCApplication(argc, argv, runUnitTests); + QGCApplication* app = new QGCApplication(argc, argv); Q_CHECK_PTR(app); if(app->isErrorState()) { app->exec(); @@ -269,15 +230,27 @@ int main(int argc, char *argv[]) int exitCode = 0; -#ifdef UNITTEST_BUILD - if (runUnitTests) { +#if defined(QT_DEBUG) && defined(UNITTEST_BUILD) + #ifdef Q_OS_WIN + if (quietWindowsAsserts) { + _CrtSetReportHook(WindowsCrtReportHook); + } + if (app->runningUnitTests()) { + // Don't pop up Windows Error Reporting dialog when app crashes. This prevents TeamCity from + // hanging. + const DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX); + (void) SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX); + } + #endif + + if (app->runningUnitTests()) { for (int i=0; i < (stressUnitTests ? 20 : 1); i++) { if (!app->_initForUnitTests()) { return -1; } // Run the test - int failures = UnitTest::run(unitTestOptions); + int failures = UnitTest::run(app->unitTests()); if (failures == 0) { qDebug() << "ALL TESTS PASSED"; exitCode = 0; diff --git a/test/qgcunittest/UnitTest.cc b/test/qgcunittest/UnitTest.cc index b4664779db07..550bd527357b 100644 --- a/test/qgcunittest/UnitTest.cc +++ b/test/qgcunittest/UnitTest.cc @@ -63,7 +63,7 @@ QList& UnitTest::_testList(void) return tests; } -int UnitTest::run(QString& singleTest) +int UnitTest::run(QStringView singleTest) { int ret = 0; diff --git a/test/qgcunittest/UnitTest.h b/test/qgcunittest/UnitTest.h index 66b33e0cc985..8990f226a913 100644 --- a/test/qgcunittest/UnitTest.h +++ b/test/qgcunittest/UnitTest.h @@ -39,7 +39,7 @@ class UnitTest : public QObject /// @brief Called to run all the registered unit tests /// @param singleTest Name of test to just run a single test - static int run(QString& singleTest); + static int run(QStringView singleTest); /// @brief Sets up for an expected QGCMessageBox /// @param response Response to take on message box