2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2010-10-14 18:05:43 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2010-10-14 18:05:43 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2010-10-14 18:05:43 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:58:39 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2010-10-14 18:05:43 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 17:14:20 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2016-03-18 07:55:01 +01:00
|
|
|
#pragma once
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-05-05 18:21:22 +02:00
|
|
|
#include "utils_global.h"
|
|
|
|
|
|
2010-10-14 18:05:43 +02:00
|
|
|
#include "environment.h"
|
2021-05-11 14:34:56 +02:00
|
|
|
#include "commandline.h"
|
2021-08-06 16:20:47 +02:00
|
|
|
#include "processutils.h"
|
2022-02-14 11:14:08 +01:00
|
|
|
#include "qtcassert.h"
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2013-03-18 14:47:33 +01:00
|
|
|
#include <QProcess>
|
2021-05-05 18:21:22 +02:00
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
|
|
QT_FORWARD_DECLARE_CLASS(QDebug)
|
2022-01-25 13:55:54 +01:00
|
|
|
QT_FORWARD_DECLARE_CLASS(QTextCodec)
|
2013-03-18 14:47:33 +01:00
|
|
|
|
2021-06-14 15:09:11 +02:00
|
|
|
class tst_QtcProcess;
|
|
|
|
|
|
2010-10-14 18:05:43 +02:00
|
|
|
namespace Utils {
|
2021-05-05 18:21:22 +02:00
|
|
|
|
2022-02-14 11:14:08 +01:00
|
|
|
class ProcessInterface;
|
2021-05-26 17:40:57 +02:00
|
|
|
class QtcProcess;
|
2021-05-05 18:21:22 +02:00
|
|
|
|
2021-05-06 11:15:28 +02:00
|
|
|
namespace Internal { class QtcProcessPrivate; }
|
|
|
|
|
|
2021-05-26 17:40:57 +02:00
|
|
|
class DeviceProcessHooks
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
std::function<void(QtcProcess &)> startProcessHook;
|
|
|
|
|
std::function<Environment(const FilePath &)> systemEnvironmentForBinary;
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-14 15:21:54 +02:00
|
|
|
class QTCREATOR_UTILS_EXPORT QtcProcess : public QObject
|
2021-05-05 18:21:22 +02:00
|
|
|
{
|
2021-05-12 14:25:50 +02:00
|
|
|
Q_OBJECT
|
|
|
|
|
|
2021-05-05 18:21:22 +02:00
|
|
|
public:
|
2022-02-10 19:25:03 +01:00
|
|
|
QtcProcess(QObject *parent = nullptr);
|
|
|
|
|
~QtcProcess();
|
|
|
|
|
|
2021-07-09 09:09:05 +02:00
|
|
|
enum ProcessImpl {
|
|
|
|
|
QProcessImpl,
|
2022-01-27 17:00:01 +01:00
|
|
|
ProcessLauncherImpl,
|
|
|
|
|
DefaultImpl,
|
2021-07-09 09:09:05 +02:00
|
|
|
};
|
|
|
|
|
|
2022-01-21 16:15:17 +01:00
|
|
|
enum TerminalMode {
|
|
|
|
|
TerminalOff,
|
|
|
|
|
TerminalRun,
|
|
|
|
|
TerminalDebug,
|
|
|
|
|
TerminalSuspend,
|
|
|
|
|
TerminalOn = TerminalRun // default mode for ON
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-05 18:21:22 +02:00
|
|
|
enum Result {
|
2021-05-28 13:19:38 +02:00
|
|
|
// Finished successfully. Unless an ExitCodeInterpreter is set
|
|
|
|
|
// this corresponds to a return code 0.
|
|
|
|
|
FinishedWithSuccess,
|
|
|
|
|
Finished = FinishedWithSuccess, // FIXME: Kept to ease downstream transition
|
|
|
|
|
// Finished unsuccessfully. Unless an ExitCodeInterpreter is set
|
|
|
|
|
// this corresponds to a return code different from 0.
|
|
|
|
|
FinishedWithError,
|
|
|
|
|
FinishedError = FinishedWithError, // FIXME: Kept to ease downstream transition
|
2021-05-05 18:21:22 +02:00
|
|
|
// Process terminated abnormally (kill)
|
|
|
|
|
TerminatedAbnormally,
|
|
|
|
|
// Executable could not be started
|
|
|
|
|
StartFailed,
|
|
|
|
|
// Hang, no output after time out
|
2021-05-28 13:19:38 +02:00
|
|
|
Hang
|
|
|
|
|
};
|
2021-05-05 18:21:22 +02:00
|
|
|
|
2022-02-14 11:14:08 +01:00
|
|
|
void setProcessInterface(ProcessInterface *interface);
|
|
|
|
|
|
2022-02-10 19:25:03 +01:00
|
|
|
void setProcessImpl(ProcessImpl processImpl);
|
|
|
|
|
|
|
|
|
|
void setTerminalMode(TerminalMode mode);
|
|
|
|
|
bool usesTerminal() const { return terminalMode() != TerminalOff; }
|
|
|
|
|
TerminalMode terminalMode() const;
|
|
|
|
|
|
|
|
|
|
void setProcessMode(ProcessMode processMode);
|
|
|
|
|
ProcessMode processMode() const;
|
|
|
|
|
|
2021-05-05 16:05:53 +02:00
|
|
|
void setEnvironment(const Environment &env);
|
2021-07-23 11:13:59 +02:00
|
|
|
void unsetEnvironment();
|
2021-05-05 16:05:53 +02:00
|
|
|
const Environment &environment() const;
|
2022-02-03 13:20:15 +01:00
|
|
|
bool hasEnvironment() const;
|
2021-05-05 16:05:53 +02:00
|
|
|
|
|
|
|
|
void setCommand(const CommandLine &cmdLine);
|
|
|
|
|
const CommandLine &commandLine() const;
|
2019-05-28 18:59:45 +02:00
|
|
|
|
2021-06-03 10:39:15 +02:00
|
|
|
FilePath workingDirectory() const;
|
|
|
|
|
void setWorkingDirectory(const FilePath &dir);
|
2021-05-14 15:21:54 +02:00
|
|
|
|
2014-05-16 15:57:02 +02:00
|
|
|
void setUseCtrlCStub(bool enabled);
|
2021-05-05 16:05:53 +02:00
|
|
|
void setLowPriority();
|
|
|
|
|
void setDisableUnixTerminal();
|
2021-09-08 14:51:49 +02:00
|
|
|
void setRunAsRoot(bool on);
|
2022-02-01 14:51:23 +01:00
|
|
|
bool isRunAsRoot() const;
|
2021-05-05 16:05:53 +02:00
|
|
|
|
2022-01-21 16:15:17 +01:00
|
|
|
void setAbortOnMetaChars(bool abort);
|
|
|
|
|
|
2022-02-11 17:38:16 +01:00
|
|
|
virtual void start();
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual void terminate();
|
|
|
|
|
virtual void interrupt();
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-08-25 12:34:54 +02:00
|
|
|
static bool startDetached(const CommandLine &cmd, const FilePath &workingDirectory = {},
|
2021-08-12 12:33:28 +02:00
|
|
|
qint64 *pid = nullptr);
|
2022-01-24 19:57:52 +01:00
|
|
|
|
|
|
|
|
enum EventLoopMode {
|
|
|
|
|
NoEventLoop,
|
|
|
|
|
WithEventLoop // Avoid
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Starts the command and waits for finish.
|
|
|
|
|
// User input processing is enabled when WithEventLoop was passed.
|
|
|
|
|
void runBlocking(EventLoopMode eventLoopMode = NoEventLoop);
|
2021-06-22 04:24:13 +02:00
|
|
|
|
2021-05-06 11:15:28 +02:00
|
|
|
/* Timeout for hanging processes (triggers after no more output
|
|
|
|
|
* occurs on stderr/stdout). */
|
|
|
|
|
void setTimeoutS(int timeoutS);
|
|
|
|
|
|
|
|
|
|
void setCodec(QTextCodec *c);
|
|
|
|
|
void setTimeOutMessageBoxEnabled(bool);
|
2021-05-12 14:25:50 +02:00
|
|
|
void setExitCodeInterpreter(const std::function<QtcProcess::Result(int)> &interpreter);
|
2021-05-06 11:15:28 +02:00
|
|
|
|
2021-05-06 17:54:28 +02:00
|
|
|
void setWriteData(const QByteArray &writeData);
|
|
|
|
|
|
2021-05-06 11:15:28 +02:00
|
|
|
void setStdOutCallback(const std::function<void(const QString &)> &callback);
|
2021-06-04 11:40:35 +02:00
|
|
|
void setStdOutLineCallback(const std::function<void(const QString &)> &callback);
|
2021-05-06 11:15:28 +02:00
|
|
|
void setStdErrCallback(const std::function<void(const QString &)> &callback);
|
2021-06-04 11:40:35 +02:00
|
|
|
void setStdErrLineCallback(const std::function<void(const QString &)> &callback);
|
2021-05-06 11:15:28 +02:00
|
|
|
|
2021-05-26 17:40:57 +02:00
|
|
|
static void setRemoteProcessHooks(const DeviceProcessHooks &hooks);
|
2014-02-05 10:43:21 +01:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
bool stopProcess();
|
|
|
|
|
bool readDataFromProcess(int timeoutS, QByteArray *stdOut, QByteArray *stdErr,
|
|
|
|
|
bool showTimeOutMessageBox);
|
|
|
|
|
|
|
|
|
|
static QString normalizeNewlines(const QString &text);
|
|
|
|
|
|
2021-05-12 14:25:50 +02:00
|
|
|
Result result() const;
|
|
|
|
|
void setResult(Result result);
|
|
|
|
|
|
|
|
|
|
QByteArray allRawOutput() const;
|
|
|
|
|
QString allOutput() const;
|
|
|
|
|
|
|
|
|
|
QString stdOut() const;
|
|
|
|
|
QString stdErr() const;
|
|
|
|
|
|
|
|
|
|
QByteArray rawStdOut() const;
|
|
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual int exitCode() const;
|
2021-05-12 14:25:50 +02:00
|
|
|
|
2021-05-14 13:12:46 +02:00
|
|
|
QString exitMessage();
|
2021-05-12 14:25:50 +02:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
// Helpers to find binaries. Do not use it for other path variables
|
|
|
|
|
// and file types.
|
|
|
|
|
static QString locateBinary(const QString &binary);
|
|
|
|
|
static QString locateBinary(const QString &path, const QString &binary);
|
|
|
|
|
|
2021-05-26 17:40:57 +02:00
|
|
|
static Environment systemEnvironmentForBinary(const FilePath &filePath);
|
|
|
|
|
|
2022-01-25 11:29:23 +01:00
|
|
|
void kickoffProcess();
|
|
|
|
|
void interruptProcess();
|
|
|
|
|
qint64 applicationMainThreadID() const;
|
|
|
|
|
|
2021-05-14 15:21:54 +02:00
|
|
|
// FIXME: Cut down the following bits inherited from QProcess and QIODevice.
|
|
|
|
|
|
|
|
|
|
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
|
|
|
|
|
|
|
|
|
QProcess::ProcessError error() const;
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual QProcess::ProcessState state() const;
|
2021-11-22 11:21:35 +01:00
|
|
|
bool isRunning() const; // Short for state() == QProcess::Running.
|
2021-05-14 15:21:54 +02:00
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual QString errorString() const;
|
2021-05-14 15:21:54 +02:00
|
|
|
void setErrorString(const QString &str);
|
|
|
|
|
|
|
|
|
|
qint64 processId() const;
|
|
|
|
|
|
|
|
|
|
bool waitForStarted(int msecs = 30000);
|
|
|
|
|
bool waitForReadyRead(int msecs = 30000);
|
|
|
|
|
bool waitForFinished(int msecs = 30000);
|
|
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual QByteArray readAllStandardOutput();
|
|
|
|
|
virtual QByteArray readAllStandardError();
|
2021-05-14 15:21:54 +02:00
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual QProcess::ExitStatus exitStatus() const;
|
2021-05-14 15:21:54 +02:00
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual void kill();
|
2021-05-14 15:21:54 +02:00
|
|
|
|
2022-01-27 19:09:06 +01:00
|
|
|
virtual qint64 write(const QByteArray &input);
|
2021-05-14 15:21:54 +02:00
|
|
|
void close();
|
|
|
|
|
|
2021-06-28 17:39:14 +02:00
|
|
|
void setStandardInputFile(const QString &inputFile);
|
|
|
|
|
|
2021-09-09 23:03:39 +02:00
|
|
|
QString toStandaloneCommandLine() const;
|
|
|
|
|
|
2022-02-11 17:38:16 +01:00
|
|
|
void setExtraData(const QString &key, const QVariant &value);
|
|
|
|
|
QVariant extraData(const QString &key) const;
|
|
|
|
|
|
|
|
|
|
void setExtraData(const QVariantHash &extraData);
|
|
|
|
|
QVariantHash extraData() const;
|
|
|
|
|
|
2021-05-14 15:21:54 +02:00
|
|
|
signals:
|
|
|
|
|
void started();
|
2021-05-28 14:48:25 +02:00
|
|
|
void finished();
|
2021-05-14 15:21:54 +02:00
|
|
|
void errorOccurred(QProcess::ProcessError error);
|
|
|
|
|
void readyReadStandardOutput();
|
|
|
|
|
void readyReadStandardError();
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
private:
|
2021-05-14 19:00:50 +02:00
|
|
|
friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r);
|
2021-05-12 14:25:50 +02:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
Internal::QtcProcessPrivate *d = nullptr;
|
|
|
|
|
|
2021-06-14 15:09:11 +02:00
|
|
|
friend tst_QtcProcess;
|
|
|
|
|
void beginFeed();
|
|
|
|
|
void feedStdOut(const QByteArray &data);
|
|
|
|
|
void endFeed();
|
2021-05-06 13:07:36 +02:00
|
|
|
};
|
|
|
|
|
|
2022-02-14 11:14:08 +01:00
|
|
|
class QTCREATOR_UTILS_EXPORT ProcessSetupData
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
QtcProcess::ProcessImpl m_processImpl = QtcProcess::DefaultImpl;
|
|
|
|
|
ProcessMode m_processMode = ProcessMode::Reader;
|
|
|
|
|
QtcProcess::TerminalMode m_terminalMode = QtcProcess::TerminalOff;
|
|
|
|
|
|
2022-02-15 14:36:24 +01:00
|
|
|
CommandLine m_commandLine;
|
|
|
|
|
FilePath m_workingDirectory;
|
|
|
|
|
Environment m_environment;
|
|
|
|
|
QByteArray m_writeData;
|
|
|
|
|
bool m_runAsRoot = false;
|
|
|
|
|
bool m_haveEnv = false;
|
|
|
|
|
bool m_useCtrlCStub = false;
|
|
|
|
|
QVariantHash m_extraData;
|
|
|
|
|
|
2022-02-14 11:14:08 +01:00
|
|
|
QString m_nativeArguments;
|
|
|
|
|
QString m_standardInputFile;
|
|
|
|
|
QString m_initialErrorString;
|
|
|
|
|
bool m_belowNormalPriority = false;
|
|
|
|
|
bool m_lowPriority = false;
|
|
|
|
|
bool m_unixTerminalDisabled = false;
|
|
|
|
|
bool m_abortOnMetaChars = true;
|
|
|
|
|
QProcess::ProcessChannelMode m_procesChannelMode = QProcess::SeparateChannels;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ProcessInterface(QObject *parent, ProcessMode processMode)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
, m_processMode(processMode) {}
|
|
|
|
|
|
|
|
|
|
virtual QByteArray readAllStandardOutput() = 0;
|
|
|
|
|
virtual QByteArray readAllStandardError() = 0;
|
|
|
|
|
|
2022-02-16 01:48:40 +01:00
|
|
|
virtual void start() { defaultStart(); }
|
2022-02-14 11:14:08 +01:00
|
|
|
virtual void terminate() = 0;
|
|
|
|
|
virtual void kill() = 0;
|
|
|
|
|
virtual void close() = 0;
|
|
|
|
|
virtual qint64 write(const QByteArray &data) = 0;
|
|
|
|
|
|
|
|
|
|
virtual QProcess::ProcessError error() const = 0;
|
|
|
|
|
virtual QProcess::ProcessState state() const = 0;
|
|
|
|
|
virtual qint64 processId() const = 0;
|
|
|
|
|
virtual int exitCode() const = 0;
|
|
|
|
|
virtual QProcess::ExitStatus exitStatus() const = 0;
|
|
|
|
|
virtual QString errorString() const = 0;
|
|
|
|
|
virtual void setErrorString(const QString &str) = 0;
|
|
|
|
|
|
|
|
|
|
virtual bool waitForStarted(int msecs) = 0;
|
|
|
|
|
virtual bool waitForReadyRead(int msecs) = 0;
|
|
|
|
|
virtual bool waitForFinished(int msecs) = 0;
|
|
|
|
|
|
|
|
|
|
virtual void kickoffProcess() { QTC_CHECK(false); }
|
|
|
|
|
virtual void interruptProcess() { QTC_CHECK(false); }
|
|
|
|
|
virtual qint64 applicationMainThreadID() const { QTC_CHECK(false); return -1; }
|
|
|
|
|
|
|
|
|
|
const ProcessMode m_processMode;
|
2022-02-15 17:50:33 +01:00
|
|
|
ProcessSetupData m_setup;
|
2022-02-14 11:14:08 +01:00
|
|
|
|
|
|
|
|
signals:
|
|
|
|
|
void started();
|
|
|
|
|
void finished(int exitCode, QProcess::ExitStatus status);
|
|
|
|
|
void errorOccurred(QProcess::ProcessError error);
|
|
|
|
|
void readyReadStandardOutput();
|
|
|
|
|
void readyReadStandardError();
|
2022-02-16 01:48:40 +01:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void defaultStart();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
virtual void doDefaultStart(const QString &program, const QStringList &arguments)
|
|
|
|
|
{ Q_UNUSED(program) Q_UNUSED(arguments) QTC_CHECK(false); }
|
|
|
|
|
bool dissolveCommand(QString *program, QStringList *arguments);
|
|
|
|
|
bool ensureProgramExists(const QString &program);
|
2022-02-14 11:14:08 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2021-05-12 14:25:50 +02:00
|
|
|
using ExitCodeInterpreter = std::function<QtcProcess::Result(int /*exitCode*/)>;
|
|
|
|
|
|
2013-07-12 09:00:12 +02:00
|
|
|
} // namespace Utils
|