Ssh: Re-base SshProcess on top of QtcProcess

Change-Id: I266820e0e2ea12d6e4a5a83a679a7279fab9cd83
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2021-06-25 14:54:27 +02:00
parent 77fed0b0fd
commit f72c4cb8ac
18 changed files with 116 additions and 105 deletions

View File

@@ -58,7 +58,7 @@ struct Command
struct SftpSession::SftpSessionPrivate struct SftpSession::SftpSessionPrivate
{ {
SshProcess sftpProc; SshProcess sftpProc = {ProcessMode::Writer};
QStringList connectionArgs; QStringList connectionArgs;
QByteArray output; QByteArray output;
QQueue<Command> pendingCommands; QQueue<Command> pendingCommands;
@@ -112,17 +112,17 @@ static QByteArray prompt() { return "sftp> "; }
SftpSession::SftpSession(const QStringList &connectionArgs) : d(new SftpSessionPrivate) SftpSession::SftpSession(const QStringList &connectionArgs) : d(new SftpSessionPrivate)
{ {
d->connectionArgs = connectionArgs; d->connectionArgs = connectionArgs;
connect(&d->sftpProc, &QProcess::started, [this] { connect(&d->sftpProc, &QtcProcess::started, [this] {
qCDebug(sshLog) << "sftp process started"; qCDebug(sshLog) << "sftp process started";
d->sftpProc.write("\n"); // Force initial prompt. d->sftpProc.write("\n"); // Force initial prompt.
}); });
connect(&d->sftpProc, &QProcess::errorOccurred, [this](QProcess::ProcessError error) { connect(&d->sftpProc, &QtcProcess::errorOccurred, [this](QProcess::ProcessError error) {
if (error == QProcess::FailedToStart) { if (error == QProcess::FailedToStart) {
d->state = State::Inactive; d->state = State::Inactive;
emit done(tr("sftp failed to start: %1").arg(d->sftpProc.errorString())); emit done(tr("sftp failed to start: %1").arg(d->sftpProc.errorString()));
} }
}); });
connect(&d->sftpProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this] { connect(&d->sftpProc, &QtcProcess::finished, [this] {
qCDebug(sshLog) << "sftp process finished"; qCDebug(sshLog) << "sftp process finished";
d->state = State::Inactive; d->state = State::Inactive;
@@ -136,7 +136,7 @@ SftpSession::SftpSession(const QStringList &connectionArgs) : d(new SftpSessionP
} }
emit done(QString()); emit done(QString());
}); });
connect(&d->sftpProc, &QProcess::readyReadStandardOutput, this, &SftpSession::handleStdout); connect(&d->sftpProc, &QtcProcess::readyReadStandardOutput, this, &SftpSession::handleStdout);
} }
void SftpSession::doStart() void SftpSession::doStart()
@@ -153,7 +153,8 @@ void SftpSession::doStart()
d->activeCommand = Command(); d->activeCommand = Command();
const QStringList args = QStringList{"-q"} << d->connectionArgs; const QStringList args = QStringList{"-q"} << d->connectionArgs;
qCDebug(sshLog) << "starting sftp session:" << sftpBinary.toUserOutput() << args; qCDebug(sshLog) << "starting sftp session:" << sftpBinary.toUserOutput() << args;
d->sftpProc.start(sftpBinary.toString(), args); d->sftpProc.setCommand(CommandLine(sftpBinary, args));
d->sftpProc.start();
} }
void SftpSession::handleStdout() void SftpSession::handleStdout()

View File

@@ -113,11 +113,11 @@ SftpTransfer::SftpTransfer(const FilesToTransfer &files, Internal::FileTransferT
d->transferType = type; d->transferType = type;
d->errorHandlingMode = errorHandlingMode; d->errorHandlingMode = errorHandlingMode;
d->connectionArgs = connectionArgs; d->connectionArgs = connectionArgs;
connect(&d->sftpProc, &QProcess::errorOccurred, [this](QProcess::ProcessError error) { connect(&d->sftpProc, &QtcProcess::errorOccurred, [this](QProcess::ProcessError error) {
if (error == QProcess::FailedToStart) if (error == QProcess::FailedToStart)
emitError(tr("sftp failed to start: %1").arg(d->sftpProc.errorString())); emitError(tr("sftp failed to start: %1").arg(d->sftpProc.errorString()));
}); });
connect(&d->sftpProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this] { connect(&d->sftpProc, &QtcProcess::finished, [this] {
if (d->sftpProc.exitStatus() != QProcess::NormalExit) { if (d->sftpProc.exitStatus() != QProcess::NormalExit) {
emitError(tr("sftp crashed.")); emitError(tr("sftp crashed."));
return; return;
@@ -128,7 +128,7 @@ SftpTransfer::SftpTransfer(const FilesToTransfer &files, Internal::FileTransferT
} }
emit done(QString()); emit done(QString());
}); });
connect(&d->sftpProc, &QProcess::readyReadStandardOutput, [this] { connect(&d->sftpProc, &QtcProcess::readyReadStandardOutput, [this] {
emit progress(QString::fromLocal8Bit(d->sftpProc.readAllStandardOutput())); emit progress(QString::fromLocal8Bit(d->sftpProc.readAllStandardOutput()));
}); });
} }
@@ -179,7 +179,8 @@ void SftpTransfer::doStart()
+ ProcessArgs::quoteArgUnix(f.targetFile).toLocal8Bit() + '\n'); + ProcessArgs::quoteArgUnix(f.targetFile).toLocal8Bit() + '\n');
} }
d->sftpProc.setStandardInputFile(batchFile.fileName()); d->sftpProc.setStandardInputFile(batchFile.fileName());
d->sftpProc.start(sftpBinary.toString(), d->connectionArgs); d->sftpProc.setCommand(CommandLine(sftpBinary, d->connectionArgs));
d->sftpProc.start();
emit started(); emit started();
} }

View File

@@ -167,7 +167,7 @@ SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject
qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo"); qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo");
qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>"); qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>");
d->connParams = serverInfo; d->connParams = serverInfo;
connect(&d->masterProcess, &QProcess::started, [this] { connect(&d->masterProcess, &QtcProcess::started, [this] {
QFileInfo socketInfo(d->socketFilePath()); QFileInfo socketInfo(d->socketFilePath());
if (socketInfo.exists()) { if (socketInfo.exists()) {
emitConnected(); emitConnected();
@@ -194,7 +194,7 @@ SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject
socketWatcherTimer->start(); socketWatcherTimer->start();
} }
}); });
connect(&d->masterProcess, &QProcess::errorOccurred, [this] (QProcess::ProcessError error) { connect(&d->masterProcess, &QtcProcess::errorOccurred, [this] (QProcess::ProcessError error) {
switch (error) { switch (error) {
case QProcess::FailedToStart: case QProcess::FailedToStart:
emitError(tr("Cannot establish SSH connection: Control process failed to start: %1") emitError(tr("Cannot establish SSH connection: Control process failed to start: %1")
@@ -208,7 +208,7 @@ SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject
break; // Cannot happen. break; // Cannot happen.
} }
}); });
connect(&d->masterProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this] { connect(&d->masterProcess, &QtcProcess::finished, [this] {
if (d->state == Disconnecting) { if (d->state == Disconnecting) {
emitDisconnected(); emitDisconnected();
return; return;
@@ -220,9 +220,9 @@ SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject
emitError(errorMsg); emitError(errorMsg);
}); });
if (!d->connParams.x11DisplayName.isEmpty()) { if (!d->connParams.x11DisplayName.isEmpty()) {
QProcessEnvironment env = d->masterProcess.processEnvironment(); Environment env = d->masterProcess.environment();
env.insert("DISPLAY", d->connParams.x11DisplayName); env.set("DISPLAY", d->connParams.x11DisplayName);
d->masterProcess.setProcessEnvironment(env); d->masterProcess.setEnvironment(env);
} }
} }
@@ -316,16 +316,17 @@ SshConnection::~SshConnection()
delete d; delete d;
} }
SshRemoteProcessPtr SshConnection::createRemoteProcess(const QString &command) SshRemoteProcessPtr SshConnection::createRemoteProcess(const QString &command, ProcessMode processMode)
{ {
QTC_ASSERT(state() == Connected, return SshRemoteProcessPtr()); QTC_ASSERT(state() == Connected, return SshRemoteProcessPtr());
return SshRemoteProcessPtr(new SshRemoteProcess(command, return SshRemoteProcessPtr(new SshRemoteProcess(command,
d->connectionArgs(SshSettings::sshFilePath()))); d->connectionArgs(SshSettings::sshFilePath()),
processMode));
} }
SshRemoteProcessPtr SshConnection::createRemoteShell() SshRemoteProcessPtr SshConnection::createRemoteShell(ProcessMode processMode)
{ {
return createRemoteProcess({}); return createRemoteProcess({}, processMode);
} }
SftpTransferPtr SshConnection::createUpload(const FilesToTransfer &files, SftpTransferPtr SshConnection::createUpload(const FilesToTransfer &files,
@@ -372,7 +373,8 @@ void SshConnection::doConnectToHost()
if (!d->connParams.x11DisplayName.isEmpty()) if (!d->connParams.x11DisplayName.isEmpty())
args.prepend("-X"); args.prepend("-X");
qCDebug(sshLog) << "establishing connection:" << sshBinary.toUserOutput() << args; qCDebug(sshLog) << "establishing connection:" << sshBinary.toUserOutput() << args;
d->masterProcess.start(sshBinary.toString(), args); d->masterProcess.setCommand(CommandLine(sshBinary, args));
d->masterProcess.start();
} }
void SshConnection::emitError(const QString &reason) void SshConnection::emitError(const QString &reason)

View File

@@ -28,6 +28,8 @@
#include "sftpdefs.h" #include "sftpdefs.h"
#include "ssh_global.h" #include "ssh_global.h"
#include <utils/processutils.h>
#include <QByteArray> #include <QByteArray>
#include <QFlags> #include <QFlags>
#include <QMetaType> #include <QMetaType>
@@ -113,8 +115,10 @@ public:
bool sharingEnabled() const; bool sharingEnabled() const;
~SshConnection(); ~SshConnection();
SshRemoteProcessPtr createRemoteProcess(const QString &command); SshRemoteProcessPtr createRemoteProcess(const QString &command, Utils::ProcessMode processMode
SshRemoteProcessPtr createRemoteShell(); = Utils::ProcessMode::Reader);
SshRemoteProcessPtr createRemoteShell(Utils::ProcessMode processMode
= Utils::ProcessMode::Reader);
SftpTransferPtr createUpload(const FilesToTransfer &files, SftpTransferPtr createUpload(const FilesToTransfer &files,
FileTransferErrorHandling errorHandlingMode); FileTransferErrorHandling errorHandlingMode);
SftpTransferPtr createDownload(const FilesToTransfer &files, SftpTransferPtr createDownload(const FilesToTransfer &files,

View File

@@ -36,7 +36,8 @@
namespace QSsh { namespace QSsh {
SshProcess::SshProcess() SshProcess::SshProcess(Utils::ProcessMode processMode)
: Utils::QtcProcess(processMode)
{ {
Utils::Environment env = Utils::Environment::systemEnvironment(); Utils::Environment env = Utils::Environment::systemEnvironment();
if (SshSettings::askpassFilePath().exists()) { if (SshSettings::askpassFilePath().exists()) {
@@ -46,37 +47,10 @@ SshProcess::SshProcess()
if (!env.hasKey("DISPLAY")) if (!env.hasKey("DISPLAY"))
env.set("DISPLAY", ":0"); env.set("DISPLAY", ":0");
} }
setProcessEnvironment(env.toProcessEnvironment()); setEnvironment(env);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_UNIX)
setChildProcessModifier([this] { setupChildProcess_impl(); });
#endif
}
SshProcess::~SshProcess() // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
{ setDisableUnixTerminal();
if (state() == QProcess::NotRunning)
return;
disconnect();
terminate();
waitForFinished(1000);
if (state() == QProcess::NotRunning)
return;
kill();
waitForFinished(1000);
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void SshProcess::setupChildProcess()
{
setupChildProcess_impl();
}
#endif
void SshProcess::setupChildProcess_impl()
{
#ifdef Q_OS_UNIX
setsid(); // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
#endif
} }
} // namespace QSsh } // namespace QSsh

View File

@@ -27,22 +27,14 @@
#include "ssh_global.h" #include "ssh_global.h"
#include <QProcess> #include <utils/qtcprocess.h>
namespace QSsh { namespace QSsh {
class QSSH_EXPORT SshProcess : public QProcess class QSSH_EXPORT SshProcess : public Utils::QtcProcess
{ {
public: public:
SshProcess(); SshProcess(Utils::ProcessMode processMode = Utils::ProcessMode::Reader);
~SshProcess() override;
private:
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void setupChildProcess() override;
#endif
void setupChildProcess_impl();
}; };
} // namespace QSsh } // namespace QSsh

View File

@@ -60,13 +60,15 @@ struct SshRemoteProcess::SshRemoteProcessPrivate
bool useTerminal = false; bool useTerminal = false;
}; };
SshRemoteProcess::SshRemoteProcess(const QString &command, const QStringList &connectionArgs) SshRemoteProcess::SshRemoteProcess(const QString &command, const QStringList &connectionArgs,
: d(new SshRemoteProcessPrivate) Utils::ProcessMode processMode)
: SshProcess(processMode)
, d(new SshRemoteProcessPrivate)
{ {
d->remoteCommand = command; d->remoteCommand = command;
d->connectionArgs = connectionArgs; d->connectionArgs = connectionArgs;
connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this] { connect(this, &QtcProcess::finished, this, [this] {
QString error; QString error;
if (exitStatus() == QProcess::CrashExit) if (exitStatus() == QProcess::CrashExit)
error = tr("The ssh process crashed: %1").arg(errorString()); error = tr("The ssh process crashed: %1").arg(errorString());
@@ -74,7 +76,7 @@ SshRemoteProcess::SshRemoteProcess(const QString &command, const QStringList &co
error = tr("Remote process crashed."); error = tr("Remote process crashed.");
emit done(error); emit done(error);
}); });
connect(this, &QProcess::errorOccurred, [this](QProcess::ProcessError error) { connect(this, &QtcProcess::errorOccurred, [this](QProcess::ProcessError error) {
if (error == QProcess::FailedToStart) if (error == QProcess::FailedToStart)
emit done(errorString()); emit done(errorString());
}); });
@@ -85,12 +87,13 @@ void SshRemoteProcess::doStart()
QTC_ASSERT(!isRunning(), return); QTC_ASSERT(!isRunning(), return);
const Utils::CommandLine cmd = fullLocalCommandLine(); const Utils::CommandLine cmd = fullLocalCommandLine();
if (!d->displayName.isEmpty()) { if (!d->displayName.isEmpty()) {
QProcessEnvironment env = processEnvironment(); Utils::Environment env = environment();
env.insert("DISPLAY", d->displayName); env.set("DISPLAY", d->displayName);
setProcessEnvironment(env); setEnvironment(env);
} }
qCDebug(sshLog) << "starting remote process:" << cmd.toUserOutput(); qCDebug(sshLog) << "starting remote process:" << cmd.toUserOutput();
QProcess::start(cmd.executable().toString(), cmd.splitArguments()); setCommand(cmd);
QtcProcess::start();
} }
SshRemoteProcess::~SshRemoteProcess() SshRemoteProcess::~SshRemoteProcess()
@@ -110,7 +113,7 @@ void SshRemoteProcess::requestX11Forwarding(const QString &displayName)
void SshRemoteProcess::start() void SshRemoteProcess::start()
{ {
QTimer::singleShot(0, this, &SshRemoteProcess::doStart); doStart();
} }
bool SshRemoteProcess::isRunning() const bool SshRemoteProcess::isRunning() const

View File

@@ -54,7 +54,8 @@ signals:
void done(const QString &error); void done(const QString &error);
private: private:
SshRemoteProcess(const QString &command, const QStringList &connectionArgs); SshRemoteProcess(const QString &command, const QStringList &connectionArgs,
Utils::ProcessMode processMode = Utils::ProcessMode::Reader);
void doStart(); void doStart();
struct SshRemoteProcessPrivate; struct SshRemoteProcessPrivate;

View File

@@ -186,7 +186,7 @@ void SshRemoteProcessRunner::setState(int newState)
if (d->m_process) { if (d->m_process) {
disconnect(d->m_process.get(), nullptr, this, nullptr); disconnect(d->m_process.get(), nullptr, this, nullptr);
d->m_process->terminate(); d->m_process->terminate();
d->m_process.release()->deleteLater(); d->m_process.reset();
} }
if (d->m_connection) { if (d->m_connection) {
disconnect(d->m_connection, nullptr, this, nullptr); disconnect(d->m_connection, nullptr, this, nullptr);
@@ -206,7 +206,7 @@ bool SshRemoteProcessRunner::isProcessRunning() const
return d->m_process && d->m_process->isRunning(); return d->m_process && d->m_process->isRunning();
} }
SshRemoteProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const QProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const
{ {
QTC_CHECK(!isProcessRunning()); QTC_CHECK(!isProcessRunning());
return d->m_exitStatus; return d->m_exitStatus;
@@ -214,7 +214,7 @@ SshRemoteProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const
int SshRemoteProcessRunner::processExitCode() const int SshRemoteProcessRunner::processExitCode() const
{ {
QTC_CHECK(processExitStatus() == SshRemoteProcess::NormalExit); QTC_CHECK(processExitStatus() == QProcess::NormalExit);
return d->m_exitCode; return d->m_exitCode;
} }

View File

@@ -48,7 +48,7 @@ public:
bool isProcessRunning() const; bool isProcessRunning() const;
void writeDataToProcess(const QByteArray &data); void writeDataToProcess(const QByteArray &data);
void cancel(); void cancel();
SshRemoteProcess::ExitStatus processExitStatus() const; QProcess::ExitStatus processExitStatus() const;
int processExitCode() const; int processExitCode() const;
QString processErrorString() const; QString processErrorString() const;
QByteArray readAllStandardOutput(); QByteArray readAllStandardOutput();

View File

@@ -149,7 +149,7 @@ QProcess::ProcessState SshDeviceProcess::state() const
QProcess::ExitStatus SshDeviceProcess::exitStatus() const QProcess::ExitStatus SshDeviceProcess::exitStatus() const
{ {
return d->exitStatus == QSsh::SshRemoteProcess::NormalExit && d->exitCode != 255 return d->exitStatus == QProcess::NormalExit && d->exitCode != 255
? QProcess::NormalExit : QProcess::CrashExit; ? QProcess::NormalExit : QProcess::CrashExit;
} }
@@ -237,7 +237,7 @@ void SshDeviceProcess::handleDisconnected()
emit error(QProcess::FailedToStart); emit error(QProcess::FailedToStart);
break; break;
case SshDeviceProcessPrivate::ProcessRunning: case SshDeviceProcessPrivate::ProcessRunning:
d->exitStatus = QSsh::SshRemoteProcess::CrashExit; d->exitStatus = QProcess::CrashExit;
emit finished(); emit finished();
default: default:
break; break;
@@ -284,7 +284,7 @@ void SshDeviceProcess::handleKillOperationFinished(const QString &errorMessage)
if (errorMessage.isEmpty()) // Process will finish as expected; nothing to do here. if (errorMessage.isEmpty()) // Process will finish as expected; nothing to do here.
return; return;
d->exitStatus = QSsh::SshRemoteProcess::CrashExit; // Not entirely true, but it will get the message across. d->exitStatus = QProcess::CrashExit; // Not entirely true, but it will get the message across.
d->errorMessage = tr("Failed to kill remote process: %1").arg(errorMessage); d->errorMessage = tr("Failed to kill remote process: %1").arg(errorMessage);
d->setState(SshDeviceProcessPrivate::Inactive); d->setState(SshDeviceProcessPrivate::Inactive);
emit finished(); emit finished();
@@ -292,7 +292,7 @@ void SshDeviceProcess::handleKillOperationFinished(const QString &errorMessage)
void SshDeviceProcess::handleKillOperationTimeout() void SshDeviceProcess::handleKillOperationTimeout()
{ {
d->exitStatus = QSsh::SshRemoteProcess::CrashExit; // Not entirely true, but it will get the message across. d->exitStatus = QProcess::CrashExit; // Not entirely true, but it will get the message across.
d->errorMessage = tr("Timeout waiting for remote process to finish."); d->errorMessage = tr("Timeout waiting for remote process to finish.");
d->setState(SshDeviceProcessPrivate::Inactive); d->setState(SshDeviceProcessPrivate::Inactive);
emit finished(); emit finished();

View File

@@ -220,19 +220,19 @@ void GenericLinuxDeviceTester::handleSftpFinished(const QString &error)
void GenericLinuxDeviceTester::testRsync() void GenericLinuxDeviceTester::testRsync()
{ {
emit progressMessage(tr("Checking whether rsync works...")); emit progressMessage(tr("Checking whether rsync works..."));
connect(&d->rsyncProcess, &QProcess::errorOccurred, [this] { connect(&d->rsyncProcess, &Utils::QtcProcess::errorOccurred, [this] {
if (d->rsyncProcess.error() == QProcess::FailedToStart) if (d->rsyncProcess.error() == QProcess::FailedToStart)
handleRsyncFinished(); handleRsyncFinished();
}); });
connect(&d->rsyncProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(&d->rsyncProcess, &Utils::QtcProcess::finished, this, [this] {
this, [this] {
handleRsyncFinished(); handleRsyncFinished();
}); });
const RsyncCommandLine cmdLine = RsyncDeployStep::rsyncCommand(*d->connection, const RsyncCommandLine cmdLine = RsyncDeployStep::rsyncCommand(*d->connection,
RsyncDeployStep::defaultFlags()); RsyncDeployStep::defaultFlags());
const QStringList args = QStringList(cmdLine.options) const QStringList args = QStringList(cmdLine.options)
<< "-n" << "--exclude=*" << (cmdLine.remoteHostSpec + ":/tmp"); << "-n" << "--exclude=*" << (cmdLine.remoteHostSpec + ":/tmp");
d->rsyncProcess.start("rsync", args); d->rsyncProcess.setCommand(Utils::CommandLine("rsync", args));
d->rsyncProcess.start();
} }
void GenericLinuxDeviceTester::handleRsyncFinished() void GenericLinuxDeviceTester::handleRsyncFinished()

View File

@@ -119,7 +119,7 @@ void RemoteLinuxSignalOperation::interruptProcess(const QString &filePath)
void RemoteLinuxSignalOperation::runnerProcessFinished() void RemoteLinuxSignalOperation::runnerProcessFinished()
{ {
m_errorMessage.clear(); m_errorMessage.clear();
if (m_runner->processExitStatus() != QSsh::SshRemoteProcess::NormalExit) { if (m_runner->processExitStatus() != QProcess::NormalExit) {
m_errorMessage = m_runner->processErrorString(); m_errorMessage = m_runner->processErrorString();
} else if (m_runner->processExitCode() != 0) { } else if (m_runner->processExitCode() != 0) {
m_errorMessage = tr("Exit code is %1. stderr:").arg(m_runner->processExitCode()) m_errorMessage = tr("Exit code is %1. stderr:").arg(m_runner->processExitCode())

View File

@@ -123,19 +123,19 @@ void RsyncDeployService::createRemoteDirectories()
void RsyncDeployService::deployFiles() void RsyncDeployService::deployFiles()
{ {
connect(&m_rsync, &QProcess::readyReadStandardOutput, this, [this] { connect(&m_rsync, &QtcProcess::readyReadStandardOutput, this, [this] {
emit progressMessage(QString::fromLocal8Bit(m_rsync.readAllStandardOutput())); emit progressMessage(QString::fromLocal8Bit(m_rsync.readAllStandardOutput()));
}); });
connect(&m_rsync, &QProcess::readyReadStandardError, this, [this] { connect(&m_rsync, &QtcProcess::readyReadStandardError, this, [this] {
emit warningMessage(QString::fromLocal8Bit(m_rsync.readAllStandardError())); emit warningMessage(QString::fromLocal8Bit(m_rsync.readAllStandardError()));
}); });
connect(&m_rsync, &QProcess::errorOccurred, this, [this] { connect(&m_rsync, &QtcProcess::errorOccurred, this, [this] {
if (m_rsync.error() == QProcess::FailedToStart) { if (m_rsync.error() == QProcess::FailedToStart) {
emit errorMessage(tr("rsync failed to start: %1").arg(m_rsync.errorString())); emit errorMessage(tr("rsync failed to start: %1").arg(m_rsync.errorString()));
setFinished(); setFinished();
} }
}); });
connect(&m_rsync, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this] { connect(&m_rsync, &QtcProcess::finished, this, [this] {
if (m_rsync.exitStatus() == QProcess::CrashExit) { if (m_rsync.exitStatus() == QProcess::CrashExit) {
emit errorMessage(tr("rsync crashed.")); emit errorMessage(tr("rsync crashed."));
setFinished(); setFinished();
@@ -173,7 +173,8 @@ void RsyncDeployService::deployNextFile()
const QStringList args = QStringList(cmdLine.options) const QStringList args = QStringList(cmdLine.options)
<< (localFilePath + (file.localFilePath().isDir() ? "/" : QString())) << (localFilePath + (file.localFilePath().isDir() ? "/" : QString()))
<< (cmdLine.remoteHostSpec + ':' + file.remoteFilePath()); << (cmdLine.remoteHostSpec + ':' + file.remoteFilePath());
m_rsync.start("rsync", args); // TODO: Get rsync location from settings? m_rsync.setCommand(CommandLine("rsync", args));
m_rsync.start(); // TODO: Get rsync location from settings?
} }
void RsyncDeployService::setFinished() void RsyncDeployService::setFinished()

View File

@@ -1,4 +1,8 @@
file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}")
add_qtc_test(tst_ssh add_qtc_test(tst_ssh
DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\""
DEPENDS Utils QtcSsh DEPENDS Utils QtcSsh
SOURCES tst_ssh.cpp SOURCES tst_ssh.cpp
) )

View File

@@ -2,4 +2,8 @@ QT = core network
QTC_LIB_DEPENDS += ssh utils QTC_LIB_DEPENDS += ssh utils
include(../qttest.pri) include(../qttest.pri)
TEST_RELATIVE_LIBEXEC_PATH = $$relative_path($$IDE_LIBEXEC_PATH, $$OUT_PWD)
win32:TEST_RELATIVE_LIBEXEC_PATH=../$$TEST_RELATIVE_LIBEXEC_PATH
DEFINES += 'TEST_RELATIVE_LIBEXEC_PATH="\\\"$$TEST_RELATIVE_LIBEXEC_PATH\\\""'
SOURCES += tst_ssh.cpp SOURCES += tst_ssh.cpp

View File

@@ -1,8 +1,16 @@
import qbs import qbs.FileInfo
QtcAutotest { QtcAutotest {
name: "SSH autotest" name: "SSH autotest"
Depends { name: "QtcSsh" } Depends { name: "QtcSsh" }
Depends { name: "Utils" } Depends { name: "Utils" }
files: "tst_ssh.cpp" files: "tst_ssh.cpp"
cpp.defines: {
var defines = base;
var absLibExecPath = FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix,
qtc.ide_libexec_path);
var relLibExecPath = FileInfo.relativePath(destinationDirectory, absLibExecPath);
defines.push('TEST_RELATIVE_LIBEXEC_PATH="' + relLibExecPath + '"');
return defines;
}
} }

View File

@@ -29,8 +29,12 @@
#include <ssh/sshconnectionmanager.h> #include <ssh/sshconnectionmanager.h>
#include <ssh/sshremoteprocessrunner.h> #include <ssh/sshremoteprocessrunner.h>
#include <ssh/sshsettings.h> #include <ssh/sshsettings.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/launcherinterface.h>
#include <utils/processreaper.h>
#include <utils/qtcprocess.h>
#include <utils/temporarydirectory.h> #include <utils/temporarydirectory.h>
#include <QDateTime> #include <QDateTime>
@@ -114,14 +118,20 @@ private slots:
void remoteProcessInput(); void remoteProcessInput();
void sftp(); void sftp();
void cleanupTestCase();
private: private:
bool waitForConnection(SshConnection &connection); bool waitForConnection(SshConnection &connection);
SshConnectionManager sshConnectionManager; Utils::ProcessReaper *processReaper = nullptr;
SshConnectionManager *sshConnectionManager = nullptr;
}; };
void tst_Ssh::initTestCase() void tst_Ssh::initTestCase()
{ {
processReaper = new Utils::ProcessReaper();
Utils::LauncherInterface::startLauncher(qApp->applicationDirPath() + '/'
+ QLatin1String(TEST_RELATIVE_LIBEXEC_PATH));
sshConnectionManager = new SshConnectionManager();
Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath()
+ "/qtc-ssh-autotest-XXXXXX"); + "/qtc-ssh-autotest-XXXXXX");
} }
@@ -269,7 +279,7 @@ void tst_Ssh::remoteProcess()
QVERIFY2(runner.lastConnectionErrorString().isEmpty(), QVERIFY2(runner.lastConnectionErrorString().isEmpty(),
qPrintable(runner.lastConnectionErrorString())); qPrintable(runner.lastConnectionErrorString()));
if (isBlocking) { if (isBlocking) {
QVERIFY(runner.processExitStatus() == SshRemoteProcess::CrashExit QVERIFY(runner.processExitStatus() == QProcess::CrashExit
|| runner.processExitCode() != 0); || runner.processExitCode() != 0);
} else { } else {
QCOMPARE(successExpected, runner.processExitCode() == 0); QCOMPARE(successExpected, runner.processExitCode() == 0);
@@ -291,11 +301,10 @@ void tst_Ssh::remoteProcessChannels()
QByteArray remoteData; QByteArray remoteData;
SshRemoteProcessPtr echoProcess SshRemoteProcessPtr echoProcess
= connection.createRemoteProcess("printf " + QString::fromUtf8(testString) + " >&2"); = connection.createRemoteProcess("printf " + QString::fromUtf8(testString) + " >&2");
echoProcess->setReadChannel(QProcess::StandardError);
QEventLoop loop; QEventLoop loop;
connect(echoProcess.get(), &SshRemoteProcess::done, &loop, &QEventLoop::quit); connect(echoProcess.get(), &SshRemoteProcess::done, &loop, &QEventLoop::quit);
connect(echoProcess.get(), &QIODevice::readyRead, connect(echoProcess.get(), &Utils::QtcProcess::readyReadStandardError,
[&remoteData, p = echoProcess.get()] { remoteData += p->readAll(); }); [&remoteData, p = echoProcess.get()] { remoteData += p->readAllStandardError(); });
connect(echoProcess.get(), &SshRemoteProcess::readyReadStandardOutput, connect(echoProcess.get(), &SshRemoteProcess::readyReadStandardOutput,
[&remoteStdout, p = echoProcess.get()] { remoteStdout += p->readAllStandardOutput(); }); [&remoteStdout, p = echoProcess.get()] { remoteStdout += p->readAllStandardOutput(); });
connect(echoProcess.get(), &SshRemoteProcess::readyReadStandardError, connect(echoProcess.get(), &SshRemoteProcess::readyReadStandardError,
@@ -324,7 +333,8 @@ void tst_Ssh::remoteProcessInput()
SshConnection connection(params); SshConnection connection(params);
QVERIFY(waitForConnection(connection)); QVERIFY(waitForConnection(connection));
SshRemoteProcessPtr catProcess = connection.createRemoteProcess("/bin/cat"); SshRemoteProcessPtr catProcess = connection.createRemoteProcess("/bin/cat",
Utils::ProcessMode::Writer);
QEventLoop loop; QEventLoop loop;
connect(catProcess.get(), &SshRemoteProcess::started, &loop, &QEventLoop::quit); connect(catProcess.get(), &SshRemoteProcess::started, &loop, &QEventLoop::quit);
connect(catProcess.get(), &SshRemoteProcess::done, &loop, &QEventLoop::quit); connect(catProcess.get(), &SshRemoteProcess::done, &loop, &QEventLoop::quit);
@@ -340,17 +350,16 @@ void tst_Ssh::remoteProcessInput()
QVERIFY(catProcess->isRunning()); QVERIFY(catProcess->isRunning());
static QString testString = "x\r\n"; static QString testString = "x\r\n";
connect(catProcess.get(), &QIODevice::readyRead, &loop, &QEventLoop::quit); connect(catProcess.get(), &Utils::QtcProcess::readyReadStandardOutput, &loop, &QEventLoop::quit);
QTextStream stream(catProcess.get());
stream << testString; catProcess->write(testString.toUtf8());
stream.flush();
timer.start(); timer.start();
loop.exec(); loop.exec();
QVERIFY(timer.isActive()); QVERIFY(timer.isActive());
timer.stop(); timer.stop();
QVERIFY(catProcess->isRunning()); QVERIFY(catProcess->isRunning());
const QString data = QString::fromUtf8(catProcess->readAll()); const QString data = QString::fromUtf8(catProcess->readAllStandardOutput());
QCOMPARE(data, testString); QCOMPARE(data, testString);
SshRemoteProcessRunner * const killer = new SshRemoteProcessRunner(this); SshRemoteProcessRunner * const killer = new SshRemoteProcessRunner(this);
killer->run("pkill -9 cat", params); killer->run("pkill -9 cat", params);
@@ -623,6 +632,13 @@ void tst_Ssh::sftp()
QVERIFY2(connection.errorString().isEmpty(), qPrintable(connection.errorString())); QVERIFY2(connection.errorString().isEmpty(), qPrintable(connection.errorString()));
} }
void tst_Ssh::cleanupTestCase()
{
delete sshConnectionManager;
Utils::LauncherInterface::stopLauncher();
delete processReaper;
}
bool tst_Ssh::waitForConnection(SshConnection &connection) bool tst_Ssh::waitForConnection(SshConnection &connection)
{ {
QEventLoop loop; QEventLoop loop;