forked from qt-creator/qt-creator
Utils: Simplify ProcessArgs
Instead of trying to find a generic abstraction for the arguments and splitting and combininig code paths several times, split into the Windows and non-Windows case early once. This also means that the ProcessArgs class as such is not really used as value type anymore and could be converted to a namespace in the future. Change-Id: I79562b1571794d60cc97e5d7f877744f3bc7d57c Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -77,10 +77,10 @@ static void envExpandWin(QString &args, const Environment *env, const QString &p
|
||||
}
|
||||
}
|
||||
|
||||
static ProcessArgs prepareArgsWin(const QString &_args, ProcessArgs::SplitError *err,
|
||||
const Environment *env, const QString &pwd)
|
||||
static QString prepareArgsWin(const QString &_args, ProcessArgs::SplitError *err,
|
||||
const Environment *env, const QString &pwd)
|
||||
{
|
||||
QString args(_args);
|
||||
QString args = _args;
|
||||
|
||||
if (env) {
|
||||
envExpandWin(args, env, pwd);
|
||||
@@ -88,7 +88,7 @@ static ProcessArgs prepareArgsWin(const QString &_args, ProcessArgs::SplitError
|
||||
if (args.indexOf(QLatin1Char('%')) >= 0) {
|
||||
if (err)
|
||||
*err = ProcessArgs::FoundMeta;
|
||||
return ProcessArgs::createWindowsArgs(QString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,13 +107,13 @@ static ProcessArgs prepareArgsWin(const QString &_args, ProcessArgs::SplitError
|
||||
} else if (isMetaCharWin(c)) {
|
||||
if (err)
|
||||
*err = ProcessArgs::FoundMeta;
|
||||
return ProcessArgs::createWindowsArgs(QString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
*err = ProcessArgs::SplitOk;
|
||||
return ProcessArgs::createWindowsArgs(args);
|
||||
return args;
|
||||
}
|
||||
|
||||
inline static bool isWhiteSpaceWin(ushort c)
|
||||
@@ -262,7 +262,7 @@ static QStringList splitArgsWin(const QString &_args, bool abortOnMeta,
|
||||
ProcessArgs::SplitError perr;
|
||||
if (!err)
|
||||
err = &perr;
|
||||
QString args = prepareArgsWin(_args, &perr, env, pwd).toWindowsArgs();
|
||||
QString args = prepareArgsWin(_args, &perr, env, pwd);
|
||||
if (*err != ProcessArgs::SplitOk)
|
||||
return {};
|
||||
return doSplitArgsWin(args, err);
|
||||
@@ -574,15 +574,15 @@ static QString quoteArgWin(const QString &arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ProcessArgs ProcessArgs::prepareArgs(const QString &args, SplitError *err, OsType osType,
|
||||
const Environment *env, const FilePath &pwd, bool abortOnMeta)
|
||||
QString ProcessArgs::prepareShellArgs(const QString &args, SplitError *err, OsType osType,
|
||||
const Environment *env, const FilePath &pwd)
|
||||
{
|
||||
const QString wd = pwd.path();
|
||||
ProcessArgs res;
|
||||
QString res;
|
||||
if (osType == OsTypeWindows)
|
||||
res = prepareArgsWin(args, err, env, wd);
|
||||
else
|
||||
res = createUnixArgs(splitArgs(args, osType, abortOnMeta, err, env, wd));
|
||||
res = joinArgs(splitArgsUnix(args, true, err, env, wd), OsTypeLinux);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -642,27 +642,32 @@ CommandLine &CommandLine::operator<<(const QStringList &args)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ProcessArgs::prepareCommand(const CommandLine &cmdLine, QString *outCmd, ProcessArgs *outArgs,
|
||||
bool ProcessArgs::prepareCommand(const CommandLine &cmdLine, QString *outCmd, QString *outArgs,
|
||||
const Environment *env, const FilePath &pwd)
|
||||
{
|
||||
const FilePath executable = cmdLine.executable();
|
||||
if (executable.isEmpty())
|
||||
return false;
|
||||
|
||||
const QString arguments = cmdLine.arguments();
|
||||
const OsType osType = executable.osType();
|
||||
|
||||
ProcessArgs::SplitError err;
|
||||
*outArgs = ProcessArgs::prepareArgs(arguments, &err, executable.osType(), env, pwd);
|
||||
*outArgs = ProcessArgs::prepareShellArgs(arguments, &err, osType, env, pwd);
|
||||
|
||||
if (err == ProcessArgs::SplitOk) {
|
||||
*outCmd = executable.path();
|
||||
} else {
|
||||
if (executable.osType() == OsTypeWindows) {
|
||||
if (osType == OsTypeWindows) {
|
||||
*outCmd = qtcEnvironmentVariable("COMSPEC");
|
||||
*outArgs = ProcessArgs::createWindowsArgs(QLatin1String("/v:off /s /c \"")
|
||||
+ quoteArgWin(executable.nativePath()) + ' ' + arguments + '"');
|
||||
*outArgs = "/v:off /s /c \""
|
||||
+ quoteArgWin(executable.nativePath()) + ' ' + arguments + '"';
|
||||
} else {
|
||||
if (err != ProcessArgs::FoundMeta)
|
||||
return false;
|
||||
*outCmd = qtcEnvironmentVariable("SHELL", "/bin/sh");
|
||||
*outArgs = ProcessArgs::createUnixArgs({"-c", quoteArg(executable.path()) + ' ' + arguments});
|
||||
ProcessArgs::addArg(outArgs, "-c", osType);
|
||||
ProcessArgs::addArg(outArgs, quoteArg(executable.path()) + ' ' + arguments, osType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1386,42 +1391,6 @@ void ProcessArgs::ArgIterator::appendArg(const QString &str)
|
||||
m_pos += qstr.length() + 1;
|
||||
}
|
||||
|
||||
ProcessArgs ProcessArgs::createWindowsArgs(const QString &args)
|
||||
{
|
||||
ProcessArgs result;
|
||||
result.m_windowsArgs = args;
|
||||
result.m_isWindows = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
ProcessArgs ProcessArgs::createUnixArgs(const QStringList &args)
|
||||
{
|
||||
ProcessArgs result;
|
||||
result.m_unixArgs = args;
|
||||
result.m_isWindows = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ProcessArgs::toWindowsArgs() const
|
||||
{
|
||||
QTC_CHECK(m_isWindows);
|
||||
return m_windowsArgs;
|
||||
}
|
||||
|
||||
QStringList ProcessArgs::toUnixArgs() const
|
||||
{
|
||||
QTC_CHECK(!m_isWindows);
|
||||
return m_unixArgs;
|
||||
}
|
||||
|
||||
QString ProcessArgs::toString() const
|
||||
{
|
||||
if (m_isWindows)
|
||||
return m_windowsArgs;
|
||||
else
|
||||
return ProcessArgs::joinArgs(m_unixArgs, OsTypeLinux);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class Utils::CommandLine
|
||||
\inmodule QtCreator
|
||||
|
@@ -23,13 +23,6 @@ class MacroExpander;
|
||||
class QTCREATOR_UTILS_EXPORT ProcessArgs
|
||||
{
|
||||
public:
|
||||
static ProcessArgs createWindowsArgs(const QString &args);
|
||||
static ProcessArgs createUnixArgs(const QStringList &args);
|
||||
|
||||
QString toWindowsArgs() const;
|
||||
QStringList toUnixArgs() const;
|
||||
QString toString() const;
|
||||
|
||||
enum SplitError {
|
||||
SplitOk = 0, //! All went just fine
|
||||
BadQuoting, //! Command contains quoting errors
|
||||
@@ -44,12 +37,11 @@ public:
|
||||
static void addArg(QString *args, const QString &arg, OsType osType = HostOsInfo::hostOs());
|
||||
//! Join an argument list into a shell command
|
||||
static QString joinArgs(const QStringList &args, OsType osType = HostOsInfo::hostOs());
|
||||
//! Prepare argument of a shell command for feeding into QProcess
|
||||
static ProcessArgs prepareArgs(const QString &args, SplitError *err, OsType osType,
|
||||
const Environment *env = nullptr, const FilePath &pwd = {},
|
||||
bool abortOnMeta = true);
|
||||
//! Prepare argument of a shell command for feeding into QProcess.
|
||||
static QString prepareShellArgs(const QString &args, SplitError *err, OsType osType,
|
||||
const Environment *env = nullptr, const FilePath &pwd = {});
|
||||
//! Prepare a shell command for feeding into QProcess
|
||||
static bool prepareCommand(const CommandLine &cmdLine, QString *outCmd, ProcessArgs *outArgs,
|
||||
static bool prepareCommand(const CommandLine &cmdLine, QString *outCmd, QString *outArgs,
|
||||
const Environment *env = nullptr, const FilePath &pwd = {});
|
||||
//! Quote and append each argument to a shell command
|
||||
static void addArgs(QString *args, const QStringList &inArgs);
|
||||
@@ -111,11 +103,6 @@ public:
|
||||
QString m_str;
|
||||
ArgIterator m_ait;
|
||||
};
|
||||
|
||||
private:
|
||||
QString m_windowsArgs;
|
||||
QStringList m_unixArgs;
|
||||
bool m_isWindows;
|
||||
};
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT RunResult
|
||||
|
@@ -244,13 +244,15 @@ void DefaultImpl::start()
|
||||
bool DefaultImpl::dissolveCommand(QString *program, QStringList *arguments)
|
||||
{
|
||||
const CommandLine &commandLine = m_setup.m_commandLine;
|
||||
const OsType osType = commandLine.executable().osType();
|
||||
|
||||
QString commandString;
|
||||
ProcessArgs processArgs;
|
||||
QString processArgs;
|
||||
const bool success = ProcessArgs::prepareCommand(commandLine, &commandString, &processArgs,
|
||||
&m_setup.m_environment,
|
||||
m_setup.m_workingDirectory);
|
||||
|
||||
if (commandLine.executable().osType() == OsTypeWindows) {
|
||||
if (osType == OsTypeWindows) {
|
||||
QString args;
|
||||
if (m_setup.m_useCtrlCStub) {
|
||||
if (m_setup.m_lowPriority)
|
||||
@@ -261,7 +263,7 @@ bool DefaultImpl::dissolveCommand(QString *program, QStringList *arguments)
|
||||
} else if (m_setup.m_lowPriority) {
|
||||
m_setup.m_belowNormalPriority = true;
|
||||
}
|
||||
ProcessArgs::addArgs(&args, processArgs.toWindowsArgs());
|
||||
ProcessArgs::addArgs(&args, processArgs);
|
||||
m_setup.m_nativeArguments = args;
|
||||
// Note: Arguments set with setNativeArgs will be appended to the ones
|
||||
// passed with start() below.
|
||||
@@ -275,7 +277,7 @@ bool DefaultImpl::dissolveCommand(QString *program, QStringList *arguments)
|
||||
emit done(result);
|
||||
return false;
|
||||
}
|
||||
*arguments = processArgs.toUnixArgs();
|
||||
*arguments = ProcessArgs::splitArgs(processArgs, osType);
|
||||
}
|
||||
*program = commandString;
|
||||
return true;
|
||||
|
@@ -285,9 +285,9 @@ Result DebuggerRunParameters::fixupParameters(ProjectExplorer::RunControl *runCo
|
||||
if (HostOsInfo::isWindowsHost()) {
|
||||
// Otherwise command lines with '> tmp.log' hang.
|
||||
ProcessArgs::SplitError perr;
|
||||
ProcessArgs::prepareArgs(m_inferior.command.arguments(), &perr,
|
||||
ProcessArgs::prepareShellArgs(m_inferior.command.arguments(), &perr,
|
||||
HostOsInfo::hostOs(), nullptr,
|
||||
m_inferior.workingDirectory).toWindowsArgs();
|
||||
m_inferior.workingDirectory);
|
||||
if (perr != ProcessArgs::SplitOk) {
|
||||
// perr == BadQuoting is never returned on Windows
|
||||
// FIXME? QTCREATORBUG-2809
|
||||
|
@@ -145,12 +145,15 @@ QString ProcessParameters::prettyArguments() const
|
||||
{
|
||||
const QString margs = effectiveArguments();
|
||||
const FilePath workDir = effectiveWorkingDirectory();
|
||||
const OsType osType = workDir.osType();
|
||||
ProcessArgs::SplitError err;
|
||||
const ProcessArgs args = ProcessArgs::prepareArgs(margs, &err, HostOsInfo::hostOs(),
|
||||
&m_runData.environment, workDir);
|
||||
const QString args = ProcessArgs::prepareShellArgs(margs, &err, osType,
|
||||
&m_runData.environment, workDir);
|
||||
if (err != ProcessArgs::SplitOk)
|
||||
return margs; // Sorry, too complex - just fall back.
|
||||
return args.toString();
|
||||
if (osType == OsTypeWindows)
|
||||
return args.front();
|
||||
return args;
|
||||
}
|
||||
|
||||
static QString invalidCommandMessage(const QString &displayName)
|
||||
|
@@ -386,8 +386,7 @@ void tst_Process::prepareArgs()
|
||||
QFETCH(OsType, os);
|
||||
|
||||
ProcessArgs::SplitError outerr;
|
||||
ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os);
|
||||
QString outstr = args.toString();
|
||||
QString outstr = ProcessArgs::prepareShellArgs(in, &outerr, os);
|
||||
|
||||
QCOMPARE(outerr, err);
|
||||
if (err == ProcessArgs::SplitOk)
|
||||
@@ -476,8 +475,7 @@ void tst_Process::prepareArgsEnv()
|
||||
QFETCH(OsType, os);
|
||||
|
||||
ProcessArgs::SplitError outerr;
|
||||
ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os, os == OsTypeLinux ? &envLinux : &envWindows);
|
||||
QString outstr = args.toString();
|
||||
QString outstr = ProcessArgs::prepareShellArgs(in, &outerr, os, os == OsTypeLinux ? &envLinux : &envWindows);
|
||||
|
||||
QCOMPARE(outerr, err);
|
||||
if (err == ProcessArgs::SplitOk)
|
||||
@@ -485,7 +483,6 @@ void tst_Process::prepareArgsEnv()
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tst_Process::iterations_data()
|
||||
{
|
||||
QTest::addColumn<QString>("in");
|
||||
|
Reference in New Issue
Block a user