forked from qt-creator/qt-creator
Provide initial implementation for ProcessLauncherImpl
The initial implementation is a copy of QbsProcess with some small adaptations. Start a LauncherProcess in Creator's main function, just after the creation of the application object. Change-Id: I016df3ed664d7914c73f4a35742d5a63d5faaca0 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/launcherinterface.h>
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
#include <utils/qtcsettings.h>
|
#include <utils/qtcsettings.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
|
#include <QScopeGuard>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
@@ -548,6 +550,9 @@ int main(int argc, char **argv)
|
|||||||
QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));
|
QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR));
|
||||||
QGuiApplication::setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME);
|
QGuiApplication::setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME);
|
||||||
|
|
||||||
|
Utils::LauncherInterface::startLauncher();
|
||||||
|
auto cleanup = qScopeGuard([] { Utils::LauncherInterface::stopLauncher(); });
|
||||||
|
|
||||||
const QStringList pluginArguments = app.arguments();
|
const QStringList pluginArguments = app.arguments();
|
||||||
|
|
||||||
/*Initialize global settings and resetup install settings with QApplication::applicationDirPath */
|
/*Initialize global settings and resetup install settings with QApplication::applicationDirPath */
|
||||||
|
@@ -25,11 +25,14 @@
|
|||||||
|
|
||||||
#include "qtcprocess.h"
|
#include "qtcprocess.h"
|
||||||
|
|
||||||
#include "stringutils.h"
|
#include "commandline.h"
|
||||||
#include "executeondestruction.h"
|
#include "executeondestruction.h"
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
#include "commandline.h"
|
#include "launcherinterface.h"
|
||||||
|
#include "launcherpackets.h"
|
||||||
|
#include "launchersocket.h"
|
||||||
#include "qtcassert.h"
|
#include "qtcassert.h"
|
||||||
|
#include "stringutils.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -281,17 +284,26 @@ private:
|
|||||||
class ProcessLauncherImpl : public ProcessInterface
|
class ProcessLauncherImpl : public ProcessInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ProcessLauncherImpl() : ProcessInterface() {}
|
ProcessLauncherImpl() : ProcessInterface()
|
||||||
|
{
|
||||||
|
connect(LauncherInterface::socket(), &LauncherSocket::ready,
|
||||||
|
this, &ProcessLauncherImpl::handleSocketReady);
|
||||||
|
connect(LauncherInterface::socket(), &LauncherSocket::errorOccurred,
|
||||||
|
this, &ProcessLauncherImpl::handleSocketError);
|
||||||
|
connect(LauncherInterface::socket(), &LauncherSocket::packetArrived,
|
||||||
|
this, &ProcessLauncherImpl::handlePacket);
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray readAllStandardOutput() override { QTC_CHECK(false); return {}; }
|
QByteArray readAllStandardOutput() override { return readAndClear(m_stdout); }
|
||||||
QByteArray readAllStandardError() override { QTC_CHECK(false); return {}; }
|
QByteArray readAllStandardError() override { return readAndClear(m_stderr); }
|
||||||
|
|
||||||
void setProcessEnvironment(const QProcessEnvironment &environment) override { QTC_CHECK(false); }
|
void setProcessEnvironment(const QProcessEnvironment &environment) override
|
||||||
void setWorkingDirectory(const QString &dir) override { QTC_CHECK(false); }
|
{ m_environment = environment; }
|
||||||
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode) override { QTC_CHECK(false); }
|
void setWorkingDirectory(const QString &dir) override { m_workingDirectory = dir; }
|
||||||
void terminate() override { QTC_CHECK(false); }
|
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode) override;
|
||||||
void kill() override { QTC_CHECK(false); }
|
void terminate() override { cancel(); } // TODO: what are differences among terminate, kill and close?
|
||||||
void close() override { QTC_CHECK(false); }
|
void kill() override { cancel(); } // TODO: see above
|
||||||
|
void close() override { cancel(); } // TODO: see above
|
||||||
qint64 write(const QByteArray &data) override { QTC_CHECK(false); return -1; }
|
qint64 write(const QByteArray &data) override { QTC_CHECK(false); return -1; }
|
||||||
void closeWriteChannel() override { QTC_CHECK(false); }
|
void closeWriteChannel() override { QTC_CHECK(false); }
|
||||||
|
|
||||||
@@ -301,11 +313,11 @@ public:
|
|||||||
QProcess::ProcessChannel readChannel() const override { QTC_CHECK(false); return QProcess::StandardOutput; }
|
QProcess::ProcessChannel readChannel() const override { QTC_CHECK(false); return QProcess::StandardOutput; }
|
||||||
qint64 bytesAvailable() const override { QTC_CHECK(false); return 0; }
|
qint64 bytesAvailable() const override { QTC_CHECK(false); return 0; }
|
||||||
QString program() const override { QTC_CHECK(false); return {}; }
|
QString program() const override { QTC_CHECK(false); return {}; }
|
||||||
QProcess::ProcessError error() const override { QTC_CHECK(false); return QProcess::UnknownError; }
|
QProcess::ProcessError error() const override { return m_error; }
|
||||||
QProcess::ProcessState state() const override { QTC_CHECK(false); return QProcess::NotRunning; }
|
QProcess::ProcessState state() const override { return m_state; }
|
||||||
qint64 processId() const override { QTC_CHECK(false); return 0; }
|
qint64 processId() const override { QTC_CHECK(false); return 0; }
|
||||||
QProcess::ExitStatus exitStatus() const override { QTC_CHECK(false); return QProcess::NormalExit; }
|
QProcess::ExitStatus exitStatus() const override { QTC_CHECK(false); return QProcess::NormalExit; }
|
||||||
QString errorString() const override { QTC_CHECK(false); return {}; }
|
QString errorString() const override { return m_errorString; }
|
||||||
void setErrorString(const QString &str) override { QTC_CHECK(false); }
|
void setErrorString(const QString &str) override { QTC_CHECK(false); }
|
||||||
|
|
||||||
bool waitForStarted(int msecs) override { QTC_CHECK(false); return false; }
|
bool waitForStarted(int msecs) override { QTC_CHECK(false); return false; }
|
||||||
@@ -323,8 +335,147 @@ public:
|
|||||||
{ QTC_CHECK(false); }
|
{ QTC_CHECK(false); }
|
||||||
void setNativeArguments(const QString &arguments) override { QTC_CHECK(false); }
|
void setNativeArguments(const QString &arguments) override { QTC_CHECK(false); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void doStart();
|
||||||
|
void cancel();
|
||||||
|
void sendPacket(const Internal::LauncherPacket &packet)
|
||||||
|
{ LauncherInterface::socket()->sendData(packet.serialize()); }
|
||||||
|
QByteArray readAndClear(QByteArray &data)
|
||||||
|
{
|
||||||
|
const QByteArray tmp = data;
|
||||||
|
data.clear();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSocketError(const QString &message);
|
||||||
|
void handlePacket(Internal::LauncherPacketType type, quintptr token,
|
||||||
|
const QByteArray &payload);
|
||||||
|
void handleErrorPacket(const QByteArray &packetData);
|
||||||
|
void handleFinishedPacket(const QByteArray &packetData);
|
||||||
|
void handleSocketReady();
|
||||||
|
|
||||||
|
quintptr token() const { return reinterpret_cast<quintptr>(this); }
|
||||||
|
|
||||||
|
QString m_command;
|
||||||
|
QStringList m_arguments;
|
||||||
|
QProcessEnvironment m_environment;
|
||||||
|
QString m_workingDirectory;
|
||||||
|
QByteArray m_stdout;
|
||||||
|
QByteArray m_stderr;
|
||||||
|
QString m_errorString;
|
||||||
|
QProcess::ProcessError m_error = QProcess::UnknownError;
|
||||||
|
QProcess::ProcessState m_state = QProcess::NotRunning;
|
||||||
|
int m_exitCode = 0;
|
||||||
|
int m_connectionAttempts = 0;
|
||||||
|
bool m_socketError = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
|
||||||
|
{
|
||||||
|
// TODO: pass the open mode to StartProcessPacket
|
||||||
|
if (m_socketError) {
|
||||||
|
m_error = QProcess::FailedToStart;
|
||||||
|
emit errorOccurred(m_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_command = program;
|
||||||
|
m_arguments = arguments;
|
||||||
|
m_state = QProcess::Starting;
|
||||||
|
if (LauncherInterface::socket()->isReady())
|
||||||
|
doStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::doStart()
|
||||||
|
{
|
||||||
|
m_state = QProcess::Running;
|
||||||
|
StartProcessPacket p(token());
|
||||||
|
p.command = m_command;
|
||||||
|
p.arguments = m_arguments;
|
||||||
|
p.env = m_environment.toStringList();
|
||||||
|
p.workingDir = m_workingDirectory;
|
||||||
|
sendPacket(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::cancel()
|
||||||
|
{
|
||||||
|
switch (m_state) {
|
||||||
|
case QProcess::NotRunning:
|
||||||
|
break;
|
||||||
|
case QProcess::Starting:
|
||||||
|
m_errorString = QCoreApplication::translate("Utils::QtcProcess",
|
||||||
|
"Process canceled before it was started.");
|
||||||
|
m_error = QProcess::FailedToStart;
|
||||||
|
m_state = QProcess::NotRunning;
|
||||||
|
emit errorOccurred(m_error);
|
||||||
|
break;
|
||||||
|
case QProcess::Running:
|
||||||
|
sendPacket(StopProcessPacket(token()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::handlePacket(LauncherPacketType type, quintptr token, const QByteArray &payload)
|
||||||
|
{
|
||||||
|
if (token != this->token())
|
||||||
|
return;
|
||||||
|
switch (type) {
|
||||||
|
case LauncherPacketType::ProcessError:
|
||||||
|
handleErrorPacket(payload);
|
||||||
|
break;
|
||||||
|
case LauncherPacketType::ProcessFinished:
|
||||||
|
handleFinishedPacket(payload);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
QTC_ASSERT(false, break);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::handleSocketReady()
|
||||||
|
{
|
||||||
|
m_socketError = false;
|
||||||
|
if (m_state == QProcess::Starting)
|
||||||
|
doStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::handleSocketError(const QString &message)
|
||||||
|
{
|
||||||
|
m_socketError = true;
|
||||||
|
m_errorString = QCoreApplication::translate("Utils::QtcProcess",
|
||||||
|
"Internal socket error: %1").arg(message);
|
||||||
|
if (m_state != QProcess::NotRunning) {
|
||||||
|
m_state = QProcess::NotRunning;
|
||||||
|
m_error = QProcess::FailedToStart;
|
||||||
|
emit errorOccurred(m_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::handleErrorPacket(const QByteArray &packetData)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_state != QProcess::NotRunning, return);
|
||||||
|
const auto packet = LauncherPacket::extractPacket<ProcessErrorPacket>(token(), packetData);
|
||||||
|
m_error = packet.error;
|
||||||
|
m_errorString = packet.errorString;
|
||||||
|
m_state = QProcess::NotRunning;
|
||||||
|
emit errorOccurred(m_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessLauncherImpl::handleFinishedPacket(const QByteArray &packetData)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_state == QProcess::Running, return);
|
||||||
|
m_state = QProcess::NotRunning;
|
||||||
|
const auto packet = LauncherPacket::extractPacket<ProcessFinishedPacket>(token(), packetData);
|
||||||
|
m_exitCode = packet.exitCode;
|
||||||
|
m_stdout = packet.stdOut;
|
||||||
|
m_stderr = packet.stdErr;
|
||||||
|
if (!m_stdout.isEmpty())
|
||||||
|
emit readyReadStandardOutput();
|
||||||
|
if (!m_stderr.isEmpty())
|
||||||
|
emit readyReadStandardError();
|
||||||
|
m_errorString = packet.errorString;
|
||||||
|
emit finished(m_exitCode, packet.exitStatus);
|
||||||
|
}
|
||||||
|
|
||||||
static ProcessInterface *newProcessInstance(QtcProcess::ProcessImpl processImpl)
|
static ProcessInterface *newProcessInstance(QtcProcess::ProcessImpl processImpl)
|
||||||
{
|
{
|
||||||
if (processImpl == QtcProcess::QProcessImpl)
|
if (processImpl == QtcProcess::QProcessImpl)
|
||||||
|
Reference in New Issue
Block a user