forked from qt-creator/qt-creator
RemoteLinux: Support terminal aspect
This is possible now that the remote process is started via a local tool. [ChangeLog] Remote Linux applications can be run in a terminal now. Change-Id: I9f7df87563a18880d85c6d16ad18fb10a4d9f0e0 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -84,20 +85,15 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList
|
|||||||
void SshRemoteProcess::doStart()
|
void SshRemoteProcess::doStart()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isRunning(), return);
|
QTC_ASSERT(!isRunning(), return);
|
||||||
QStringList args = QStringList("-q") << d->connectionArgs;
|
const QStringList args = fullLocalCommandLine();
|
||||||
if (d->useTerminal)
|
|
||||||
args.prepend("-tt");
|
|
||||||
if (!d->displayName.isEmpty()) {
|
if (!d->displayName.isEmpty()) {
|
||||||
args.prepend("-X");
|
|
||||||
QProcessEnvironment env = processEnvironment();
|
QProcessEnvironment env = processEnvironment();
|
||||||
env.insert("DISPLAY", d->displayName);
|
env.insert("DISPLAY", d->displayName);
|
||||||
setProcessEnvironment(env);
|
setProcessEnvironment(env);
|
||||||
}
|
}
|
||||||
if (!d->remoteCommand.isEmpty())
|
qCDebug(sshLog) << "starting remote process:" << QDir::toNativeSeparators(args.first())
|
||||||
args << QLatin1String(d->remoteCommand);
|
|
||||||
qCDebug(sshLog) << "starting remote process:" << SshSettings::sshFilePath().toUserOutput()
|
|
||||||
<< args;
|
<< args;
|
||||||
QProcess::start(SshSettings::sshFilePath().toString(), args);
|
QProcess::start(args.first(), args.mid(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
SshRemoteProcess::~SshRemoteProcess()
|
SshRemoteProcess::~SshRemoteProcess()
|
||||||
@@ -125,4 +121,17 @@ bool SshRemoteProcess::isRunning() const
|
|||||||
return state() == QProcess::Running;
|
return state() == QProcess::Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList SshRemoteProcess::fullLocalCommandLine() const
|
||||||
|
{
|
||||||
|
QStringList args = QStringList("-q") << d->connectionArgs;
|
||||||
|
if (d->useTerminal)
|
||||||
|
args.prepend("-tt");
|
||||||
|
if (!d->displayName.isEmpty())
|
||||||
|
args.prepend("-X");
|
||||||
|
if (!d->remoteCommand.isEmpty())
|
||||||
|
args << QLatin1String(d->remoteCommand);
|
||||||
|
args.prepend(SshSettings::sshFilePath().toString());
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QSsh
|
} // namespace QSsh
|
||||||
|
@@ -50,6 +50,7 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
|
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
|
QStringList fullLocalCommandLine() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void done(const QString &error);
|
void done(const QString &error);
|
||||||
|
@@ -411,6 +411,7 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
|
|||||||
m_success = true;
|
m_success = true;
|
||||||
|
|
||||||
m_deviceProcess = device->createProcess(this);
|
m_deviceProcess = device->createProcess(this);
|
||||||
|
m_deviceProcess->setRunInTerminal(m_useTerminal);
|
||||||
connect(m_deviceProcess, &DeviceProcess::started,
|
connect(m_deviceProcess, &DeviceProcess::started,
|
||||||
q, &ApplicationLauncher::remoteProcessStarted);
|
q, &ApplicationLauncher::remoteProcessStarted);
|
||||||
connect(m_deviceProcess, &DeviceProcess::readyReadStandardOutput,
|
connect(m_deviceProcess, &DeviceProcess::readyReadStandardOutput,
|
||||||
|
@@ -57,6 +57,9 @@ public:
|
|||||||
|
|
||||||
virtual qint64 write(const QByteArray &data) = 0;
|
virtual qint64 write(const QByteArray &data) = 0;
|
||||||
|
|
||||||
|
void setRunInTerminal(bool term) { m_runInTerminal = term; }
|
||||||
|
bool runInTerminal() const { return m_runInTerminal; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void started();
|
void started();
|
||||||
void finished();
|
void finished();
|
||||||
@@ -71,6 +74,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const QSharedPointer<const IDevice> m_device;
|
const QSharedPointer<const IDevice> m_device;
|
||||||
|
bool m_runInTerminal = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -31,12 +31,15 @@
|
|||||||
#include <ssh/sshconnection.h>
|
#include <ssh/sshconnection.h>
|
||||||
#include <ssh/sshconnectionmanager.h>
|
#include <ssh/sshconnectionmanager.h>
|
||||||
#include <ssh/sshremoteprocess.h>
|
#include <ssh/sshremoteprocess.h>
|
||||||
|
#include <utils/consoleprocess.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
enum class Signal { Interrupt, Terminate, Kill };
|
enum class Signal { Interrupt, Terminate, Kill };
|
||||||
@@ -49,6 +52,7 @@ public:
|
|||||||
SshDeviceProcess * const q;
|
SshDeviceProcess * const q;
|
||||||
QSsh::SshConnection *connection = nullptr;
|
QSsh::SshConnection *connection = nullptr;
|
||||||
QSsh::SshRemoteProcessPtr process;
|
QSsh::SshRemoteProcessPtr process;
|
||||||
|
ConsoleProcess consoleProcess;
|
||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
|
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
|
||||||
@@ -114,11 +118,15 @@ void SshDeviceProcess::interrupt()
|
|||||||
void SshDeviceProcess::terminate()
|
void SshDeviceProcess::terminate()
|
||||||
{
|
{
|
||||||
d->doSignal(Signal::Terminate);
|
d->doSignal(Signal::Terminate);
|
||||||
|
if (runInTerminal())
|
||||||
|
d->consoleProcess.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshDeviceProcess::kill()
|
void SshDeviceProcess::kill()
|
||||||
{
|
{
|
||||||
d->doSignal(Signal::Kill);
|
d->doSignal(Signal::Kill);
|
||||||
|
if (runInTerminal())
|
||||||
|
d->consoleProcess.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
QProcess::ProcessState SshDeviceProcess::state() const
|
QProcess::ProcessState SshDeviceProcess::state() const
|
||||||
@@ -178,16 +186,32 @@ void SshDeviceProcess::handleConnected()
|
|||||||
d->setState(SshDeviceProcessPrivate::Connected);
|
d->setState(SshDeviceProcessPrivate::Connected);
|
||||||
|
|
||||||
d->process = d->connection->createRemoteProcess(fullCommandLine(d->runnable).toUtf8());
|
d->process = d->connection->createRemoteProcess(fullCommandLine(d->runnable).toUtf8());
|
||||||
connect(d->process.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted);
|
|
||||||
connect(d->process.get(), &QSsh::SshRemoteProcess::done, this, &SshDeviceProcess::handleProcessFinished);
|
|
||||||
connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &SshDeviceProcess::handleStdout);
|
|
||||||
connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardError, this, &SshDeviceProcess::handleStderr);
|
|
||||||
|
|
||||||
const QString display = d->displayName();
|
const QString display = d->displayName();
|
||||||
if (!display.isEmpty())
|
if (!display.isEmpty())
|
||||||
d->process->requestX11Forwarding(display);
|
d->process->requestX11Forwarding(display);
|
||||||
|
if (runInTerminal()) {
|
||||||
|
d->process->requestTerminal();
|
||||||
|
const QStringList cmdLine = d->process->fullLocalCommandLine();
|
||||||
|
connect(&d->consoleProcess,
|
||||||
|
static_cast<void (ConsoleProcess::*)(QProcess::ProcessError)>(&ConsoleProcess::error),
|
||||||
|
this, &DeviceProcess::error);
|
||||||
|
connect(&d->consoleProcess, &ConsoleProcess::processStarted,
|
||||||
|
this, &SshDeviceProcess::handleProcessStarted);
|
||||||
|
connect(&d->consoleProcess, &ConsoleProcess::stubStopped,
|
||||||
|
this, [this] { handleProcessFinished(d->consoleProcess.errorString()); });
|
||||||
|
d->consoleProcess.start(cmdLine.first(), cmdLine.mid(1).join(' '));
|
||||||
|
} else {
|
||||||
|
connect(d->process.get(), &QSsh::SshRemoteProcess::started,
|
||||||
|
this, &SshDeviceProcess::handleProcessStarted);
|
||||||
|
connect(d->process.get(), &QSsh::SshRemoteProcess::done,
|
||||||
|
this, &SshDeviceProcess::handleProcessFinished);
|
||||||
|
connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||||
|
this, &SshDeviceProcess::handleStdout);
|
||||||
|
connect(d->process.get(), &QSsh::SshRemoteProcess::readyReadStandardError,
|
||||||
|
this, &SshDeviceProcess::handleStderr);
|
||||||
d->process->start();
|
d->process->start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SshDeviceProcess::handleConnectionError()
|
void SshDeviceProcess::handleConnectionError()
|
||||||
{
|
{
|
||||||
@@ -226,7 +250,7 @@ void SshDeviceProcess::handleProcessStarted()
|
|||||||
void SshDeviceProcess::handleProcessFinished(const QString &error)
|
void SshDeviceProcess::handleProcessFinished(const QString &error)
|
||||||
{
|
{
|
||||||
d->errorMessage = error;
|
d->errorMessage = error;
|
||||||
d->exitCode = d->process->exitCode();
|
d->exitCode = runInTerminal() ? d->consoleProcess.exitCode() : d->process->exitCode();
|
||||||
d->setState(SshDeviceProcessPrivate::Inactive);
|
d->setState(SshDeviceProcessPrivate::Inactive);
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
@@ -327,6 +351,7 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe
|
|||||||
killOperation.clear();
|
killOperation.clear();
|
||||||
}
|
}
|
||||||
killTimer.stop();
|
killTimer.stop();
|
||||||
|
consoleProcess.disconnect();
|
||||||
if (process)
|
if (process)
|
||||||
process->disconnect(q);
|
process->disconnect(q);
|
||||||
if (connection) {
|
if (connection) {
|
||||||
@@ -338,6 +363,7 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe
|
|||||||
|
|
||||||
qint64 SshDeviceProcess::write(const QByteArray &data)
|
qint64 SshDeviceProcess::write(const QByteArray &data)
|
||||||
{
|
{
|
||||||
|
QTC_ASSERT(!runInTerminal(), return -1);
|
||||||
return d->process->write(data);
|
return d->process->write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ void LinuxDeviceProcess::setRcFilesToSource(const QStringList &filePaths)
|
|||||||
QByteArray LinuxDeviceProcess::readAllStandardOutput()
|
QByteArray LinuxDeviceProcess::readAllStandardOutput()
|
||||||
{
|
{
|
||||||
QByteArray output = SshDeviceProcess::readAllStandardOutput();
|
QByteArray output = SshDeviceProcess::readAllStandardOutput();
|
||||||
if (m_processId != 0)
|
if (m_processId != 0 || runInTerminal())
|
||||||
return output;
|
return output;
|
||||||
|
|
||||||
m_processIdString.append(output);
|
m_processIdString.append(output);
|
||||||
@@ -91,9 +91,11 @@ QString LinuxDeviceProcess::fullCommandLine(const Runnable &runnable) const
|
|||||||
envString.append(env.key(it)).append(QLatin1String("='")).append(env.value(it))
|
envString.append(env.key(it)).append(QLatin1String("='")).append(env.value(it))
|
||||||
.append(QLatin1Char('\''));
|
.append(QLatin1Char('\''));
|
||||||
}
|
}
|
||||||
|
if (!runInTerminal())
|
||||||
fullCommandLine.append("echo $$ && ");
|
fullCommandLine.append("echo $$ && ");
|
||||||
if (!envString.isEmpty())
|
if (!envString.isEmpty())
|
||||||
fullCommandLine.append(envString);
|
fullCommandLine.append(envString);
|
||||||
|
if (!runInTerminal())
|
||||||
fullCommandLine.append(" exec ");
|
fullCommandLine.append(" exec ");
|
||||||
fullCommandLine.append(quote(runnable.executable));
|
fullCommandLine.append(quote(runnable.executable));
|
||||||
if (!runnable.commandLineArguments.isEmpty()) {
|
if (!runnable.commandLineArguments.isEmpty()) {
|
||||||
|
@@ -60,6 +60,8 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar
|
|||||||
|
|
||||||
addAspect<ArgumentsAspect>();
|
addAspect<ArgumentsAspect>();
|
||||||
addAspect<WorkingDirectoryAspect>();
|
addAspect<WorkingDirectoryAspect>();
|
||||||
|
if (HostOsInfo::isAnyUnixHost())
|
||||||
|
addAspect<TerminalAspect>();
|
||||||
addAspect<RemoteLinuxEnvironmentAspect>(target);
|
addAspect<RemoteLinuxEnvironmentAspect>(target);
|
||||||
if (Utils::HostOsInfo::isAnyUnixHost())
|
if (Utils::HostOsInfo::isAnyUnixHost())
|
||||||
addAspect<X11ForwardingAspect>();
|
addAspect<X11ForwardingAspect>();
|
||||||
|
@@ -34,7 +34,7 @@ namespace RemoteLinux {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl)
|
LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl)
|
||||||
: DebuggerRunTool(runControl)
|
: DebuggerRunTool(runControl, nullptr, false)
|
||||||
{
|
{
|
||||||
setId("LinuxDeviceDebugSupport");
|
setId("LinuxDeviceDebugSupport");
|
||||||
|
|
||||||
|
@@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
#include <qtsupport/qtoutputformatter.h>
|
#include <qtsupport/qtoutputformatter.h>
|
||||||
|
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
@@ -60,6 +62,8 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Core::I
|
|||||||
|
|
||||||
addAspect<ArgumentsAspect>();
|
addAspect<ArgumentsAspect>();
|
||||||
addAspect<WorkingDirectoryAspect>();
|
addAspect<WorkingDirectoryAspect>();
|
||||||
|
if (HostOsInfo::isAnyUnixHost())
|
||||||
|
addAspect<TerminalAspect>();
|
||||||
addAspect<RemoteLinuxEnvironmentAspect>(target);
|
addAspect<RemoteLinuxEnvironmentAspect>(target);
|
||||||
if (id == IdPrefix && Utils::HostOsInfo::isAnyUnixHost())
|
if (id == IdPrefix && Utils::HostOsInfo::isAnyUnixHost())
|
||||||
addAspect<X11ForwardingAspect>();
|
addAspect<X11ForwardingAspect>();
|
||||||
|
Reference in New Issue
Block a user