mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-12-21 08:09:35 +08:00
Refactor parameters parsing
Introduce classes that encapsulate parameter names and parsing schemes from command line and from environment variables.
This commit is contained in:
parent
0bf7fa15c1
commit
0710a59bf5
@ -47,32 +47,205 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isBoolEnvVarSetToTrue(const QProcessEnvironment &env, const QString &var)
|
||||
// Base option class. Encapsulates name operations.
|
||||
class Option
|
||||
{
|
||||
QString val = env.value(var);
|
||||
// we accept "1" and "true" (upper or lower cased) as boolean 'true' values
|
||||
return (val == QLatin1String("1") || val.toUpper() == QLatin1String("TRUE"));
|
||||
}
|
||||
|
||||
int readIntlEnvVar(const QProcessEnvironment &env, const QString &var, int defaultValue)
|
||||
{
|
||||
QString val = env.value(var);
|
||||
if (val.isEmpty()) return defaultValue;
|
||||
bool ok;
|
||||
int res = val.toInt(&ok);
|
||||
if (!ok) {
|
||||
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'")
|
||||
.arg(var).arg(val);
|
||||
return defaultValue;
|
||||
protected:
|
||||
constexpr Option(const char *name, char shortcut = 0)
|
||||
: m_name {name}
|
||||
, m_shortcut {shortcut}
|
||||
{
|
||||
}
|
||||
return res;
|
||||
|
||||
QString fullParameter() const
|
||||
{
|
||||
return QLatin1String("--") + QLatin1String(m_name);
|
||||
}
|
||||
|
||||
QString shortcutParameter() const
|
||||
{
|
||||
return QLatin1String("-") + QLatin1Char(m_shortcut);
|
||||
}
|
||||
|
||||
bool hasShortcut() const
|
||||
{
|
||||
return m_shortcut != 0;
|
||||
}
|
||||
|
||||
QString envVarName() const
|
||||
{
|
||||
return QLatin1String("QBT_")
|
||||
+ QString(QLatin1String(m_name)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_'));
|
||||
}
|
||||
|
||||
static QString padUsageText(const QString &usage)
|
||||
{
|
||||
const int TAB_WIDTH = 8;
|
||||
QString res = QLatin1String("\t") + usage;
|
||||
if (usage.size() < 2 * TAB_WIDTH)
|
||||
return res + QLatin1String("\t\t");
|
||||
else
|
||||
return res + QLatin1String("\t");
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_name;
|
||||
const char m_shortcut;
|
||||
};
|
||||
|
||||
// Boolean option.
|
||||
class BoolOption: protected Option
|
||||
{
|
||||
public:
|
||||
constexpr BoolOption(const char *name, char shortcut = 0)
|
||||
: Option {name, shortcut}
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const QString &arg) const
|
||||
{
|
||||
return (hasShortcut() && ((arg.size() == 2) && (arg == shortcutParameter())))
|
||||
|| (arg == fullParameter());
|
||||
}
|
||||
|
||||
bool value(const QProcessEnvironment &env) const
|
||||
{
|
||||
QString val = env.value(envVarName());
|
||||
// we accept "1" and "true" (upper or lower cased) as boolean 'true' values
|
||||
return (val == QLatin1String("1") || val.toUpper() == QLatin1String("TRUE"));
|
||||
}
|
||||
|
||||
QString usage() const
|
||||
{
|
||||
QString res;
|
||||
if (hasShortcut())
|
||||
res += shortcutParameter() + QLatin1String(" | ");
|
||||
res += fullParameter();
|
||||
return padUsageText(res);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const QString &s, const BoolOption &o)
|
||||
{
|
||||
return o == s;
|
||||
}
|
||||
|
||||
QString envVarNameForParameter(const char *parameterName)
|
||||
// Option with string value. May not have a shortcut
|
||||
struct StringOption: protected Option
|
||||
{
|
||||
return QLatin1String("QBT_") +
|
||||
QString(QLatin1String(parameterName)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_'));
|
||||
public:
|
||||
constexpr StringOption(const char *name)
|
||||
: Option {name, 0}
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const QString &arg) const
|
||||
{
|
||||
return arg.startsWith(parameterAssignment());
|
||||
}
|
||||
|
||||
QString value(const QString &arg) const
|
||||
{
|
||||
QStringList parts = arg.split(QLatin1Char('='));
|
||||
if (parts.size() == 2)
|
||||
return unquote(parts[1]);
|
||||
throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
|
||||
"e.g. Parameter '--webui-port' must follow syntax '--webui-port=value'")
|
||||
.arg(fullParameter()).arg(QLatin1String("<value>")));
|
||||
}
|
||||
|
||||
QString value(const QProcessEnvironment &env, const QString &defaultValue = QString()) const
|
||||
{
|
||||
QString val = env.value(envVarName());
|
||||
return val.isEmpty() ? defaultValue : unquote(val);
|
||||
}
|
||||
|
||||
QString usage(const QString &valueName) const
|
||||
{
|
||||
return padUsageText(parameterAssignment() + QLatin1Char('<') + valueName + QLatin1Char('>'));
|
||||
}
|
||||
|
||||
private:
|
||||
QString parameterAssignment() const
|
||||
{
|
||||
return fullParameter() + QLatin1Char('=');
|
||||
}
|
||||
|
||||
static QString unquote(const QString &s)
|
||||
{
|
||||
auto isStringQuoted =
|
||||
[](const QString &s, QChar quoteChar)
|
||||
{
|
||||
return (s.startsWith(quoteChar) && s.endsWith(quoteChar));
|
||||
};
|
||||
|
||||
if ((s.size() >= 2) && (isStringQuoted(s, QLatin1Char('\'')) || isStringQuoted(s, QLatin1Char('"'))))
|
||||
return s.mid(1, s.size() - 2);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const QString &s, const StringOption &o)
|
||||
{
|
||||
return o == s;
|
||||
}
|
||||
|
||||
// Option with integer value. May not have a shortcut
|
||||
class IntOption: protected StringOption
|
||||
{
|
||||
public:
|
||||
constexpr IntOption(const char *name)
|
||||
: StringOption {name}
|
||||
{
|
||||
}
|
||||
|
||||
using StringOption::operator==;
|
||||
using StringOption::usage;
|
||||
|
||||
int value(const QString &arg) const
|
||||
{
|
||||
QString val = StringOption::value(arg);
|
||||
bool ok = false;
|
||||
int res = val.toInt(&ok);
|
||||
if (!ok)
|
||||
throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'",
|
||||
"e.g. Parameter '--webui-port' must follow syntax '--webui-port=<value>'")
|
||||
.arg(fullParameter()).arg(QLatin1String("<integer value>")));
|
||||
return res;
|
||||
}
|
||||
|
||||
int value(const QProcessEnvironment &env, int defaultValue) const
|
||||
{
|
||||
QString val = env.value(envVarName());
|
||||
if (val.isEmpty()) return defaultValue;
|
||||
|
||||
bool ok;
|
||||
int res = val.toInt(&ok);
|
||||
if (!ok) {
|
||||
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'")
|
||||
.arg(envVarName()).arg(val);
|
||||
return defaultValue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const QString &s, const IntOption &o)
|
||||
{
|
||||
return o == s;
|
||||
}
|
||||
|
||||
constexpr const BoolOption SHOW_HELP_OPTION = {"help", 'h'};
|
||||
constexpr const BoolOption SHOW_VERSION_OPTION = {"version", 'v'};
|
||||
#ifdef DISABLE_GUI
|
||||
constexpr const BoolOption DAEMON_OPTION = {"daemon", 'd'};
|
||||
#else
|
||||
constexpr const BoolOption NO_SPLASH_OPTION = {"no-splash"};
|
||||
#endif
|
||||
constexpr const IntOption WEBUI_PORT_OPTION = {"webui-port"};
|
||||
constexpr const StringOption PROFILE_OPTION = {"profile"};
|
||||
constexpr const StringOption CONFIGURATION_OPTION = {"configuration"};
|
||||
constexpr const BoolOption PORTABLE_OPTION = {"portable"};
|
||||
}
|
||||
|
||||
QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env)
|
||||
@ -81,14 +254,14 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
|
||||
, showVersion(false)
|
||||
#endif
|
||||
#ifndef DISABLE_GUI
|
||||
, noSplash(isBoolEnvVarSetToTrue(env, envVarNameForParameter("no-splash")))
|
||||
, noSplash(NO_SPLASH_OPTION.value(env))
|
||||
#else
|
||||
, shouldDaemonize(isBoolEnvVarSetToTrue(env, envVarNameForParameter("daemon")))
|
||||
, shouldDaemonize(DAEMON_OPTION.value(env))
|
||||
#endif
|
||||
, webUiPort(readIntlEnvVar(env, envVarNameForParameter("webui-port"), -1))
|
||||
, profileDir(env.value(envVarNameForParameter("profile")))
|
||||
, portableMode(isBoolEnvVarSetToTrue(env, envVarNameForParameter("portable")))
|
||||
, configurationName(env.value(envVarNameForParameter("configuration")))
|
||||
, webUiPort(WEBUI_PORT_OPTION.value(env, -1))
|
||||
, profileDir(PROFILE_OPTION.value(env))
|
||||
, portableMode(PORTABLE_OPTION.value(env))
|
||||
, configurationName(CONFIGURATION_OPTION.value(env))
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,45 +275,37 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
|
||||
if ((arg.startsWith("--") && !arg.endsWith(".torrent"))
|
||||
|| (arg.startsWith("-") && (arg.size() == 2))) {
|
||||
// Parse known parameters
|
||||
if ((arg == QLatin1String("-h")) || (arg == QLatin1String("--help"))) {
|
||||
if ((arg == SHOW_HELP_OPTION)) {
|
||||
result.showHelp = true;
|
||||
}
|
||||
#ifndef Q_OS_WIN
|
||||
else if ((arg == QLatin1String("-v")) || (arg == QLatin1String("--version"))) {
|
||||
else if (arg == SHOW_VERSION_OPTION) {
|
||||
result.showVersion = true;
|
||||
}
|
||||
#endif
|
||||
else if (arg.startsWith(QLatin1String("--webui-port="))) {
|
||||
QStringList parts = arg.split(QLatin1Char('='));
|
||||
if (parts.size() == 2) {
|
||||
bool ok = false;
|
||||
result.webUiPort = parts.last().toInt(&ok);
|
||||
if (!ok || (result.webUiPort < 1) || (result.webUiPort > 65535))
|
||||
throw CommandLineParameterError(QObject::tr("%1 must specify the correct port (1 to 65535).")
|
||||
.arg(QLatin1String("--webui-port")));
|
||||
}
|
||||
else if (arg == WEBUI_PORT_OPTION) {
|
||||
result.webUiPort = WEBUI_PORT_OPTION.value(arg);
|
||||
if ((result.webUiPort < 1) || (result.webUiPort > 65535))
|
||||
throw CommandLineParameterError(QObject::tr("%1 must specify the correct port (1 to 65535).")
|
||||
.arg(QLatin1String("--webui-port")));
|
||||
}
|
||||
#ifndef DISABLE_GUI
|
||||
else if (arg == QLatin1String("--no-splash")) {
|
||||
else if (arg == NO_SPLASH_OPTION) {
|
||||
result.noSplash = true;
|
||||
}
|
||||
#else
|
||||
else if ((arg == QLatin1String("-d")) || (arg == QLatin1String("--daemon"))) {
|
||||
else if (arg == DAEMON_OPTION) {
|
||||
result.shouldDaemonize = true;
|
||||
}
|
||||
#endif
|
||||
else if (arg == QLatin1String("--profile")) {
|
||||
QStringList parts = arg.split(QLatin1Char('='));
|
||||
if (parts.size() == 2)
|
||||
result.profileDir = parts.last();
|
||||
else if (arg == PROFILE_OPTION) {
|
||||
result.profileDir = PROFILE_OPTION.value(arg);
|
||||
}
|
||||
else if (arg == QLatin1String("--portable")) {
|
||||
else if (arg == PORTABLE_OPTION) {
|
||||
result.portableMode = true;
|
||||
}
|
||||
else if (arg == QLatin1String("--configuration")) {
|
||||
QStringList parts = arg.split(QLatin1Char('='));
|
||||
if (parts.size() == 2)
|
||||
result.configurationName = parts.last();
|
||||
else if (arg == CONFIGURATION_OPTION) {
|
||||
result.configurationName = CONFIGURATION_OPTION.value(arg);
|
||||
}
|
||||
else {
|
||||
// Unknown argument
|
||||
@ -185,20 +350,20 @@ QString makeUsage(const QString &prgName)
|
||||
|
||||
stream << QObject::tr("Options:") << '\n';
|
||||
#ifndef Q_OS_WIN
|
||||
stream << "\t-v | --version\t\t" << QObject::tr("Displays program version and exit") << '\n';
|
||||
stream << SHOW_VERSION_OPTION.usage() << QObject::tr("Displays program version and exit") << '\n';
|
||||
#endif
|
||||
stream << "\t-h | --help\t\t" << QObject::tr("Displays this help message and exit") << '\n';
|
||||
stream << "\t--webui-port=<port>\t"
|
||||
stream << SHOW_HELP_OPTION.usage() << QObject::tr("Displays this help message and exit") << '\n';
|
||||
stream << WEBUI_PORT_OPTION.usage(QLatin1String("port"))
|
||||
<< QObject::tr("Changes the Web UI port")
|
||||
<< '\n';
|
||||
#ifndef DISABLE_GUI
|
||||
stream << "\t--no-splash\t\t" << QObject::tr("Disable splash screen") << '\n';
|
||||
stream << NO_SPLASH_OPTION.usage() << QObject::tr("Disable splash screen") << '\n';
|
||||
#else
|
||||
stream << "\t-d | --daemon\t\t" << QObject::tr("Run in daemon-mode (background)") << '\n';
|
||||
stream << DAEMON_OPTION.usage() << QObject::tr("Run in daemon-mode (background)") << '\n';
|
||||
#endif
|
||||
stream << "\t--profile=<dir>\t\t" << QObject::tr("Store configuration files in <dir>") << '\n';
|
||||
stream << "\t--portable\t\t" << QObject::tr("Shortcut for --profile=<exe dir>/profile") << '\n';
|
||||
stream << "\t--configuration=<name>\t" << QObject::tr("Store configuration files in directories qBittorrent_<name>")
|
||||
stream << PROFILE_OPTION.usage(QLatin1String("dir")) << QObject::tr("Store configuration files in <dir>") << '\n';
|
||||
stream << PORTABLE_OPTION.usage() << QObject::tr("Shortcut for --profile=<exe dir>/profile") << '\n';
|
||||
stream << CONFIGURATION_OPTION.usage(QLatin1String("name")) << QObject::tr("Store configuration files in directories qBittorrent_<name>")
|
||||
<< '\n';
|
||||
stream << "\tfiles or urls\t\t" << QObject::tr("Downloads the torrents passed by the user") << '\n'
|
||||
<< '\n';
|
||||
|
Loading…
Reference in New Issue
Block a user