Utils: Un-seat QtcProcess from ProcessInterface

I find it too confusing to have that inheritance only to enforce
similar interfaces.

Change-Id: I9da68ea59c04f709228e0874460e987115b30f56
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
hjk
2022-03-29 18:01:08 +02:00
parent 5b1035c20f
commit 27c8f00d73
3 changed files with 98 additions and 90 deletions

View File

@@ -131,7 +131,7 @@ public:
} }
void start() override { m_target->start(); } void start() override { m_target->start(); }
void interrupt() override { m_target->interrupt(); }; void interrupt() override { m_target->interrupt(); }
void terminate() override { m_target->terminate(); } void terminate() override { m_target->terminate(); }
void kill() override { m_target->kill(); } void kill() override { m_target->kill(); }
void close() override { m_target->close(); } void close() override { m_target->close(); }

View File

@@ -564,19 +564,18 @@ public:
OtherFailure OtherFailure
}; };
explicit QtcProcessPrivate(QtcProcess *parent, const ProcessSetupData::Ptr &setup) explicit QtcProcessPrivate(QtcProcess *parent)
: QObject(parent) : QObject(parent)
, q(parent) , q(parent)
, m_setup(setup)
{} {}
ProcessInterface *createProcessInterface() ProcessInterface *createProcessInterface()
{ {
if (m_setup->m_terminalMode != TerminalMode::Off) if (m_setup.m_terminalMode != TerminalMode::Off)
return new TerminalImpl(); return new TerminalImpl();
const ProcessImpl impl = m_setup->m_processImpl == ProcessImpl::Default const ProcessImpl impl = m_setup.m_processImpl == ProcessImpl::Default
? defaultProcessImpl() : m_setup->m_processImpl; ? defaultProcessImpl() : m_setup.m_processImpl;
if (impl == ProcessImpl::QProcess) if (impl == ProcessImpl::QProcess)
return new QProcessImpl(); return new QProcessImpl();
return new ProcessLauncherImpl(); return new ProcessLauncherImpl();
@@ -585,7 +584,7 @@ public:
void setProcessInterface(ProcessInterface *process) void setProcessInterface(ProcessInterface *process)
{ {
m_process.reset(process); m_process.reset(process);
m_setup->m_errorString.clear(); m_setup.m_errorString.clear();
m_process->setParent(this); m_process->setParent(this);
connect(m_process.get(), &ProcessInterface::started, connect(m_process.get(), &ProcessInterface::started,
@@ -616,21 +615,21 @@ public:
CommandLine fullCommandLine() const CommandLine fullCommandLine() const
{ {
if (!m_setup->m_runAsRoot || HostOsInfo::isWindowsHost()) if (!m_setup.m_runAsRoot || HostOsInfo::isWindowsHost())
return m_setup->m_commandLine; return m_setup.m_commandLine;
CommandLine rootCommand("sudo", {"-A"}); CommandLine rootCommand("sudo", {"-A"});
rootCommand.addCommandLineAsArgs(m_setup->m_commandLine); rootCommand.addCommandLineAsArgs(m_setup.m_commandLine);
return rootCommand; return rootCommand;
} }
Environment fullEnvironment() const Environment fullEnvironment() const
{ {
Environment env; Environment env;
if (m_setup->m_haveEnv) { if (m_setup.m_haveEnv) {
if (m_setup->m_environment.size() == 0) if (m_setup.m_environment.size() == 0)
qWarning("QtcProcess::start: Empty environment set when running '%s'.", qWarning("QtcProcess::start: Empty environment set when running '%s'.",
qPrintable(m_setup->m_commandLine.executable().toString())); qPrintable(m_setup.m_commandLine.executable().toString()));
env = m_setup->m_environment; env = m_setup.m_environment;
} else { } else {
env = Environment::systemEnvironment(); env = Environment::systemEnvironment();
} }
@@ -643,7 +642,7 @@ public:
QtcProcess *q; QtcProcess *q;
std::unique_ptr<ProcessInterface> m_process; std::unique_ptr<ProcessInterface> m_process;
ProcessSetupData::Ptr m_setup; ProcessSetupData m_setup;
void slotTimeout(); void slotTimeout();
void slotFinished(); void slotFinished();
@@ -708,8 +707,8 @@ qint64 ProcessInterface::applicationMainThreadID() const
*/ */
QtcProcess::QtcProcess(QObject *parent) QtcProcess::QtcProcess(QObject *parent)
: ProcessInterface(parent), : QObject(parent),
d(new QtcProcessPrivate(this, m_setup)) d(new QtcProcessPrivate(this))
{ {
static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>(); static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>();
static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>(); static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
@@ -773,90 +772,90 @@ void QtcProcess::setProcessInterface(ProcessInterface *interface)
{ {
d->setProcessInterface(interface); d->setProcessInterface(interface);
// Make a copy, don't share, until we get rid of fullCommandLine() and fullEnvironment() // Make a copy, don't share, until we get rid of fullCommandLine() and fullEnvironment()
*d->m_process->m_setup = *d->m_setup; *d->m_process->m_setup = d->m_setup;
} }
void QtcProcess::setProcessImpl(ProcessImpl processImpl) void QtcProcess::setProcessImpl(ProcessImpl processImpl)
{ {
d->m_setup->m_processImpl = processImpl; d->m_setup.m_processImpl = processImpl;
} }
ProcessMode QtcProcess::processMode() const ProcessMode QtcProcess::processMode() const
{ {
return d->m_setup->m_processMode; return d->m_setup.m_processMode;
} }
void QtcProcess::setTerminalMode(TerminalMode mode) void QtcProcess::setTerminalMode(TerminalMode mode)
{ {
d->m_setup->m_terminalMode = mode; d->m_setup.m_terminalMode = mode;
} }
TerminalMode QtcProcess::terminalMode() const TerminalMode QtcProcess::terminalMode() const
{ {
return d->m_setup->m_terminalMode; return d->m_setup.m_terminalMode;
} }
void QtcProcess::setProcessMode(ProcessMode processMode) void QtcProcess::setProcessMode(ProcessMode processMode)
{ {
d->m_setup->m_processMode = processMode; d->m_setup.m_processMode = processMode;
} }
void QtcProcess::setEnvironment(const Environment &env) void QtcProcess::setEnvironment(const Environment &env)
{ {
d->m_setup->m_environment = env; d->m_setup.m_environment = env;
d->m_setup->m_haveEnv = true; d->m_setup.m_haveEnv = true;
} }
void QtcProcess::unsetEnvironment() void QtcProcess::unsetEnvironment()
{ {
d->m_setup->m_environment = Environment(); d->m_setup.m_environment = Environment();
d->m_setup->m_haveEnv = false; d->m_setup.m_haveEnv = false;
} }
const Environment &QtcProcess::environment() const const Environment &QtcProcess::environment() const
{ {
return d->m_setup->m_environment; return d->m_setup.m_environment;
} }
bool QtcProcess::hasEnvironment() const bool QtcProcess::hasEnvironment() const
{ {
return d->m_setup->m_haveEnv; return d->m_setup.m_haveEnv;
} }
void QtcProcess::setRemoteEnvironment(const Environment &environment) void QtcProcess::setRemoteEnvironment(const Environment &environment)
{ {
d->m_setup->m_remoteEnvironment = environment; d->m_setup.m_remoteEnvironment = environment;
} }
Environment QtcProcess::remoteEnvironment() const Environment QtcProcess::remoteEnvironment() const
{ {
return d->m_setup->m_remoteEnvironment; return d->m_setup.m_remoteEnvironment;
} }
void QtcProcess::setCommand(const CommandLine &cmdLine) void QtcProcess::setCommand(const CommandLine &cmdLine)
{ {
if (d->m_setup->m_workingDirectory.needsDevice() && cmdLine.executable().needsDevice()) { if (d->m_setup.m_workingDirectory.needsDevice() && cmdLine.executable().needsDevice()) {
QTC_CHECK(d->m_setup->m_workingDirectory.host() == cmdLine.executable().host()); QTC_CHECK(d->m_setup.m_workingDirectory.host() == cmdLine.executable().host());
} }
d->m_setup->m_commandLine = cmdLine; d->m_setup.m_commandLine = cmdLine;
} }
const CommandLine &QtcProcess::commandLine() const const CommandLine &QtcProcess::commandLine() const
{ {
return d->m_setup->m_commandLine; return d->m_setup.m_commandLine;
} }
FilePath QtcProcess::workingDirectory() const FilePath QtcProcess::workingDirectory() const
{ {
return d->m_setup->m_workingDirectory; return d->m_setup.m_workingDirectory;
} }
void QtcProcess::setWorkingDirectory(const FilePath &dir) void QtcProcess::setWorkingDirectory(const FilePath &dir)
{ {
if (dir.needsDevice() && d->m_setup->m_commandLine.executable().needsDevice()) { if (dir.needsDevice() && d->m_setup.m_commandLine.executable().needsDevice()) {
QTC_CHECK(dir.host() == d->m_setup->m_commandLine.executable().host()); QTC_CHECK(dir.host() == d->m_setup.m_commandLine.executable().host());
} }
d->m_setup->m_workingDirectory = dir; d->m_setup.m_workingDirectory = dir;
} }
void QtcProcess::setUseCtrlCStub(bool enabled) void QtcProcess::setUseCtrlCStub(bool enabled)
@@ -865,7 +864,7 @@ void QtcProcess::setUseCtrlCStub(bool enabled)
// Qt Creator otherwise, because they share the same Windows console. // Qt Creator otherwise, because they share the same Windows console.
// See QTCREATORBUG-11995 for details. // See QTCREATORBUG-11995 for details.
#ifndef QT_DEBUG #ifndef QT_DEBUG
d->m_setup->m_useCtrlCStub = enabled; d->m_setup.m_useCtrlCStub = enabled;
#else #else
Q_UNUSED(enabled) Q_UNUSED(enabled)
#endif #endif
@@ -877,7 +876,7 @@ void QtcProcess::start()
// QTC_ASSERT(state() == QProcess::NotRunning, return); // QTC_ASSERT(state() == QProcess::NotRunning, return);
ProcessInterface *processImpl = nullptr; ProcessInterface *processImpl = nullptr;
if (d->m_setup->m_commandLine.executable().needsDevice()) { if (d->m_setup.m_commandLine.executable().needsDevice()) {
if (s_deviceHooks.processImplHook) { // TODO: replace "if" with an assert for the hook if (s_deviceHooks.processImplHook) { // TODO: replace "if" with an assert for the hook
processImpl = s_deviceHooks.processImplHook(commandLine().executable()); processImpl = s_deviceHooks.processImplHook(commandLine().executable());
} }
@@ -929,7 +928,7 @@ BOOL CALLBACK sendInterruptMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARA
void QtcProcess::terminate() void QtcProcess::terminate()
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if (d->m_setup->m_useCtrlCStub) if (d->m_setup.m_useCtrlCStub)
EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, processId()); EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, processId());
else else
#endif #endif
@@ -940,7 +939,7 @@ void QtcProcess::terminate()
void QtcProcess::interrupt() void QtcProcess::interrupt()
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if (d->m_setup->m_useCtrlCStub) if (d->m_setup.m_useCtrlCStub)
EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, processId()); EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, processId());
else else
#endif #endif
@@ -958,71 +957,71 @@ bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDi
void QtcProcess::setLowPriority() void QtcProcess::setLowPriority()
{ {
d->m_setup->m_lowPriority = true; d->m_setup.m_lowPriority = true;
} }
void QtcProcess::setDisableUnixTerminal() void QtcProcess::setDisableUnixTerminal()
{ {
d->m_setup->m_unixTerminalDisabled = true; d->m_setup.m_unixTerminalDisabled = true;
} }
void QtcProcess::setAbortOnMetaChars(bool abort) void QtcProcess::setAbortOnMetaChars(bool abort)
{ {
d->m_setup->m_abortOnMetaChars = abort; d->m_setup.m_abortOnMetaChars = abort;
} }
void QtcProcess::setRunAsRoot(bool on) void QtcProcess::setRunAsRoot(bool on)
{ {
d->m_setup->m_runAsRoot = on; d->m_setup.m_runAsRoot = on;
} }
bool QtcProcess::isRunAsRoot() const bool QtcProcess::isRunAsRoot() const
{ {
return d->m_setup->m_runAsRoot; return d->m_setup.m_runAsRoot;
} }
void QtcProcess::setStandardInputFile(const QString &inputFile) void QtcProcess::setStandardInputFile(const QString &inputFile)
{ {
d->m_setup->m_standardInputFile = inputFile; d->m_setup.m_standardInputFile = inputFile;
} }
QString QtcProcess::toStandaloneCommandLine() const QString QtcProcess::toStandaloneCommandLine() const
{ {
QStringList parts; QStringList parts;
parts.append("/usr/bin/env"); parts.append("/usr/bin/env");
if (!d->m_setup->m_workingDirectory.isEmpty()) { if (!d->m_setup.m_workingDirectory.isEmpty()) {
parts.append("-C"); parts.append("-C");
d->m_setup->m_workingDirectory.path(); d->m_setup.m_workingDirectory.path();
} }
parts.append("-i"); parts.append("-i");
if (d->m_setup->m_environment.size() > 0) { if (d->m_setup.m_environment.size() > 0) {
const QStringList envVars = d->m_setup->m_environment.toStringList(); const QStringList envVars = d->m_setup.m_environment.toStringList();
std::transform(envVars.cbegin(), envVars.cend(), std::transform(envVars.cbegin(), envVars.cend(),
std::back_inserter(parts), ProcessArgs::quoteArgUnix); std::back_inserter(parts), ProcessArgs::quoteArgUnix);
} }
parts.append(d->m_setup->m_commandLine.executable().path()); parts.append(d->m_setup.m_commandLine.executable().path());
parts.append(d->m_setup->m_commandLine.splitArguments()); parts.append(d->m_setup.m_commandLine.splitArguments());
return parts.join(" "); return parts.join(" ");
} }
void QtcProcess::setExtraData(const QString &key, const QVariant &value) void QtcProcess::setExtraData(const QString &key, const QVariant &value)
{ {
d->m_setup->m_extraData.insert(key, value); d->m_setup.m_extraData.insert(key, value);
} }
QVariant QtcProcess::extraData(const QString &key) const QVariant QtcProcess::extraData(const QString &key) const
{ {
return d->m_setup->m_extraData.value(key); return d->m_setup.m_extraData.value(key);
} }
void QtcProcess::setExtraData(const QVariantHash &extraData) void QtcProcess::setExtraData(const QVariantHash &extraData)
{ {
d->m_setup->m_extraData = extraData; d->m_setup.m_extraData = extraData;
} }
QVariantHash QtcProcess::extraData() const QVariantHash QtcProcess::extraData() const
{ {
return d->m_setup->m_extraData; return d->m_setup.m_extraData;
} }
void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks) void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks)
@@ -1107,7 +1106,7 @@ bool QtcProcess::readDataFromProcess(int timeoutS,
} }
// Prompt user, pretend we have data if says 'No'. // Prompt user, pretend we have data if says 'No'.
const bool hang = !hasData && !finished; const bool hang = !hasData && !finished;
hasData = hang && showTimeOutMessageBox && !askToKill(d->m_setup->m_commandLine.executable().path()); hasData = hang && showTimeOutMessageBox && !askToKill(d->m_setup.m_commandLine.executable().path());
} while (hasData && !finished); } while (hasData && !finished);
if (syncDebug) if (syncDebug)
qDebug() << "<readDataFromProcess" << finished; qDebug() << "<readDataFromProcess" << finished;
@@ -1249,7 +1248,7 @@ qint64 QtcProcess::applicationMainThreadID() const
void QtcProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode) void QtcProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
{ {
d->m_setup->m_processChannelMode = mode; d->m_setup.m_processChannelMode = mode;
} }
QProcess::ProcessError QtcProcess::error() const QProcess::ProcessError QtcProcess::error() const
@@ -1277,7 +1276,7 @@ QString QtcProcess::errorString() const
{ {
if (d->m_process) if (d->m_process)
return d->m_process->errorString(); return d->m_process->errorString();
return d->m_setup->m_errorString; return d->m_setup.m_errorString;
} }
void QtcProcess::setErrorString(const QString &str) void QtcProcess::setErrorString(const QString &str)
@@ -1285,7 +1284,7 @@ void QtcProcess::setErrorString(const QString &str)
if (d->m_process) if (d->m_process)
d->m_process->setErrorString(str); d->m_process->setErrorString(str);
else else
d->m_setup->m_errorString = str; d->m_setup.m_errorString = str;
} }
qint64 QtcProcess::processId() const qint64 QtcProcess::processId() const
@@ -1584,7 +1583,7 @@ void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
void QtcProcess::setWriteData(const QByteArray &writeData) void QtcProcess::setWriteData(const QByteArray &writeData)
{ {
d->m_setup->m_writeData = writeData; d->m_setup.m_writeData = writeData;
} }
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
@@ -1598,7 +1597,7 @@ void QtcProcess::runBlocking(EventLoopMode eventLoopMode)
{ {
// FIXME: Implement properly // FIXME: Implement properly
if (d->m_setup->m_commandLine.executable().needsDevice()) { if (d->m_setup.m_commandLine.executable().needsDevice()) {
QtcProcess::start(); QtcProcess::start();
waitForFinished(); waitForFinished();
return; return;
@@ -1696,7 +1695,7 @@ void QtcProcessPrivate::slotTimeout()
qDebug() << Q_FUNC_INFO << "HANG detected, killing"; qDebug() << Q_FUNC_INFO << "HANG detected, killing";
m_waitingForUser = true; m_waitingForUser = true;
const bool terminate = !m_timeOutMessageBoxEnabled const bool terminate = !m_timeOutMessageBoxEnabled
|| askToKill(m_setup->m_commandLine.executable().toString()); || askToKill(m_setup.m_commandLine.executable().toString());
m_waitingForUser = false; m_waitingForUser = false;
if (terminate) { if (terminate) {
q->stopProcess(); q->stopProcess();

View File

@@ -30,13 +30,14 @@
#include "environment.h" #include "environment.h"
#include "commandline.h" #include "commandline.h"
#include "processenums.h" #include "processenums.h"
#include "processinterface.h"
#include "qtcassert.h" #include "qtcassert.h"
#include <QProcess> #include <QProcess>
QT_FORWARD_DECLARE_CLASS(QDebug) QT_BEGIN_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QTextCodec) class QDebug;
class QTextCodec;
QT_END_NAMESPACE
class tst_QtcProcess; class tst_QtcProcess;
@@ -45,8 +46,9 @@ namespace Utils {
namespace Internal { class QtcProcessPrivate; } namespace Internal { class QtcProcessPrivate; }
class DeviceProcessHooks; class DeviceProcessHooks;
class ProcessInterface;
class QTCREATOR_UTILS_EXPORT QtcProcess : public ProcessInterface class QTCREATOR_UTILS_EXPORT QtcProcess : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -56,31 +58,31 @@ public:
// ProcessInterface related // ProcessInterface related
void start() override; virtual void start();
void interrupt() override; virtual void interrupt();
void terminate() override; virtual void terminate();
void kill() override; virtual void kill();
void close() final; void close();
QByteArray readAllStandardOutput() override; virtual QByteArray readAllStandardOutput();
QByteArray readAllStandardError() override; virtual QByteArray readAllStandardError();
qint64 write(const QByteArray &input) override; virtual qint64 write(const QByteArray &input);
qint64 processId() const override; virtual qint64 processId() const;
QProcess::ProcessState state() const override; virtual QProcess::ProcessState state() const;
int exitCode() const override; virtual int exitCode() const;
QProcess::ExitStatus exitStatus() const override; virtual QProcess::ExitStatus exitStatus() const;
QProcess::ProcessError error() const final; QProcess::ProcessError error() const;
QString errorString() const override; virtual QString errorString() const;
void setErrorString(const QString &str) final; void setErrorString(const QString &str);
bool waitForStarted(int msecs = 30000) final; bool waitForStarted(int msecs = 30000);
bool waitForReadyRead(int msecs = 30000) final; bool waitForReadyRead(int msecs = 30000);
bool waitForFinished(int msecs = 30000) final; bool waitForFinished(int msecs = 30000);
void kickoffProcess() final; void kickoffProcess();
qint64 applicationMainThreadID() const final; qint64 applicationMainThreadID() const;
// ProcessSetupData related // ProcessSetupData related
@@ -185,6 +187,13 @@ public:
QString toStandaloneCommandLine() const; QString toStandaloneCommandLine() const;
signals:
void started();
void finished();
void errorOccurred(QProcess::ProcessError error);
void readyReadStandardOutput();
void readyReadStandardError();
protected: protected:
// TODO: remove these methods on QtcProcess de-virtualization // TODO: remove these methods on QtcProcess de-virtualization
virtual void emitStarted(); virtual void emitStarted();