forked from qt-creator/qt-creator
ProcessInterface: Move out default impl into separate class
Introduce private DefaultImpl class and base QProcessImpl and ProcessLauncherImpl on it. Remove default impl specific methods from ProcessInterface. Change-Id: Iea964ab19cc0ea8401180f65351b6ef3f595703f Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -69,7 +69,7 @@ class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject
|
|||||||
public:
|
public:
|
||||||
ProcessInterface(QObject *parent = nullptr) : QObject(parent) {}
|
ProcessInterface(QObject *parent = nullptr) : QObject(parent) {}
|
||||||
|
|
||||||
virtual void start() { defaultStart(); }
|
virtual void start() = 0;
|
||||||
virtual void terminate() = 0;
|
virtual void terminate() = 0;
|
||||||
virtual void kill() = 0;
|
virtual void kill() = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
@@ -103,14 +103,7 @@ signals:
|
|||||||
void readyReadStandardError();
|
void readyReadStandardError();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void defaultStart();
|
|
||||||
|
|
||||||
ProcessSetupData m_setup;
|
ProcessSetupData m_setup;
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void doDefaultStart(const QString &program, const QStringList &arguments);
|
|
||||||
bool dissolveCommand(QString *program, QStringList *arguments);
|
|
||||||
bool ensureProgramExists(const QString &program);
|
|
||||||
friend class QtcProcess;
|
friend class QtcProcess;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,119 @@ private:
|
|||||||
Internal::TerminalProcess m_terminal;
|
Internal::TerminalProcess m_terminal;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QProcessImpl : public ProcessInterface
|
class DefaultImpl : public ProcessInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void start() { defaultStart(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void defaultStart();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void doDefaultStart(const QString &program, const QStringList &arguments) = 0;
|
||||||
|
bool dissolveCommand(QString *program, QStringList *arguments);
|
||||||
|
bool ensureProgramExists(const QString &program);
|
||||||
|
};
|
||||||
|
|
||||||
|
static QString blockingMessage(const QVariant &variant)
|
||||||
|
{
|
||||||
|
if (!variant.isValid())
|
||||||
|
return "non blocking";
|
||||||
|
if (variant.toInt() == int(QtcProcess::WithEventLoop))
|
||||||
|
return "blocking with event loop";
|
||||||
|
return "blocking without event loop";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultImpl::defaultStart()
|
||||||
|
{
|
||||||
|
if (processLog().isDebugEnabled()) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
const quint64 msSinceEpoc =
|
||||||
|
duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||||
|
setProperty(QTC_PROCESS_STARTTIME, msSinceEpoc);
|
||||||
|
|
||||||
|
static std::atomic_int startCounter = 0;
|
||||||
|
const int currentNumber = startCounter.fetch_add(1);
|
||||||
|
qCDebug(processLog).nospace().noquote()
|
||||||
|
<< "Process " << currentNumber << " starting ("
|
||||||
|
<< qPrintable(blockingMessage(property(QTC_PROCESS_BLOCKING_TYPE)))
|
||||||
|
<< "): "
|
||||||
|
<< m_setup.m_commandLine.toUserOutput();
|
||||||
|
setProperty(QTC_PROCESS_NUMBER, currentNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString program;
|
||||||
|
QStringList arguments;
|
||||||
|
if (!dissolveCommand(&program, &arguments))
|
||||||
|
return;
|
||||||
|
if (!ensureProgramExists(program))
|
||||||
|
return;
|
||||||
|
s_start.measureAndRun(&DefaultImpl::doDefaultStart, this, program, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultImpl::dissolveCommand(QString *program, QStringList *arguments)
|
||||||
|
{
|
||||||
|
const CommandLine &commandLine = m_setup.m_commandLine;
|
||||||
|
QString commandString;
|
||||||
|
ProcessArgs processArgs;
|
||||||
|
const bool success = ProcessArgs::prepareCommand(commandLine, &commandString, &processArgs,
|
||||||
|
&m_setup.m_environment,
|
||||||
|
&m_setup.m_workingDirectory);
|
||||||
|
|
||||||
|
if (commandLine.executable().osType() == OsTypeWindows) {
|
||||||
|
QString args;
|
||||||
|
if (m_setup.m_useCtrlCStub) {
|
||||||
|
if (m_setup.m_lowPriority)
|
||||||
|
ProcessArgs::addArg(&args, "-nice");
|
||||||
|
ProcessArgs::addArg(&args, QDir::toNativeSeparators(commandString));
|
||||||
|
commandString = QCoreApplication::applicationDirPath()
|
||||||
|
+ QLatin1String("/qtcreator_ctrlc_stub.exe");
|
||||||
|
} else if (m_setup.m_lowPriority) {
|
||||||
|
m_setup.m_belowNormalPriority = true;
|
||||||
|
}
|
||||||
|
ProcessArgs::addArgs(&args, processArgs.toWindowsArgs());
|
||||||
|
m_setup.m_nativeArguments = args;
|
||||||
|
// Note: Arguments set with setNativeArgs will be appended to the ones
|
||||||
|
// passed with start() below.
|
||||||
|
*arguments = QStringList();
|
||||||
|
} else {
|
||||||
|
if (!success) {
|
||||||
|
setErrorString(tr("Error in command line."));
|
||||||
|
// TODO: in fact it's WrongArgumentsFailure
|
||||||
|
emit errorOccurred(QProcess::FailedToStart);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*arguments = processArgs.toUnixArgs();
|
||||||
|
}
|
||||||
|
*program = commandString;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FilePath resolve(const FilePath &workingDir, const FilePath &filePath)
|
||||||
|
{
|
||||||
|
if (filePath.isAbsolutePath())
|
||||||
|
return filePath;
|
||||||
|
|
||||||
|
const FilePath fromWorkingDir = workingDir.resolvePath(filePath);
|
||||||
|
if (fromWorkingDir.exists() && fromWorkingDir.isExecutableFile())
|
||||||
|
return fromWorkingDir;
|
||||||
|
return filePath.searchInPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultImpl::ensureProgramExists(const QString &program)
|
||||||
|
{
|
||||||
|
const FilePath programFilePath = resolve(m_setup.m_workingDirectory,
|
||||||
|
FilePath::fromString(program));
|
||||||
|
if (programFilePath.exists() && programFilePath.isExecutableFile())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
setErrorString(QLatin1String("The program \"%1\" does not exist or is not executable.")
|
||||||
|
.arg(program));
|
||||||
|
emit errorOccurred(QProcess::FailedToStart);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QProcessImpl : public DefaultImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QProcessImpl() : m_process(new ProcessHelper(this))
|
QProcessImpl() : m_process(new ProcessHelper(this))
|
||||||
@@ -366,7 +478,7 @@ static uint uniqueToken()
|
|||||||
return ++globalUniqueToken;
|
return ++globalUniqueToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProcessLauncherImpl : public ProcessInterface
|
class ProcessLauncherImpl : public DefaultImpl
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -572,15 +684,6 @@ QtcProcess::Result QtcProcessPrivate::interpretExitCode(int exitCode)
|
|||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
|
|
||||||
static QString blockingMessage(const QVariant &variant)
|
|
||||||
{
|
|
||||||
if (!variant.isValid())
|
|
||||||
return "non blocking";
|
|
||||||
if (variant.toInt() == int(QtcProcess::WithEventLoop))
|
|
||||||
return "blocking with event loop";
|
|
||||||
return "blocking without event loop";
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessInterface::kickoffProcess()
|
void ProcessInterface::kickoffProcess()
|
||||||
{
|
{
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
@@ -596,102 +699,6 @@ qint64 ProcessInterface::applicationMainThreadID() const
|
|||||||
QTC_CHECK(false); return -1;
|
QTC_CHECK(false); return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessInterface::defaultStart()
|
|
||||||
{
|
|
||||||
if (processLog().isDebugEnabled()) {
|
|
||||||
using namespace std::chrono;
|
|
||||||
const quint64 msSinceEpoc =
|
|
||||||
duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
|
||||||
setProperty(QTC_PROCESS_STARTTIME, msSinceEpoc);
|
|
||||||
|
|
||||||
static std::atomic_int startCounter = 0;
|
|
||||||
const int currentNumber = startCounter.fetch_add(1);
|
|
||||||
qCDebug(processLog).nospace().noquote()
|
|
||||||
<< "Process " << currentNumber << " starting ("
|
|
||||||
<< qPrintable(blockingMessage(property(QTC_PROCESS_BLOCKING_TYPE)))
|
|
||||||
<< "): "
|
|
||||||
<< m_setup.m_commandLine.toUserOutput();
|
|
||||||
setProperty(QTC_PROCESS_NUMBER, currentNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString program;
|
|
||||||
QStringList arguments;
|
|
||||||
if (!dissolveCommand(&program, &arguments))
|
|
||||||
return;
|
|
||||||
if (!ensureProgramExists(program))
|
|
||||||
return;
|
|
||||||
s_start.measureAndRun(&ProcessInterface::doDefaultStart, this, program, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessInterface::doDefaultStart(const QString &program, const QStringList &arguments)
|
|
||||||
{
|
|
||||||
Q_UNUSED(program)
|
|
||||||
Q_UNUSED(arguments)
|
|
||||||
QTC_CHECK(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessInterface::dissolveCommand(QString *program, QStringList *arguments)
|
|
||||||
{
|
|
||||||
const CommandLine &commandLine = m_setup.m_commandLine;
|
|
||||||
QString commandString;
|
|
||||||
ProcessArgs processArgs;
|
|
||||||
const bool success = ProcessArgs::prepareCommand(commandLine, &commandString, &processArgs,
|
|
||||||
&m_setup.m_environment,
|
|
||||||
&m_setup.m_workingDirectory);
|
|
||||||
|
|
||||||
if (commandLine.executable().osType() == OsTypeWindows) {
|
|
||||||
QString args;
|
|
||||||
if (m_setup.m_useCtrlCStub) {
|
|
||||||
if (m_setup.m_lowPriority)
|
|
||||||
ProcessArgs::addArg(&args, "-nice");
|
|
||||||
ProcessArgs::addArg(&args, QDir::toNativeSeparators(commandString));
|
|
||||||
commandString = QCoreApplication::applicationDirPath()
|
|
||||||
+ QLatin1String("/qtcreator_ctrlc_stub.exe");
|
|
||||||
} else if (m_setup.m_lowPriority) {
|
|
||||||
m_setup.m_belowNormalPriority = true;
|
|
||||||
}
|
|
||||||
ProcessArgs::addArgs(&args, processArgs.toWindowsArgs());
|
|
||||||
m_setup.m_nativeArguments = args;
|
|
||||||
// Note: Arguments set with setNativeArgs will be appended to the ones
|
|
||||||
// passed with start() below.
|
|
||||||
*arguments = QStringList();
|
|
||||||
} else {
|
|
||||||
if (!success) {
|
|
||||||
setErrorString(tr("Error in command line."));
|
|
||||||
// TODO: in fact it's WrongArgumentsFailure
|
|
||||||
emit errorOccurred(QProcess::FailedToStart);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*arguments = processArgs.toUnixArgs();
|
|
||||||
}
|
|
||||||
*program = commandString;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilePath resolve(const FilePath &workingDir, const FilePath &filePath)
|
|
||||||
{
|
|
||||||
if (filePath.isAbsolutePath())
|
|
||||||
return filePath;
|
|
||||||
|
|
||||||
const FilePath fromWorkingDir = workingDir.resolvePath(filePath);
|
|
||||||
if (fromWorkingDir.exists() && fromWorkingDir.isExecutableFile())
|
|
||||||
return fromWorkingDir;
|
|
||||||
return filePath.searchInPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessInterface::ensureProgramExists(const QString &program)
|
|
||||||
{
|
|
||||||
const FilePath programFilePath = resolve(m_setup.m_workingDirectory,
|
|
||||||
FilePath::fromString(program));
|
|
||||||
if (programFilePath.exists() && programFilePath.isExecutableFile())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
setErrorString(QLatin1String("The program \"%1\" does not exist or is not executable.")
|
|
||||||
.arg(program));
|
|
||||||
emit errorOccurred(QProcess::FailedToStart);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class Utils::QtcProcess
|
\class Utils::QtcProcess
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user