Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmdlineargs: Error handling and translation #4170

Merged
merged 4 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/coreservices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ CoreServices::CoreServices(const CmdlineArgs& args, QApplication* pApp)
mixxx::Time::start();
ScopedTimer t("CoreServices::CoreServices");
// All this here is running without without start up screen
// Defere long initialisations to CoreServices::initialize() which is
// called after the GUI is initalized
// Defer long initializations to CoreServices::initialize() which is
// called after the GUI is initialized
initializeSettings();
initializeLogging();
// Only record stats in developer mode.
Expand Down
2 changes: 2 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ constexpr int kParseCmdlineArgsErrorExitCode = 2;
int runMixxx(MixxxApplication* pApp, const CmdlineArgs& args) {
const auto pCoreServices = std::make_shared<mixxx::CoreServices>(args, pApp);

CmdlineArgs::Instance().parseForUserFeedback();

MixxxMainWindow mainWindow(pApp, pCoreServices);
pApp->installEventFilter(&mainWindow);

Expand Down
152 changes: 91 additions & 61 deletions src/util/cmdlineargs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "config.h"
#include "defs_urls.h"
#include "sources/soundsourceproxy.h"
#include "util/assert.h"

CmdlineArgs::CmdlineArgs()
: m_startInFullscreen(false), // Initialize vars
Expand All @@ -24,6 +25,7 @@ CmdlineArgs::CmdlineArgs()
m_debugAssertBreak(false),
m_settingsPathSet(false),
m_useColors(false),
m_hasUserFeedback(false),
m_logLevel(mixxx::kLogLevelDefault),
m_logFlushLevel(mixxx::kLogFlushLevelDefault),
// We are not ready to switch to XDG folders under Linux, so keeping $HOME/.mixxx as preferences folder. see lp:1463273
Expand Down Expand Up @@ -73,39 +75,54 @@ bool CmdlineArgs::parse(int argc, char** argv) {
for (int a = 0; a < argc; ++a) {
arguments << QString::fromLocal8Bit(argv[a]);
}
return parse(arguments, false);
}

void CmdlineArgs::parseForUserFeedback() {
DEBUG_ASSERT(QCoreApplication::instance());
if (!m_hasUserFeedback) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition seems to be wrong or I misunderstand the purpose/naming of the boolean.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need only execute the second run when the first run has produced user feedback, otherwise we can skip the second run. I am happy to rename the variable if you have a suggestion.

Copy link
Contributor

@uklotzde uklotzde Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_requiresUserFeedback or m_needsUserFeedback? German: "erfordert"

Copy link
Member Author

@daschuer daschuer Aug 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be read as if we require feedback from the user.
How about m_parseForUserFeedbackRequired?

return;
}
parse(QCoreApplication::arguments(), true);
}

bool CmdlineArgs::parse(const QStringList& arguments, bool forUserFeedback) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add enum class ParseMode instead of using a boolean.

QCommandLineParser parser;
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);

parser.setApplicationDescription(
QCoreApplication::translate("CmdlineArgs",
"Mixxx is an open source DJ software. For more "
"information, see: ") +
MIXXX_MANUAL_COMMANDLINEOPTIONS_URL);

if (forUserFeedback) {
parser.setApplicationDescription(
QCoreApplication::translate("CmdlineArgs",
"Mixxx is an open source DJ software. For more "
"information, see: ") +
MIXXX_MANUAL_COMMANDLINEOPTIONS_URL);
}
// add options
const QCommandLineOption fullScreen(
QStringList({QStringLiteral("f"), QStringLiteral("full-screen")}),
QCoreApplication::translate(
"CmdlineArgs", "Starts Mixxx in full-screen mode"));
forUserFeedback ? QCoreApplication::translate(
"CmdlineArgs", "Starts Mixxx in full-screen mode")
: QString());
QCommandLineOption fullScreenDeprecated(QStringLiteral("fullScreen"));
fullScreenDeprecated.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(fullScreen);
parser.addOption(fullScreenDeprecated);

const QCommandLineOption locale(QStringLiteral("locale"),
QCoreApplication::translate("CmdlineArgs",
"Use a custom locale for loading translations. (e.g "
"'fr')"),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Use a custom locale for loading translations. (e.g "
"'fr')")
: QString(),
QStringLiteral("locale"));
parser.addOption(locale);

// An option with a value
const QCommandLineOption settingsPath(QStringLiteral("settings-path"),
QCoreApplication::translate("CmdlineArgs",
"Top-level directory where Mixxx should look for settings. "
"Default is:") +
getSettingsPath(),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Top-level directory where Mixxx should look for settings. "
"Default is:") +
getSettingsPath()
: QString(),
QStringLiteral("path"));
QCommandLineOption settingsPathDeprecated(
QStringLiteral("settingsPath"));
Expand All @@ -115,10 +132,11 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(settingsPathDeprecated);

QCommandLineOption resourcePath(QStringLiteral("resource-path"),
QCoreApplication::translate("CmdlineArgs",
"Top-level directory where Mixxx should look for its "
"resource files such as MIDI mappings, overriding the "
"default installation location."),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Top-level directory where Mixxx should look for its "
"resource files such as MIDI mappings, overriding the "
"default installation location.")
: QString(),
QStringLiteral("path"));
QCommandLineOption resourcePathDeprecated(
QStringLiteral("resourcePath"));
Expand All @@ -128,8 +146,9 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(resourcePathDeprecated);

const QCommandLineOption timelinePath(QStringLiteral("timeline-path"),
QCoreApplication::translate("CmdlineArgs",
"Path the debug statistics time line is written to"),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Path the debug statistics time line is written to")
: QString(),
QStringLiteral("path"));
QCommandLineOption timelinePathDeprecated(
QStringLiteral("timelinePath"), timelinePath.description());
Expand All @@ -139,9 +158,10 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(timelinePathDeprecated);

const QCommandLineOption controllerDebug(QStringLiteral("controller-debug"),
QCoreApplication::translate("CmdlineArgs",
"Causes Mixxx to display/log all of the controller data it "
"receives and script functions it loads"));
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Causes Mixxx to display/log all of the controller data it "
"receives and script functions it loads")
: QString());
QCommandLineOption controllerDebugDeprecated(
QStringList({QStringLiteral("controllerDebug"),
QStringLiteral("midiDebug")}));
Expand All @@ -150,36 +170,40 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(controllerDebugDeprecated);

const QCommandLineOption developer(QStringLiteral("developer"),
QCoreApplication::translate("CmdlineArgs",
"Enables developer-mode. Includes extra log info, stats on "
"performance, and a Developer tools menu."));
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Enables developer-mode. Includes extra log info, stats on "
"performance, and a Developer tools menu.")
: QString());
parser.addOption(developer);

const QCommandLineOption safeMode(QStringLiteral("safe-mode"),
QCoreApplication::translate("CmdlineArgs",
"Enables safe-mode. Disables OpenGL waveforms, and "
"spinning vinyl widgets. Try this option if Mixxx is "
"crashing on startup."));
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Enables safe-mode. Disables OpenGL waveforms, and "
"spinning vinyl widgets. Try this option if Mixxx is "
"crashing on startup.")
: QString());
QCommandLineOption safeModeDeprecated(QStringLiteral("safeMode"), safeMode.description());
safeModeDeprecated.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(safeMode);
parser.addOption(safeModeDeprecated);

const QCommandLineOption color(QStringLiteral("color"),
QCoreApplication::translate("CmdlineArgs",
"[auto|always|never] Use colors on the console output."),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"[auto|always|never] Use colors on the console output.")
: QString(),
QStringLiteral("color"),
QStringLiteral("auto"));
parser.addOption(color);

const QCommandLineOption logLevel(QStringLiteral("log-level"),
QCoreApplication::translate("CmdlineArgs",
"Sets the verbosity of command line logging.\n"
"critical - Critical/Fatal only\n"
"warning - Above + Warnings\n"
"info - Above + Informational messages\n"
"debug - Above + Debug/Developer messages\n"
"trace - Above + Profiling messages"),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Sets the verbosity of command line logging.\n"
"critical - Critical/Fatal only\n"
"warning - Above + Warnings\n"
"info - Above + Informational messages\n"
"debug - Above + Debug/Developer messages\n"
"trace - Above + Profiling messages")
: QString(),
QStringLiteral("level"));
QCommandLineOption logLevelDeprecated(QStringLiteral("logLevel"), logLevel.description());
logLevelDeprecated.setFlags(QCommandLineOption::HiddenFromHelp);
Expand All @@ -188,10 +212,11 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(logLevelDeprecated);

const QCommandLineOption logFlushLevel(QStringLiteral("log-flush-level"),
QCoreApplication::translate("CmdlineArgs",
"Sets the the logging level at which the log buffer is "
"flushed to mixxx.log. <level> is one of the values defined "
"at --log-level above."),
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Sets the the logging level at which the log buffer is "
"flushed to mixxx.log. <level> is one of the values defined "
"at --log-level above.")
: QString(),
QStringLiteral("level"));
QCommandLineOption logFlushLevelDeprecated(
QStringLiteral("logFlushLevel"), logLevel.description());
Expand All @@ -201,9 +226,10 @@ bool CmdlineArgs::parse(int argc, char** argv) {
parser.addOption(logFlushLevelDeprecated);

QCommandLineOption debugAssertBreak(QStringLiteral("debug-assert-break"),
QCoreApplication::translate("CmdlineArgs",
"Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to "
"false. Under a debugger you can continue afterwards."));
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to "
"false. Under a debugger you can continue afterwards.")
: QString());
QCommandLineOption debugAssertBreakDeprecated(
QStringLiteral("debugAssertBreak"), debugAssertBreak.description());
debugAssertBreakDeprecated.setFlags(QCommandLineOption::HiddenFromHelp);
Expand All @@ -214,29 +240,33 @@ bool CmdlineArgs::parse(int argc, char** argv) {
const QCommandLineOption versionOption = parser.addVersionOption();

parser.addPositionalArgument(QStringLiteral("file"),
QCoreApplication::translate("CmdlineArgs",
"Load the specified music file(s) at start-up. Each file "
"you specify will be loaded into the next virtual deck."));
forUserFeedback ? QCoreApplication::translate("CmdlineArgs",
"Load the specified music file(s) at start-up. Each file "
"you specify will be loaded into the next virtual deck.")
: QString());

if (forUserFeedback) {
// We know form the first path, that there will be likely an error message, check again.
// This is not the case if the user uses a Qt internal option that is unknown
// in the first path
puts(""); // Add a blank line to make the parser output more visible
// This call does not return and calls exit() in case of help or an parser error
parser.process(arguments);
return true;
}

// process all arguments
if (!parser.parse(arguments)) {
qWarning() << parser.errorText();
m_hasUserFeedback = true;
}

if (parser.isSet(helpOption)
if (parser.isSet(versionOption) ||
parser.isSet(helpOption)
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|| parser.isSet(QStringLiteral("help-all"))
#endif
) {
// we need to call process here with an initialized QCoreApplication
// otherwise there is no way to print the help-all information
QCoreApplication coreApp(argc, argv);
parser.process(arguments);
return false;
}
if (parser.isSet(versionOption)) {
parser.showVersion();
return false;
m_hasUserFeedback = true;
}

m_startInFullscreen = parser.isSet(fullScreen) || parser.isSet(fullScreenDeprecated);
Expand Down
9 changes: 9 additions & 0 deletions src/util/cmdlineargs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ class CmdlineArgs final {
return cla;
}

//! The original parser that provides the parsed values to Mixxx
//! This can be called before anything else is initialized
bool parse(int argc, char** argv);

//! The optional second run, that provides translated user feedback
//! This requires an initialized QCoreApplication
void parseForUserFeedback();

const QList<QString>& getMusicFiles() const { return m_musicFiles; }
bool getStartInFullscreen() const { return m_startInFullscreen; }
bool getMidiDebug() const { return m_midiDebug; }
Expand All @@ -45,6 +51,8 @@ class CmdlineArgs final {
const QString& getTimelinePath() const { return m_timelinePath; }

private:
bool parse(const QStringList& arguments, bool forUserFeedback);

QList<QString> m_musicFiles; // List of files to load into players at startup
bool m_startInFullscreen; // Start in fullscreen mode
bool m_midiDebug;
Expand All @@ -53,6 +61,7 @@ class CmdlineArgs final {
bool m_debugAssertBreak;
bool m_settingsPathSet; // has --settingsPath been set on command line ?
bool m_useColors; // should colors be used
bool m_hasUserFeedback;
mixxx::LogLevel m_logLevel; // Level of stderr logging message verbosity
mixxx::LogLevel m_logFlushLevel; // Level of mixx.log file flushing
QString m_locale;
Expand Down