Skip to content

Commit

Permalink
Merge pull request #4170 from daschuer/command_line_fix_2
Browse files Browse the repository at this point in the history
cmdlineargs:  Error handling and translation
  • Loading branch information
uklotzde committed Aug 4, 2021
2 parents 8d89f2e + 456c542 commit fa1b0fd
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 63 deletions.
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
169 changes: 108 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_parseForUserFeedbackRequired(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 @@ -64,6 +66,9 @@ bool parseLogLevel(
} // namespace

bool CmdlineArgs::parse(int argc, char** argv) {
// Some command line parameters needs to be evaluated before
// The QCoreApplication is initalized.
DEBUG_ASSERT(!QCoreApplication::instance());
if (argc == 1) {
// Mixxx was run with the binary name only, nothing to do
return true;
Expand All @@ -73,39 +78,63 @@ bool CmdlineArgs::parse(int argc, char** argv) {
for (int a = 0; a < argc; ++a) {
arguments << QString::fromLocal8Bit(argv[a]);
}
return parse(arguments, ParseMode::Initial);
}

void CmdlineArgs::parseForUserFeedback() {
// For user feedback we need an initalized QCoreApplication because
// it add some QT specific command line parameters
DEBUG_ASSERT(QCoreApplication::instance());
// We need only execute the second parse for user feedback when the first run
// has produces an not yet displayed error or help text.
// Otherwise we can skip the second run.
// A parameter for the QCoreApplication will fail in the first run and
// m_parseForUserFeedbackRequired will be set as well.
if (!m_parseForUserFeedbackRequired) {
return;
}
parse(QCoreApplication::arguments(), ParseMode::ForUserFeedback);
}

bool CmdlineArgs::parse(const QStringList& arguments, CmdlineArgs::ParseMode mode) {
bool forUserFeedback = (mode == ParseMode::ForUserFeedback);

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 +144,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 +158,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 +170,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 +182,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 +224,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 +238,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 +252,38 @@ 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;
}

// From here, we are in in the initial parse mode
DEBUG_ASSERT(mode == ParseMode::Initial);

// process all arguments
if (!parser.parse(arguments)) {
qWarning() << parser.errorText();
// we have an misspelled argument or one that is processed
// in the not yet initialized QCoreApplication
m_parseForUserFeedbackRequired = 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_parseForUserFeedbackRequired = true;
}

m_startInFullscreen = parser.isSet(fullScreen) || parser.isSet(fullScreenDeprecated);
Expand Down
14 changes: 14 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,13 @@ class CmdlineArgs final {
const QString& getTimelinePath() const { return m_timelinePath; }

private:
enum class ParseMode {
Initial,
ForUserFeedback
};

bool parse(const QStringList& arguments, ParseMode mode);

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 +66,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_parseForUserFeedbackRequired;
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

0 comments on commit fa1b0fd

Please sign in to comment.