aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorChristian Kandeler <[email protected]>2018-11-23 11:07:57 +0100
committerChristian Kandeler <[email protected]>2018-12-13 15:10:11 +0000
commitd7178b88c4b2572fb83b28f8178940766216deed (patch)
tree861eb8069fb97c8e8e79f56cb8f88f05126639fc /src/plugins
parent030d4d01084b04af361f07dd6360dfad8e2cc19c (diff)
SSH: Use OpenSSH tools
... instead of our own SSH library. Advantages: - Full compatibility with OpenSSH behavior guaranteed. - Minimal maintenance effort. - Less code to build. - Big chunk of 3rd party sources can be removed from our repository. One the downside, Windows users now need to install OpenSSH for RemoteLinux support. Hoewever, people doing embedded development probably have it installed anyway. [ChangeLog] Switched SSH backend to OpenSSH Fixes: QTCREATORBUG-15744 Fixes: QTCREATORBUG-15807 Fixes: QTCREATORBUG-19306 Fixes: QTCREATORBUG-20210 Change-Id: Ifcfefdd39401e45ba1f4aca35d2c5bf7046c7aab Reviewed-by: Eike Ziller <[email protected]> Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.cpp20
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.h3
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.cpp24
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp110
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h5
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp36
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h2
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp188
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshsettingspage.h53
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp25
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro2
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs1
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h1
-rw-r--r--src/plugins/qnx/qnxdevicetester.cpp4
-rw-r--r--src/plugins/qnx/qnxdevicetester.h2
-rw-r--r--src/plugins/qnx/qnxdevicewizard.cpp4
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp2
-rw-r--r--src/plugins/remotelinux/genericdirectuploadservice.cpp498
-rw-r--r--src/plugins/remotelinux/genericdirectuploadservice.h24
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp44
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h2
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui45
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp3
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp20
-rw-r--r--src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardsetuppage.ui50
-rw-r--r--src/plugins/remotelinux/linuxdevicetester.cpp54
-rw-r--r--src/plugins/remotelinux/linuxdevicetester.h5
-rw-r--r--src/plugins/remotelinux/packageuploader.cpp72
-rw-r--r--src/plugins/remotelinux/packageuploader.h12
-rw-r--r--src/plugins/remotelinux/remotelinuxcheckforfreediskspaceservice.cpp13
-rw-r--r--src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp8
-rw-r--r--src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.h2
-rw-r--r--src/plugins/remotelinux/remotelinuxpackageinstaller.cpp4
-rw-r--r--src/plugins/remotelinux/remotelinuxpackageinstaller.h2
-rw-r--r--src/plugins/remotelinux/sshkeydeployer.cpp15
-rw-r--r--src/plugins/remotelinux/sshkeydeployer.h2
-rw-r--r--src/plugins/valgrind/callgrind/callgrindcontroller.cpp14
-rw-r--r--src/plugins/valgrind/callgrind/callgrindcontroller.h5
-rw-r--r--src/plugins/valgrind/memchecktool.cpp2
39 files changed, 623 insertions, 755 deletions
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
index 939d4d3884b..e5bcc779a92 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
@@ -31,7 +31,6 @@
#include <coreplugin/messagemanager.h>
#include <projectexplorer/projectexplorerconstants.h>
-#include <ssh/sshhostkeydatabase.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/persistentsettings.h>
@@ -72,7 +71,6 @@ public:
static DeviceManager *clonedInstance;
QList<IDevice::Ptr> devices;
QHash<Core::Id, Core::Id> defaultDevices;
- QSsh::SshHostKeyDatabasePtr hostKeyDatabase;
Utils::PersistentSettingsWriter *writer = nullptr;
};
@@ -134,7 +132,6 @@ void DeviceManager::save()
QVariantMap data;
data.insert(QLatin1String(DeviceManagerKey), toMap());
d->writer->save(data, Core::ICore::mainWindow());
- d->hostKeyDatabase->store(hostKeysFilePath());
}
void DeviceManager::load()
@@ -315,11 +312,6 @@ bool DeviceManager::isLoaded() const
return d->writer;
}
-QSsh::SshHostKeyDatabasePtr DeviceManager::hostKeyDatabase() const
-{
- return d->hostKeyDatabase;
-}
-
void DeviceManager::setDefaultDevice(Core::Id id)
{
QTC_ASSERT(this != instance(), return);
@@ -356,13 +348,6 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
if (isInstance) {
QTC_ASSERT(!m_instance, return);
m_instance = this;
- d->hostKeyDatabase = QSsh::SshHostKeyDatabasePtr::create();
- const QString keyFilePath = hostKeysFilePath();
- if (QFileInfo::exists(keyFilePath)) {
- QString error;
- if (!d->hostKeyDatabase->load(keyFilePath, &error))
- Core::MessageManager::write(error);
- }
connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, this, &DeviceManager::save);
}
}
@@ -406,11 +391,6 @@ IDevice::ConstPtr DeviceManager::defaultDevice(Core::Id deviceType) const
return id.isValid() ? find(id) : IDevice::ConstPtr();
}
-QString DeviceManager::hostKeysFilePath()
-{
- return settingsFilePath(QLatin1String("/ssh-hostkeys")).toString();
-}
-
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.h b/src/plugins/projectexplorer/devicesupport/devicemanager.h
index 2b086f06836..bd9c2b606ed 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.h
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.h
@@ -33,7 +33,6 @@
#include <memory>
-namespace QSsh { class SshHostKeyDatabase; }
namespace Utils { class FileName; }
namespace ProjectExplorer {
@@ -97,8 +96,6 @@ private:
static void replaceInstance();
static void removeClonedInstance();
- static QString hostKeysFilePath();
- QSharedPointer<QSsh::SshHostKeyDatabase> hostKeyDatabase() const;
static Utils::FileName settingsFilePath(const QString &extension);
static Utils::FileName systemSettingsFilePath(const QString &deviceFileRelativePath);
static void copy(const DeviceManager *source, DeviceManager *target, bool deep);
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp
index 2ff4090ffd5..0487954312d 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp
@@ -120,16 +120,14 @@ const char PortsSpecKey[] = "FreePortsSpec";
const char UserNameKey[] = "Uname";
const char AuthKey[] = "Authentication";
const char KeyFileKey[] = "KeyFile";
-const char PasswordKey[] = "Password";
const char TimeoutKey[] = "Timeout";
const char HostKeyCheckingKey[] = "HostKeyChecking";
-const char SshOptionsKey[] = "SshOptions";
const char DebugServerKey[] = "DebugServerKey";
const char QmlsceneKey[] = "QmlsceneKey";
using AuthType = QSsh::SshConnectionParameters::AuthenticationType;
-const AuthType DefaultAuthType = QSsh::SshConnectionParameters::AuthenticationTypePublicKey;
+const AuthType DefaultAuthType = QSsh::SshConnectionParameters::AuthenticationTypeAll;
const IDevice::MachineType DefaultMachineType = IDevice::Hardware;
const int DefaultTimeout = 10;
@@ -161,7 +159,6 @@ DeviceTester::DeviceTester(QObject *parent) : QObject(parent) { }
IDevice::IDevice() : d(new Internal::IDevicePrivate)
{
- d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
}
IDevice::IDevice(Core::Id type, Origin origin, MachineType machineType, Core::Id id)
@@ -172,7 +169,6 @@ IDevice::IDevice(Core::Id type, Origin origin, MachineType machineType, Core::Id
d->machineType = machineType;
QTC_CHECK(origin == ManuallyAdded || id.isValid());
d->id = id.isValid() ? id : newId();
- d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
}
IDevice::IDevice(const IDevice &other)
@@ -328,16 +324,19 @@ void IDevice::fromMap(const QVariantMap &map)
d->sshParameters.setHost(map.value(QLatin1String(HostKey)).toString());
d->sshParameters.setPort(map.value(QLatin1String(SshPortKey), 22).toInt());
d->sshParameters.setUserName(map.value(QLatin1String(UserNameKey)).toString());
- d->sshParameters.authenticationType
- = static_cast<AuthType>(map.value(QLatin1String(AuthKey), DefaultAuthType).toInt());
- d->sshParameters.setPassword(map.value(QLatin1String(PasswordKey)).toString());
+
+ // Pre-4.9, the authentication enum used to have more values
+ const int storedAuthType = map.value(QLatin1String(AuthKey), DefaultAuthType).toInt();
+ const bool outdatedAuthType = storedAuthType
+ > QSsh::SshConnectionParameters::AuthenticationTypeSpecificKey;
+ d->sshParameters.authenticationType = outdatedAuthType
+ ? QSsh::SshConnectionParameters::AuthenticationTypeAll
+ : static_cast<AuthType>(storedAuthType);
+
d->sshParameters.privateKeyFile = map.value(QLatin1String(KeyFileKey), defaultPrivateKeyFilePath()).toString();
d->sshParameters.timeout = map.value(QLatin1String(TimeoutKey), DefaultTimeout).toInt();
d->sshParameters.hostKeyCheckingMode = static_cast<QSsh::SshHostKeyCheckingMode>
(map.value(QLatin1String(HostKeyCheckingKey), QSsh::SshHostKeyCheckingNone).toInt());
- const QVariant optionsVariant = map.value(QLatin1String(SshOptionsKey));
- if (optionsVariant.isValid()) // false for QtC < 3.4
- d->sshParameters.options = QSsh::SshConnectionOptions(optionsVariant.toInt());
QString portsSpec = map.value(PortsSpecKey).toString();
if (portsSpec.isEmpty())
@@ -369,11 +368,9 @@ QVariantMap IDevice::toMap() const
map.insert(QLatin1String(SshPortKey), d->sshParameters.port());
map.insert(QLatin1String(UserNameKey), d->sshParameters.userName());
map.insert(QLatin1String(AuthKey), d->sshParameters.authenticationType);
- map.insert(QLatin1String(PasswordKey), d->sshParameters.password());
map.insert(QLatin1String(KeyFileKey), d->sshParameters.privateKeyFile);
map.insert(QLatin1String(TimeoutKey), d->sshParameters.timeout);
map.insert(QLatin1String(HostKeyCheckingKey), d->sshParameters.hostKeyCheckingMode);
- map.insert(QLatin1String(SshOptionsKey), static_cast<int>(d->sshParameters.options));
map.insert(QLatin1String(PortsSpecKey), d->freePorts.toString());
map.insert(QLatin1String(VersionKey), d->version);
@@ -404,7 +401,6 @@ QSsh::SshConnectionParameters IDevice::sshParameters() const
void IDevice::setSshParameters(const QSsh::SshConnectionParameters &sshParameters)
{
d->sshParameters = sshParameters;
- d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
}
QUrl IDevice::toolControlChannel(const ControlChannelHint &) const
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
index 9feb7e71663..e3cc959a5d1 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
@@ -39,18 +39,19 @@
namespace ProjectExplorer {
+enum class Signal { Interrupt, Terminate, Kill };
+
class SshDeviceProcess::SshDeviceProcessPrivate
{
public:
SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {}
SshDeviceProcess * const q;
- bool serverSupportsSignals = false;
QSsh::SshConnection *connection = nullptr;
- QSsh::SshRemoteProcess::Ptr process;
+ QSsh::SshRemoteProcessPtr process;
Runnable runnable;
QString errorMessage;
- QSsh::SshRemoteProcess::ExitStatus exitStatus;
+ QProcess::ExitStatus exitStatus = QProcess::NormalExit;
DeviceProcessSignalOperation::Ptr killOperation;
QTimer killTimer;
QByteArray stdOut;
@@ -59,7 +60,7 @@ public:
enum State { Inactive, Connecting, Connected, ProcessRunning } state = Inactive;
void setState(State newState);
- void doSignal(QSsh::SshRemoteProcess::Signal signal);
+ void doSignal(Signal signal);
QString displayName() const
{
@@ -85,15 +86,12 @@ void SshDeviceProcess::start(const Runnable &runnable)
d->errorMessage.clear();
d->exitCode = -1;
+ d->exitStatus = QProcess::NormalExit;
d->runnable = runnable;
- d->connection = QSsh::acquireConnection(device()->sshParameters());
- const QString displayName = d->displayName();
- const QString connDisplayName = d->connection->x11DisplayName();
- if (!displayName.isEmpty() && !connDisplayName.isEmpty() && connDisplayName != displayName) {
- QSsh::releaseConnection(d->connection);
- d->connection = new QSsh::SshConnection(device()->sshParameters(), this);
- }
- connect(d->connection, &QSsh::SshConnection::error,
+ QSsh::SshConnectionParameters params = device()->sshParameters();
+ params.x11DisplayName = d->displayName();
+ d->connection = QSsh::acquireConnection(params);
+ connect(d->connection, &QSsh::SshConnection::errorOccurred,
this, &SshDeviceProcess::handleConnectionError);
connect(d->connection, &QSsh::SshConnection::disconnected,
this, &SshDeviceProcess::handleDisconnected);
@@ -110,17 +108,17 @@ void SshDeviceProcess::start(const Runnable &runnable)
void SshDeviceProcess::interrupt()
{
QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
- d->doSignal(QSsh::SshRemoteProcess::IntSignal);
+ d->doSignal(Signal::Interrupt);
}
void SshDeviceProcess::terminate()
{
- d->doSignal(QSsh::SshRemoteProcess::TermSignal);
+ d->doSignal(Signal::Terminate);
}
void SshDeviceProcess::kill()
{
- d->doSignal(QSsh::SshRemoteProcess::KillSignal);
+ d->doSignal(Signal::Kill);
}
QProcess::ProcessState SshDeviceProcess::state() const
@@ -169,11 +167,6 @@ QByteArray SshDeviceProcess::readAllStandardError()
return data;
}
-void SshDeviceProcess::setSshServerSupportsSignals(bool signalsSupported)
-{
- d->serverSupportsSignals = signalsSupported;
-}
-
qint64 SshDeviceProcess::processId() const
{
return 0;
@@ -185,15 +178,11 @@ void SshDeviceProcess::handleConnected()
d->setState(SshDeviceProcessPrivate::Connected);
d->process = d->connection->createRemoteProcess(fullCommandLine(d->runnable).toUtf8());
- connect(d->process.data(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted);
- connect(d->process.data(), &QSsh::SshRemoteProcess::closed, this, &SshDeviceProcess::handleProcessFinished);
- connect(d->process.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &SshDeviceProcess::handleStdout);
- connect(d->process.data(), &QSsh::SshRemoteProcess::readyReadStandardError, this, &SshDeviceProcess::handleStderr);
-
- d->process->clearEnvironment();
- const Utils::Environment env = d->runnable.environment;
- for (Utils::Environment::const_iterator it = env.constBegin(); it != env.constEnd(); ++it)
- d->process->addToEnvironment(env.key(it).toUtf8(), env.value(it).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();
if (!display.isEmpty())
d->process->requestX11Forwarding(display);
@@ -234,24 +223,10 @@ void SshDeviceProcess::handleProcessStarted()
emit started();
}
-void SshDeviceProcess::handleProcessFinished(int exitStatus)
+void SshDeviceProcess::handleProcessFinished()
{
- d->exitStatus = static_cast<QSsh::SshRemoteProcess::ExitStatus>(exitStatus);
- switch (d->exitStatus) {
- case QSsh::SshRemoteProcess::FailedToStart:
- QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connected, return);
- break;
- case QSsh::SshRemoteProcess::CrashExit:
- QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
- break;
- case QSsh::SshRemoteProcess::NormalExit:
- QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
- d->exitCode = d->process->exitCode();
- break;
- default:
- QTC_ASSERT(false, return);
- }
d->errorMessage = d->process->errorString();
+ d->exitCode = d->process->exitCode();
d->setState(SshDeviceProcessPrivate::Inactive);
emit finished();
}
@@ -302,7 +277,7 @@ QString SshDeviceProcess::fullCommandLine(const Runnable &runnable) const
return cmdLine;
}
-void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess::Signal signal)
+void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(Signal signal)
{
switch (state) {
case SshDeviceProcessPrivate::Inactive:
@@ -315,28 +290,24 @@ void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess:
break;
case SshDeviceProcessPrivate::Connected:
case SshDeviceProcessPrivate::ProcessRunning:
- if (serverSupportsSignals) {
- process->sendSignal(signal);
+ DeviceProcessSignalOperation::Ptr signalOperation = q->device()->signalOperation();
+ quint64 processId = q->processId();
+ if (signal == Signal::Interrupt) {
+ if (processId != 0)
+ signalOperation->interruptProcess(processId);
+ else
+ signalOperation->interruptProcess(runnable.executable);
} else {
- DeviceProcessSignalOperation::Ptr signalOperation = q->device()->signalOperation();
- quint64 processId = q->processId();
- if (signal == QSsh::SshRemoteProcess::IntSignal) {
- if (processId != 0)
- signalOperation->interruptProcess(processId);
- else
- signalOperation->interruptProcess(runnable.executable);
- } else {
- if (killOperation) // We are already in the process of killing the app.
- return;
- killOperation = signalOperation;
- connect(signalOperation.data(), &DeviceProcessSignalOperation::finished, q,
- &SshDeviceProcess::handleKillOperationFinished);
- killTimer.start(5000);
- if (processId != 0)
- signalOperation->killProcess(processId);
- else
- signalOperation->killProcess(runnable.executable);
- }
+ if (killOperation) // We are already in the process of killing the app.
+ return;
+ killOperation = signalOperation;
+ connect(signalOperation.data(), &DeviceProcessSignalOperation::finished, q,
+ &SshDeviceProcess::handleKillOperationFinished);
+ killTimer.start(5000);
+ if (processId != 0)
+ signalOperation->killProcess(processId);
+ else
+ signalOperation->killProcess(runnable.executable);
}
break;
}
@@ -360,10 +331,7 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe
process->disconnect(q);
if (connection) {
connection->disconnect(q);
- if (connection->parent() == q)
- connection->deleteLater();
- else
- QSsh::releaseConnection(connection);
+ QSsh::releaseConnection(connection);
connection = nullptr;
}
}
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h
index 19acc317698..7bbe942354e 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h
@@ -55,15 +55,12 @@ public:
qint64 write(const QByteArray &data) override;
- // Default is "false" due to OpenSSH not implementing this feature for some reason.
- void setSshServerSupportsSignals(bool signalsSupported);
-
private:
void handleConnected();
void handleConnectionError();
void handleDisconnected();
void handleProcessStarted();
- void handleProcessFinished(int exitStatus);
+ void handleProcessFinished();
void handleStdout();
void handleStderr();
void handleKillOperationFinished(const QString &errorMessage);
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
index 589b3d17218..c1c7b0a45f7 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp
@@ -72,31 +72,21 @@ void SshDeviceProcessList::handleConnectionError()
reportError(tr("Connection failure: %1").arg(d->process.lastConnectionErrorString()));
}
-void SshDeviceProcessList::handleListProcessFinished(int exitStatus)
+void SshDeviceProcessList::handleListProcessFinished(const QString &error)
{
setFinished();
- switch (exitStatus) {
- case SshRemoteProcess::FailedToStart:
- handleProcessError(tr("Error: Process listing command failed to start: %1")
- .arg(d->process.processErrorString()));
- break;
- case SshRemoteProcess::CrashExit:
- handleProcessError(tr("Error: Process listing command crashed: %1")
- .arg(d->process.processErrorString()));
- break;
- case SshRemoteProcess::NormalExit:
- if (d->process.processExitCode() == 0) {
- const QByteArray remoteStdout = d->process.readAllStandardOutput();
- const QString stdoutString
- = QString::fromUtf8(remoteStdout.data(), remoteStdout.count());
- reportProcessListUpdated(buildProcessList(stdoutString));
- } else {
- handleProcessError(tr("Process listing command failed with exit code %1.")
- .arg(d->process.processExitCode()));
- }
- break;
- default:
- Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status");
+ if (!error.isEmpty()) {
+ handleProcessError(error);
+ return;
+ }
+ if (d->process.processExitCode() == 0) {
+ const QByteArray remoteStdout = d->process.readAllStandardOutput();
+ const QString stdoutString
+ = QString::fromUtf8(remoteStdout.data(), remoteStdout.count());
+ reportProcessListUpdated(buildProcessList(stdoutString));
+ } else {
+ handleProcessError(tr("Process listing command failed with exit code %1.")
+ .arg(d->process.processExitCode()));
}
}
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h
index 8ecefce9b93..60937e65cc0 100644
--- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h
@@ -40,7 +40,7 @@ public:
private:
void handleConnectionError();
- void handleListProcessFinished(int exitStatus);
+ void handleListProcessFinished(const QString &error);
void handleKillProcessFinished(const QString &errorString);
virtual QString listProcessesCommandLine() const = 0;
diff --git a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
new file mode 100644
index 00000000000..c87d27d9784
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** 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
+** 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.
+**
+** 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.
+**
+****************************************************************************/
+
+#include "sshsettingspage.h"
+
+#include <coreplugin/icore.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <ssh/sshsettings.h>
+#include <utils/pathchooser.h>
+
+#include <QCheckBox>
+#include <QCoreApplication>
+#include <QFormLayout>
+#include <QLabel>
+#include <QSpinBox>
+#include <QString>
+
+using namespace QSsh;
+using namespace Utils;
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class SshSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SshSettingsWidget();
+ void saveSettings();
+
+private:
+ void setupConnectionSharingCheckBox();
+ void setupConnectionSharingSpinBox();
+ void setupSshPathChooser();
+ void setupSftpPathChooser();
+ void setupAskpassPathChooser();
+ void setupKeygenPathChooser();
+ void setupPathChooser(PathChooser &chooser, const FileName &initialPath, bool &changedFlag);
+ void updateSpinboxEnabled();
+
+ QCheckBox m_connectionSharingCheckBox;
+ QSpinBox m_connectionSharingSpinBox;
+ PathChooser m_sshChooser;
+ PathChooser m_sftpChooser;
+ PathChooser m_askpassChooser;
+ PathChooser m_keygenChooser;
+ bool m_sshPathChanged = false;
+ bool m_sftpPathChanged = false;
+ bool m_askpassPathChanged = false;
+ bool m_keygenPathChanged = false;
+};
+
+SshSettingsPage::SshSettingsPage(QObject *parent) : Core::IOptionsPage(parent)
+{
+ setId(Constants::SSH_SETTINGS_PAGE_ID);
+ setDisplayName(tr("SSH"));
+ setCategory(Constants::DEVICE_SETTINGS_CATEGORY);
+ setDisplayCategory(QCoreApplication::translate("ProjectExplorer", "SSH"));
+ setCategoryIcon(Utils::Icon({{":/projectexplorer/images/settingscategory_devices.png",
+ Utils::Theme::PanelTextColorDark}}, Utils::Icon::Tint));
+}
+
+QWidget *SshSettingsPage::widget()
+{
+ if (!m_widget)
+ m_widget = new SshSettingsWidget;
+ return m_widget;
+}
+
+void SshSettingsPage::apply()
+{
+ m_widget->saveSettings();
+}
+
+void SshSettingsPage::finish()
+{
+ delete m_widget;
+}
+
+
+SshSettingsWidget::SshSettingsWidget()
+{
+ setupConnectionSharingCheckBox();
+ setupConnectionSharingSpinBox();
+ setupSshPathChooser();
+ setupSftpPathChooser();
+ setupAskpassPathChooser();
+ setupKeygenPathChooser();
+ auto * const layout = new QFormLayout(this);
+ layout->addRow(tr("Enable connection sharing:"), &m_connectionSharingCheckBox);
+ layout->addRow(tr("Connection sharing timeout:"), &m_connectionSharingSpinBox);
+ layout->addRow(tr("Path to ssh executable:"), &m_sshChooser);
+ layout->addRow(tr("Path to sftp executable:"), &m_sftpChooser);
+ layout->addRow(tr("Path to ssh-askpass executable:"), &m_askpassChooser);
+ layout->addRow(tr("Path to ssh-keygen executable:"), &m_keygenChooser);
+ updateSpinboxEnabled();
+}
+
+void SshSettingsWidget::saveSettings()
+{
+ SshSettings::setConnectionSharingEnabled(m_connectionSharingCheckBox.isChecked());
+ SshSettings::setConnectionSharingTimeout(m_connectionSharingSpinBox.value());
+ if (m_sshPathChanged)
+ SshSettings::setSshFilePath(m_sshChooser.fileName());
+ if (m_sftpPathChanged)
+ SshSettings::setSftpFilePath(m_sftpChooser.fileName());
+ if (m_askpassPathChanged)
+ SshSettings::setAskpassFilePath(m_askpassChooser.fileName());
+ if (m_keygenPathChanged)
+ SshSettings::setKeygenFilePath(m_keygenChooser.fileName());
+ SshSettings::storeSettings(Core::ICore::settings());
+}
+
+void SshSettingsWidget::setupConnectionSharingCheckBox()
+{
+ m_connectionSharingCheckBox.setChecked(SshSettings::connectionSharingEnabled());
+ connect(&m_connectionSharingCheckBox, &QCheckBox::toggled,
+ this, &SshSettingsWidget::updateSpinboxEnabled);
+}
+
+void SshSettingsWidget::setupConnectionSharingSpinBox()
+{
+ m_connectionSharingSpinBox.setMinimum(1);
+ m_connectionSharingSpinBox.setValue(SshSettings::connectionSharingTimeout());
+ m_connectionSharingSpinBox.setSuffix(tr(" minutes"));
+}
+
+void SshSettingsWidget::setupSshPathChooser()
+{
+ setupPathChooser(m_sshChooser, SshSettings::sshFilePath(), m_sshPathChanged);
+}
+
+void SshSettingsWidget::setupSftpPathChooser()
+{
+ setupPathChooser(m_sftpChooser, SshSettings::sftpFilePath(), m_sftpPathChanged);
+}
+
+void SshSettingsWidget::setupAskpassPathChooser()
+{
+ setupPathChooser(m_askpassChooser, SshSettings::askpassFilePath(), m_askpassPathChanged);
+}
+
+void SshSettingsWidget::setupKeygenPathChooser()
+{
+ setupPathChooser(m_keygenChooser, SshSettings::keygenFilePath(), m_keygenPathChanged);
+}
+
+void SshSettingsWidget::setupPathChooser(PathChooser &chooser, const FileName &initialPath,
+ bool &changedFlag)
+{
+ chooser.setExpectedKind(PathChooser::ExistingCommand);
+ chooser.setFileName(initialPath);
+ connect(&chooser, &PathChooser::pathChanged, [&changedFlag] { changedFlag = true; });
+}
+
+void SshSettingsWidget::updateSpinboxEnabled()
+{
+ m_connectionSharingSpinBox.setEnabled(m_connectionSharingCheckBox.isChecked());
+ static_cast<QFormLayout *>(layout())->labelForField(&m_connectionSharingSpinBox)
+ ->setEnabled(m_connectionSharingCheckBox.isChecked());
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#include <sshsettingspage.moc>
diff --git a/src/plugins/projectexplorer/devicesupport/sshsettingspage.h b/src/plugins/projectexplorer/devicesupport/sshsettingspage.h
new file mode 100644
index 00000000000..e43ef93826a
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/sshsettingspage.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** 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
+** 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.
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QPointer>
+
+namespace ProjectExplorer {
+namespace Internal {
+
+class SshSettingsWidget;
+
+class SshSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ SshSettingsPage(QObject *parent = 0);
+
+private:
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
+
+ QPointer<SshSettingsWidget> m_widget;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 5048c2d0ca1..068b4f720b8 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -84,6 +84,7 @@
#include "devicesupport/desktopdevicefactory.h"
#include "devicesupport/devicemanager.h"
#include "devicesupport/devicesettingspage.h"
+#include "devicesupport/sshsettingspage.h"
#include "targetsettingspanel.h"
#include "projectpanelfactory.h"
#include "waitforstopdialog.h"
@@ -119,6 +120,7 @@
#include <texteditor/textdocument.h>
#include <texteditor/texteditorconstants.h>
#include <ssh/sshconnection.h>
+#include <ssh/sshsettings.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
@@ -536,6 +538,7 @@ public:
// Settings pages
ProjectExplorerSettingsPage m_projectExplorerSettingsPage;
DeviceSettingsPage m_deviceSettingsPage;
+ SshSettingsPage m_sshSettingsPage;
ProjectTreeWidgetFactory m_projectTreeFactory;
FolderNavigationWidgetFactory m_folderNavigationWidgetFactory;
@@ -1715,6 +1718,28 @@ void ProjectExplorerPlugin::extensionsInitialized()
BuildManager::extensionsInitialized();
DeviceManager::instance()->addDevice(IDevice::Ptr(new DesktopDevice));
+
+ QSsh::SshSettings::loadSettings(Core::ICore::settings());
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ const auto searchPathRetriever = [] {
+ const QString gitBinary = Core::ICore::settings()->value("Git/BinaryPath", "git")
+ .toString();
+ const QStringList rawGitSearchPaths = Core::ICore::settings()->value("Git/Path")
+ .toString().split(':', QString::SkipEmptyParts);
+ const Utils::FileNameList gitSearchPaths = Utils::transform(rawGitSearchPaths,
+ [](const QString &rawPath) { return Utils::FileName::fromString(rawPath); });
+ const Utils::FileName fullGitPath = Utils::Environment::systemEnvironment()
+ .searchInPath(gitBinary, gitSearchPaths);
+ if (fullGitPath.isEmpty())
+ return Utils::FileNameList();
+ return Utils::FileNameList{
+ fullGitPath.parentDir(),
+ fullGitPath.parentDir().parentDir() + "/usr/bin"
+ };
+ };
+ QSsh::SshSettings::setExtraSearchPathRetriever(searchPathRetriever);
+ }
+
// delay restoring kits until UI is shown for improved perceived startup performance
QTimer::singleShot(0, this, &ProjectExplorerPlugin::restoreKits);
}
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index 21f70f48e26..8ef32ae9bad 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -130,6 +130,7 @@ HEADERS += projectexplorer.h \
devicesupport/localprocesslist.h \
devicesupport/sshdeviceprocess.h \
devicesupport/sshdeviceprocesslist.h \
+ devicesupport/sshsettingspage.h \
devicesupport/desktopdeviceconfigurationwidget.h \
devicesupport/desktopprocesssignaloperation.h \
deploymentdata.h \
@@ -271,6 +272,7 @@ SOURCES += projectexplorer.cpp \
devicesupport/localprocesslist.cpp \
devicesupport/sshdeviceprocess.cpp \
devicesupport/sshdeviceprocesslist.cpp \
+ devicesupport/sshsettingspage.cpp \
devicesupport/desktopdeviceconfigurationwidget.cpp \
devicesupport/desktopprocesssignaloperation.cpp \
deployablefile.cpp \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index d25b52c7d42..5836c06c458 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -220,6 +220,7 @@ Project {
"localprocesslist.cpp", "localprocesslist.h",
"sshdeviceprocess.cpp", "sshdeviceprocess.h",
"sshdeviceprocesslist.cpp", "sshdeviceprocesslist.h",
+ "sshsettingspage.cpp", "sshsettingspage.h",
"desktopprocesssignaloperation.cpp", "desktopprocesssignaloperation.h",
"desktopdeviceconfigurationwidget.cpp", "desktopdeviceconfigurationwidget.h", "desktopdeviceconfigurationwidget.ui"
]
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
index 61f1429fbe9..de81a428336 100644
--- a/src/plugins/projectexplorer/projectexplorerconstants.h
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -107,6 +107,7 @@ const char KITS_SETTINGS_CATEGORY[] = "A.Kits";
// Kits pages
const char KITS_SETTINGS_PAGE_ID[] = "D.ProjectExplorer.KitsOptions";
const char DEVICE_SETTINGS_PAGE_ID[] = "E.ProjectExplorer.DeviceOptions";
+const char SSH_SETTINGS_PAGE_ID[] = "F.ProjectExplorer.SshOptions";
const char TOOLCHAIN_SETTINGS_PAGE_ID[] = "M.ProjectExplorer.ToolChainOptions";
const char DEBUGGER_SETTINGS_PAGE_ID[] = "N.ProjectExplorer.DebuggerOptions";
diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp
index 3c8c37e98a9..004de59acbe 100644
--- a/src/plugins/qnx/qnxdevicetester.cpp
+++ b/src/plugins/qnx/qnxdevicetester.cpp
@@ -113,12 +113,12 @@ void QnxDeviceTester::handleGenericTestFinished(TestResult result)
testNextCommand();
}
-void QnxDeviceTester::handleProcessFinished(int exitStatus)
+void QnxDeviceTester::handleProcessFinished(const QString &error)
{
QTC_ASSERT(m_state == CommandsTest, return);
const QString command = m_commandsToTest[m_currentCommandIndex];
- if (exitStatus == QSsh::SshRemoteProcess::NormalExit) {
+ if (error.isEmpty()) {
if (m_processRunner->processExitCode() == 0) {
emit progressMessage(tr("%1 found.").arg(command) + QLatin1Char('\n'));
} else {
diff --git a/src/plugins/qnx/qnxdevicetester.h b/src/plugins/qnx/qnxdevicetester.h
index 67acf1c776e..91d5548bda4 100644
--- a/src/plugins/qnx/qnxdevicetester.h
+++ b/src/plugins/qnx/qnxdevicetester.h
@@ -46,7 +46,7 @@ public:
private slots:
void handleGenericTestFinished(ProjectExplorer::DeviceTester::TestResult result);
- void handleProcessFinished(int exitStatus);
+ void handleProcessFinished(const QString &error);
void handleConnectionError();
private:
diff --git a/src/plugins/qnx/qnxdevicewizard.cpp b/src/plugins/qnx/qnxdevicewizard.cpp
index 58b71f95863..2ca8968388b 100644
--- a/src/plugins/qnx/qnxdevicewizard.cpp
+++ b/src/plugins/qnx/qnxdevicewizard.cpp
@@ -63,12 +63,10 @@ QnxDeviceWizard::QnxDeviceWizard(QWidget *parent) :
IDevice::Ptr QnxDeviceWizard::device()
{
QSsh::SshConnectionParameters sshParams;
- sshParams.options = QSsh::SshIgnoreDefaultProxy;
sshParams.url = m_setupPage->url();
sshParams.timeout = 10;
sshParams.authenticationType = m_setupPage->authenticationType();
- if (sshParams.authenticationType != QSsh::SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- && sshParams.authenticationType != QSsh::SshConnectionParameters::AuthenticationTypePassword)
+ if (sshParams.authenticationType == QSsh::SshConnectionParameters::AuthenticationTypeSpecificKey)
sshParams.privateKeyFile = m_setupPage->privateKeyFilePath();
QnxDevice::Ptr device = QnxDevice::create(m_setupPage->configurationName(),
diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
index c63e16ce5ab..12e47ca0d20 100644
--- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
+++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
@@ -196,7 +196,7 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success)
d->state = Connecting;
d->connection = QSsh::acquireConnection(deviceConfiguration()->sshParameters());
- connect(d->connection, &SshConnection::error,
+ connect(d->connection, &SshConnection::errorOccurred,
this, &AbstractRemoteLinuxDeployService::handleConnectionFailure);
if (d->connection->state() == SshConnection::Connected) {
handleConnected();
diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp
index 3112d519c8a..100cf040201 100644
--- a/src/plugins/remotelinux/genericdirectuploadservice.cpp
+++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp
@@ -26,9 +26,10 @@
#include "genericdirectuploadservice.h"
#include <projectexplorer/deployablefile.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <ssh/sftpchannel.h>
+#include <ssh/sftptransfer.h>
#include <ssh/sshconnection.h>
#include <ssh/sshremoteprocess.h>
@@ -44,46 +45,27 @@ using namespace QSsh;
namespace RemoteLinux {
namespace Internal {
-namespace {
-enum State { Inactive, InitializingSftp, Uploading };
-} // anonymous namespace
-
-enum class JobType {
- PreQuery,
- Upload,
- Mkdir,
- Ln,
- Chmod,
- PostQuery,
- None
-};
-struct Job
-{
- DeployableFile file;
- JobType type;
- QDateTime result;
- explicit Job(const DeployableFile &file = DeployableFile(), JobType type = JobType::None,
- const QDateTime &result = QDateTime())
- : file(file), type(type), result(result) {}
-};
+enum State { Inactive, PreChecking, Uploading, PostProcessing };
class GenericDirectUploadServicePrivate
{
public:
+ DeployableFile getFileForProcess(SshRemoteProcess *proc)
+ {
+ const auto it = remoteProcs.find(proc);
+ QTC_ASSERT(it != remoteProcs.end(), return DeployableFile());
+ const DeployableFile file = *it;
+ remoteProcs.erase(it);
+ return file;
+ }
+
bool incremental = false;
bool ignoreMissingFiles = false;
- bool uploadJobRunning = false;
+ QHash<SshRemoteProcess *, DeployableFile> remoteProcs;
State state = Inactive;
-
QList<DeployableFile> filesToUpload;
-
- QHash<SftpJobId, Job> runningJobs;
-
- SshRemoteProcess::Ptr runningProc;
- DeployableFile runningProcFile;
-
- SftpChannel::Ptr uploader;
+ SftpTransferPtr uploader;
QList<DeployableFile> deployableFiles;
};
@@ -145,253 +127,62 @@ void GenericDirectUploadService::stopDeviceSetup()
void GenericDirectUploadService::doDeploy()
{
QTC_ASSERT(d->state == Inactive, setFinished(); return);
-
- d->uploader = connection()->createSftpChannel();
- connect(d->uploader.data(), &SftpChannel::initialized,
- this, &GenericDirectUploadService::handleSftpInitialized);
- connect(d->uploader.data(), &SftpChannel::channelError,
- this, &GenericDirectUploadService::handleSftpChannelError);
- d->uploader->initialize();
- d->state = InitializingSftp;
-}
-
-void GenericDirectUploadService::handleSftpInitialized()
-{
- QTC_ASSERT(d->state == InitializingSftp, setFinished(); return);
- QTC_ASSERT(!d->deployableFiles.isEmpty(), setFinished(); return);
- connect(d->uploader.data(), &SftpChannel::finished,
- this, &GenericDirectUploadService::handleJobFinished);
- connect(d->uploader.data(), &SftpChannel::fileInfoAvailable,
- this, &GenericDirectUploadService::handleFileInfoAvailable);
- d->state = Uploading;
+ d->state = PreChecking;
queryFiles();
}
-void GenericDirectUploadService::handleSftpChannelError(const QString &message)
+QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &file,
+ SshRemoteProcess *statProc)
{
- QTC_ASSERT(d->state == InitializingSftp, setFinished(); return);
-
- emit errorMessage(tr("SFTP initialization failed: %1").arg(message));
- setFinished();
- handleDeploymentDone();
-}
-
-void GenericDirectUploadService::handleFileInfoAvailable(SftpJobId jobId,
- const QList<SftpFileInfo> &fileInfos)
-{
- QTC_ASSERT(d->state == Uploading, return);
- QTC_ASSERT(fileInfos.length() == 1, return);
- auto it = d->runningJobs.find(jobId);
- QTC_ASSERT(it != d->runningJobs.end(), return);
- it->result = QDateTime::fromSecsSinceEpoch(fileInfos.at(0).mtime);
-}
-
-void GenericDirectUploadService::handleJobFinished(SftpJobId jobId, const QString &errorMsg)
-{
- auto it = d->runningJobs.find(jobId);
- QTC_ASSERT(it != d->runningJobs.end(), return);
-
- Job job = *it;
- d->runningJobs.erase(it);
-
- switch (job.type) {
- case JobType::PreQuery:
- if (hasRemoteFileChanged(job.file, job.result)) {
- d->filesToUpload.append(job.file);
- if (!d->uploadJobRunning)
- uploadNextFile();
- } else {
- tryFinish();
- }
- break;
- case JobType::Upload:
- QTC_CHECK(d->uploadJobRunning);
-
- if (!errorMsg.isEmpty()) {
- QString errorString = tr("Upload of file \"%1\" failed. The server said: \"%2\".")
- .arg(job.file.localFilePath().toUserOutput(), errorMsg);
- if (errorMsg == QLatin1String("Failure")
- && job.file.remoteDirectory().contains(QLatin1String("/bin"))) {
- errorString += QLatin1Char(' ')
- + tr("If \"%1\" is currently running on the remote host, "
- "you might need to stop it first.").arg(job.file.remoteFilePath());
- }
- emit errorMessage(errorString);
- setFinished();
- handleDeploymentDone();
- return;
- }
-
- // This is done for Windows.
- if (job.file.isExecutable()) {
- const QString command = QLatin1String("chmod a+x ")
- + Utils::QtcProcess::quoteArgUnix(job.file.remoteFilePath());
- d->runningProc = connection()->createRemoteProcess(command.toUtf8());
- d->runningProcFile = job.file;
- connect(d->runningProc.data(), &SshRemoteProcess::closed,
- this, &GenericDirectUploadService::handleUploadProcFinished);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardOutput,
- this, &GenericDirectUploadService::handleStdOutData);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
- this, &GenericDirectUploadService::handleStdErrData);
- connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
- this, &GenericDirectUploadService::handleReadChannelFinished);
- d->runningProc->start();
- } else {
- d->uploadJobRunning = false;
- const SftpJobId jobId = d->uploader->statFile(job.file.remoteFilePath());
- if (jobId == SftpInvalidJob) {
- emit errorMessage(tr("SFTP stat query for %1 failed.")
- .arg(job.file.remoteFilePath()));
- saveDeploymentTimeStamp(job.file, QDateTime());
- } else {
- d->runningJobs.insert(jobId, Job(job.file, JobType::PostQuery));
- }
- uploadNextFile();
- }
- break;
- case JobType::PostQuery:
- if (!errorMsg.isEmpty()) {
- emit warningMessage(tr("Could not determine remote timestamp of %1: %2")
- .arg(job.file.remoteFilePath()).arg(errorMsg));
- }
- saveDeploymentTimeStamp(job.file, job.result);
- tryFinish();
- break;
- default:
- QTC_CHECK(false);
- break;
+ QString errorDetails;
+ if (statProc->exitStatus() != QProcess::NormalExit)
+ errorDetails = statProc->errorString();
+ else if (statProc->exitCode() != 0)
+ errorDetails = QString::fromUtf8(statProc->readAllStandardError());
+ if (!errorDetails.isEmpty()) {
+ emit warningMessage(tr("Failed to retrieve remote timestamp for file \"%1\". "
+ "Incremental deployment will not work. Error message was: %2")
+ .arg(file.remoteFilePath(), errorDetails));
+ return QDateTime();
}
-}
-
-void GenericDirectUploadService::clearRunningProc()
-{
- d->runningProc.clear();
- d->runningProcFile = DeployableFile();
- d->uploadJobRunning = false;
-}
-
-void GenericDirectUploadService::handleUploadProcFinished(int exitStatus)
-{
- QTC_ASSERT(d->state == Uploading, setFinished(); return);
- QTC_ASSERT(d->uploadJobRunning, return);
-
- if (exitStatus != SshRemoteProcess::NormalExit || d->runningProc->exitCode() != 0)
- handleProcFailure();
- else
- runPostQueryOnProcResult();
-}
-
-void GenericDirectUploadService::handleProcFailure()
-{
- emit errorMessage(tr("Failed to upload file \"%1\".")
- .arg(d->runningProcFile.localFilePath().toUserOutput()));
- clearRunningProc();
- setFinished();
- handleDeploymentDone();
-}
-
-void GenericDirectUploadService::runPostQueryOnProcResult()
-{
- const SftpJobId jobId = d->uploader->statFile(d->runningProcFile.remoteFilePath());
- if (jobId == SftpInvalidJob) {
- emit errorMessage(tr("SFTP stat query for %1 failed.")
- .arg(d->runningProcFile.remoteFilePath()));
- saveDeploymentTimeStamp(d->runningProcFile, QDateTime());
- } else {
- d->runningJobs.insert(jobId, Job(d->runningProcFile, JobType::PostQuery));
+ QByteArray output = statProc->readAllStandardOutput().trimmed();
+ const QString warningString(tr("Unexpected stat output for remote file \"%1\": %2")
+ .arg(file.remoteFilePath()).arg(QString::fromUtf8(output)));
+ if (!output.startsWith(file.remoteFilePath().toUtf8())) {
+ emit warningMessage(warningString);
+ return QDateTime();
}
- clearRunningProc();
- uploadNextFile();
-}
-
-void GenericDirectUploadService::tryFinish()
-{
- if (d->filesToUpload.isEmpty() && d->runningJobs.isEmpty() && d->runningProc.isNull()) {
- emit progressMessage(tr("All files successfully deployed."));
- setFinished();
- handleDeploymentDone();
+ const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' ');
+ if (columns.size() < 15) { // Normal Linux stat: 16 columns, busybox stat: 15 columns
+ emit warningMessage(warningString);
+ return QDateTime();
}
-}
-
-void GenericDirectUploadService::handleMkdirFinished(int exitStatus)
-{
- QTC_ASSERT(d->state == Uploading, setFinished(); return);
-
- QFileInfo fi = d->runningProcFile.localFilePath().toFileInfo();
- if (exitStatus != SshRemoteProcess::NormalExit || d->runningProc->exitCode() != 0) {
- handleProcFailure();
- } else if (fi.isDir()) {
- runPostQueryOnProcResult();
- } else {
- const QString remoteFilePath = d->runningProcFile.remoteFilePath();
- if (fi.isSymLink()) {
- const QString target = fi.dir().relativeFilePath(fi.symLinkTarget()); // see QTBUG-5817.
- const QStringList args = QStringList() << QLatin1String("ln") << QLatin1String("-sf")
- << target << remoteFilePath;
- const QString command = Utils::QtcProcess::joinArgs(args, Utils::OsTypeLinux);
-
- // See comment in SftpChannel::createLink as to why we can't use it.
- d->runningProc = connection()->createRemoteProcess(command.toUtf8());
- connect(d->runningProc.data(), &SshRemoteProcess::closed,
- this, &GenericDirectUploadService::handleUploadProcFinished);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardOutput,
- this, &GenericDirectUploadService::handleStdOutData);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
- this, &GenericDirectUploadService::handleStdErrData);
- connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
- this, &GenericDirectUploadService::handleReadChannelFinished);
- d->runningProc->start();
- } else {
- const SftpJobId job = d->uploader->uploadFile(
- d->runningProcFile.localFilePath().toString(), remoteFilePath,
- SftpOverwriteExisting);
- if (job == SftpInvalidJob) {
- const QString message = tr("Failed to upload file \"%1\": "
- "Could not open for reading.")
- .arg(d->runningProcFile.localFilePath().toUserOutput());
- clearRunningProc();
- if (d->ignoreMissingFiles) {
- emit warningMessage(message);
- uploadNextFile();
- } else {
- emit errorMessage(message);
- setFinished();
- handleDeploymentDone();
- }
- } else {
- d->runningJobs[job] = Job(d->runningProcFile, JobType::Upload);
- clearRunningProc();
- d->uploadJobRunning = true;
- }
- }
+ bool isNumber;
+ const qint64 secsSinceEpoch = columns.at(12).toLongLong(&isNumber);
+ if (!isNumber) {
+ emit warningMessage(warningString);
+ return QDateTime();
}
+ return QDateTime::fromSecsSinceEpoch(secsSinceEpoch);
}
-void GenericDirectUploadService::handleStdOutData()
-{
- auto const process = qobject_cast<SshRemoteProcess *>(sender());
- if (process)
- emit stdOutData(QString::fromUtf8(process->readAllStandardOutput()));
-}
-
-void GenericDirectUploadService::handleStdErrData()
-{
- auto const process = qobject_cast<SshRemoteProcess *>(sender());
- if (process)
- emit stdErrData(QString::fromUtf8(process->readAllStandardError()));
-}
-
-void GenericDirectUploadService::handleReadChannelFinished()
+void GenericDirectUploadService::checkForStateChangeOnRemoteProcFinished()
{
- auto const process = qobject_cast<SshRemoteProcess *>(sender());
- if (process && process->atEnd())
- process->close();
+ if (!d->remoteProcs.isEmpty())
+ return;
+ if (d->state == PreChecking) {
+ uploadFiles();
+ return;
+ }
+ QTC_ASSERT(d->state == PostProcessing, return);
+ emit progressMessage(tr("All files successfully deployed."));
+ setFinished();
+ handleDeploymentDone();
}
void GenericDirectUploadService::stopDeployment()
{
- QTC_ASSERT(d->state == InitializingSftp || d->state == Uploading, setFinished(); return);
+ QTC_ASSERT(d->state != Inactive, return);
setFinished();
handleDeploymentDone();
@@ -419,80 +210,143 @@ QList<DeployableFile> GenericDirectUploadService::collectFilesToUpload(
void GenericDirectUploadService::setFinished()
{
d->state = Inactive;
- if (d->runningProc)
- disconnect(d->runningProc.data(), nullptr, this, nullptr);
+ for (auto it = d->remoteProcs.begin(); it != d->remoteProcs.end(); ++it) {
+ it.key()->disconnect();
+ it.key()->terminate();
+ }
+ d->remoteProcs.clear();
if (d->uploader) {
- disconnect(d->uploader.data(), nullptr, this, nullptr);
- d->uploader->closeChannel();
+ d->uploader->disconnect();
+ d->uploader->stop();
+ d->uploader.release()->deleteLater();
}
- clearRunningProc();
- d->uploadJobRunning = false;
- d->runningJobs.clear();
d->filesToUpload.clear();
}
-void GenericDirectUploadService::uploadNextFile()
+void GenericDirectUploadService::queryFiles()
{
- QTC_ASSERT(!d->uploadJobRunning, return);
+ QTC_ASSERT(d->state == PreChecking || d->state == PostProcessing, return);
+ QTC_ASSERT(d->state == PostProcessing || d->remoteProcs.isEmpty(), return);
- if (d->filesToUpload.isEmpty()) {
- tryFinish();
- return;
+ const QList<DeployableFile> &filesToCheck = d->state == PreChecking
+ ? d->deployableFiles : d->filesToUpload;
+ for (const DeployableFile &file : filesToCheck) {
+ if (d->state == PreChecking && (!d->incremental || hasLocalFileChanged(file))) {
+ d->filesToUpload.append(file);
+ continue;
+ }
+ // We'd like to use --format=%Y, but it's not supported by busybox.
+ const QByteArray statCmd = "stat -t "
+ + Utils::QtcProcess::quoteArgUnix(file.remoteFilePath()).toUtf8();
+ SshRemoteProcess * const statProc = connection()->createRemoteProcess(statCmd).release();
+ statProc->setParent(this);
+ connect(statProc, &SshRemoteProcess::done, this,
+ [this, statProc, state = d->state] {
+ QTC_ASSERT(d->state == state, return);
+ const DeployableFile file = d->getFileForProcess(statProc);
+ QTC_ASSERT(file.isValid(), return);
+ const QDateTime timestamp = timestampFromStat(file, statProc);
+ statProc->deleteLater();
+ switch (state) {
+ case PreChecking:
+ if (!timestamp.isValid() || hasRemoteFileChanged(file, timestamp))
+ d->filesToUpload.append(file);
+ break;
+ case PostProcessing:
+ if (timestamp.isValid())
+ saveDeploymentTimeStamp(file, timestamp);
+ break;
+ case Inactive:
+ case Uploading:
+ QTC_CHECK(false);
+ break;
+ }
+ checkForStateChangeOnRemoteProcFinished();
+ });
+ d->remoteProcs.insert(statProc, file);
+ statProc->start();
}
+ checkForStateChangeOnRemoteProcFinished();
+}
- const DeployableFile df = d->filesToUpload.takeFirst();
-
- QString dirToCreate = df.remoteDirectory();
- if (dirToCreate.isEmpty()) {
- emit warningMessage(tr("Warning: No remote path set for local file \"%1\". "
- "Skipping upload.").arg(df.localFilePath().toUserOutput()));
- uploadNextFile();
+void GenericDirectUploadService::uploadFiles()
+{
+ QTC_ASSERT(d->state == PreChecking, return);
+ d->state = Uploading;
+ if (d->filesToUpload.empty()) {
+ emit progressMessage(tr("No files need to be uploaded."));
+ setFinished();
+ handleDeploymentDone();
return;
}
-
- QFileInfo fi = df.localFilePath().toFileInfo();
- if (fi.isDir())
- dirToCreate += QLatin1Char('/') + fi.fileName();
- const QString command = QLatin1String("mkdir -p ")
- + Utils::QtcProcess::quoteArgUnix(dirToCreate);
- QTC_CHECK(d->runningProc.isNull());
- d->runningProc = connection()->createRemoteProcess(command.toUtf8());
- connect(d->runningProc.data(), &SshRemoteProcess::closed,
- this, &GenericDirectUploadService::handleMkdirFinished);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardOutput,
- this, &GenericDirectUploadService::handleStdOutData);
- connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
- this, &GenericDirectUploadService::handleStdErrData);
- connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
- this, &GenericDirectUploadService::handleReadChannelFinished);
- emit progressMessage(tr("Uploading file \"%1\"...")
- .arg(df.localFilePath().toUserOutput()));
- d->runningProcFile = df;
- d->runningProc->start();
- d->uploadJobRunning = true;
+ emit progressMessage(tr("%n file(s) need to be uploaded.", "", d->filesToUpload.size()));
+ FilesToTransfer filesToTransfer;
+ for (const DeployableFile &f : d->filesToUpload) {
+ if (!f.localFilePath().exists()) {
+ const QString message = tr("Local file \"%1\" does not exist.")
+ .arg(f.localFilePath().toUserOutput());
+ if (d->ignoreMissingFiles) {
+ emit warningMessage(message);
+ continue;
+ } else {
+ emit errorMessage(message);
+ setFinished();
+ handleDeploymentDone();
+ return;
+ }
+ }
+ filesToTransfer << FileToTransfer(f.localFilePath().toString(), f.remoteFilePath());
+ }
+ d->uploader = connection()->createUpload(filesToTransfer, FileTransferErrorHandling::Abort);
+ connect(d->uploader.get(), &SftpTransfer::done, [this](const QString &error) {
+ QTC_ASSERT(d->state == Uploading, return);
+ if (!error.isEmpty()) {
+ emit errorMessage(error);
+ setFinished();
+ handleDeploymentDone();
+ return;
+ }
+ d->state = PostProcessing;
+ chmod();
+ queryFiles();
+ });
+ connect(d->uploader.get(), &SftpTransfer::progress,
+ this, &GenericDirectUploadService::progressMessage);
+ d->uploader->start();
}
-void GenericDirectUploadService::queryFiles()
+void GenericDirectUploadService::chmod()
{
- QTC_ASSERT(d->state == Uploading, return);
-
- for (const DeployableFile &file : qAsConst(d->deployableFiles)) {
- if (!d->incremental || hasLocalFileChanged(file)) {
- d->filesToUpload.append(file);
- continue;
- }
-
- const SftpJobId jobId = d->uploader->statFile(file.remoteFilePath());
- if (jobId == SftpInvalidJob) {
- emit warningMessage(tr("SFTP stat query for %1 failed.").arg(file.remoteFilePath()));
- d->filesToUpload.append(file);
+ QTC_ASSERT(d->state == PostProcessing, return);
+ if (!Utils::HostOsInfo::isWindowsHost())
+ return;
+ for (const DeployableFile &f : d->filesToUpload) {
+ if (!f.isExecutable())
continue;
- }
-
- d->runningJobs.insert(jobId, Job(file, JobType::PreQuery));
+ const QString command = QLatin1String("chmod a+x ")
+ + Utils::QtcProcess::quoteArgUnix(f.remoteFilePath());
+ SshRemoteProcess * const chmodProc
+ = connection()->createRemoteProcess(command.toUtf8()).release();
+ chmodProc->setParent(this);
+ connect(chmodProc, &SshRemoteProcess::done, this,
+ [this, chmodProc, state = d->state](const QString &error) {
+ QTC_ASSERT(state == d->state, return);
+ const DeployableFile file = d->getFileForProcess(chmodProc);
+ QTC_ASSERT(file.isValid(), return);
+ if (!error.isEmpty()) {
+ emit warningMessage(tr("Remote chmod failed for file \"%1\": %2")
+ .arg(file.remoteFilePath(), error));
+ } else if (chmodProc->exitCode() != 0) {
+ emit warningMessage(tr("Remote chmod failed for file \"%1\": %2")
+ .arg(file.remoteFilePath(),
+ QString::fromUtf8(chmodProc->readAllStandardError())));
+ }
+ chmodProc->deleteLater();
+ checkForStateChangeOnRemoteProcFinished();
+ });
+ d->remoteProcs.insert(chmodProc, f);
+ chmodProc->start();
}
-
- uploadNextFile();
}
} //namespace RemoteLinux
diff --git a/src/plugins/remotelinux/genericdirectuploadservice.h b/src/plugins/remotelinux/genericdirectuploadservice.h
index 4f5dbb71b21..c41f8f99cca 100644
--- a/src/plugins/remotelinux/genericdirectuploadservice.h
+++ b/src/plugins/remotelinux/genericdirectuploadservice.h
@@ -32,10 +32,11 @@
#include <QList>
+QT_FORWARD_DECLARE_CLASS(QDateTime)
QT_FORWARD_DECLARE_CLASS(QString)
namespace ProjectExplorer { class DeployableFile; }
-
+namespace QSsh { class SshRemoteProcess; }
namespace RemoteLinux {
namespace Internal { class GenericDirectUploadServicePrivate; }
@@ -60,27 +61,16 @@ public:
void stopDeployment() override;
private:
- void handleSftpInitialized();
- void handleSftpChannelError(const QString &errorMessage);
- void handleFileInfoAvailable(QSsh::SftpJobId jobId, const QList<QSsh::SftpFileInfo> &fileInfos);
- void handleJobFinished(QSsh::SftpJobId jobId, const QString &errorMsg);
- void handleUploadProcFinished(int exitStatus);
- void handleMkdirFinished(int exitStatus);
- void handleStdOutData();
- void handleStdErrData();
- void handleReadChannelFinished();
+ QDateTime timestampFromStat(const ProjectExplorer::DeployableFile &file,
+ QSsh::SshRemoteProcess *statProc);
+ void checkForStateChangeOnRemoteProcFinished();
QList<ProjectExplorer::DeployableFile> collectFilesToUpload(
const ProjectExplorer::DeployableFile &file) const;
void setFinished();
- void uploadNextFile();
void queryFiles();
- void clearRunningProc();
-
- void handleProcFailure();
- void runPostQueryOnProcResult();
-
- void tryFinish();
+ void uploadFiles();
+ void chmod();
Internal::GenericDirectUploadServicePrivate * const d;
};
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
index 9ef6561a3e6..5957ac428b4 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
@@ -48,18 +48,12 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget(
this, &GenericLinuxDeviceConfigurationWidget::hostNameEditingFinished);
connect(m_ui->userLineEdit, &QLineEdit::editingFinished,
this, &GenericLinuxDeviceConfigurationWidget::userNameEditingFinished);
- connect(m_ui->pwdLineEdit, &QLineEdit::editingFinished,
- this, &GenericLinuxDeviceConfigurationWidget::passwordEditingFinished);
- connect(m_ui->passwordButton, &QAbstractButton::toggled,
- this, &GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged);
connect(m_ui->keyFileLineEdit, &PathChooser::editingFinished,
this, &GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished);
connect(m_ui->keyFileLineEdit, &PathChooser::browsingFinished,
this, &GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished);
connect(m_ui->keyButton, &QAbstractButton::toggled,
this, &GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged);
- connect(m_ui->agentButton, &QAbstractButton::toggled,
- this, &GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged);
connect(m_ui->timeoutSpinBox, &QAbstractSpinBox::editingFinished,
this, &GenericLinuxDeviceConfigurationWidget::timeoutEditingFinished);
connect(m_ui->timeoutSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
@@ -68,8 +62,6 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget(
this, &GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished);
connect(m_ui->sshPortSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this, &GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished);
- connect(m_ui->showPasswordCheckBox, &QAbstractButton::toggled,
- this, &GenericLinuxDeviceConfigurationWidget::showPassword);
connect(m_ui->portsLineEdit, &QLineEdit::editingFinished,
this, &GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged);
connect(m_ui->createKeyButton, &QAbstractButton::clicked,
@@ -91,15 +83,11 @@ GenericLinuxDeviceConfigurationWidget::~GenericLinuxDeviceConfigurationWidget()
void GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged()
{
SshConnectionParameters sshParams = device()->sshParameters();
- const bool usePassword = m_ui->passwordButton->isChecked();
const bool useKeyFile = m_ui->keyButton->isChecked();
- sshParams.authenticationType
- = usePassword ? SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- : useKeyFile ? SshConnectionParameters::AuthenticationTypePublicKey
- : SshConnectionParameters::AuthenticationTypeAgent;
+ sshParams.authenticationType = useKeyFile
+ ? SshConnectionParameters::AuthenticationTypeSpecificKey
+ : SshConnectionParameters::AuthenticationTypeAll;
device()->setSshParameters(sshParams);
- m_ui->pwdLineEdit->setEnabled(usePassword);
- m_ui->passwordLabel->setEnabled(usePassword);
m_ui->keyFileLineEdit->setEnabled(useKeyFile);
m_ui->keyLabel->setEnabled(useKeyFile);
}
@@ -132,13 +120,6 @@ void GenericLinuxDeviceConfigurationWidget::userNameEditingFinished()
device()->setSshParameters(sshParams);
}
-void GenericLinuxDeviceConfigurationWidget::passwordEditingFinished()
-{
- SshConnectionParameters sshParams = device()->sshParameters();
- sshParams.setPassword(m_ui->pwdLineEdit->text());
- device()->setSshParameters(sshParams);
-}
-
void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished()
{
SshConnectionParameters sshParams = device()->sshParameters();
@@ -157,12 +138,6 @@ void GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged()
updatePortsWarningLabel();
}
-void GenericLinuxDeviceConfigurationWidget::showPassword(bool showClearText)
-{
- m_ui->pwdLineEdit->setEchoMode(showClearText
- ? QLineEdit::Normal : QLineEdit::Password);
-}
-
void GenericLinuxDeviceConfigurationWidget::setPrivateKey(const QString &path)
{
m_ui->keyFileLineEdit->setPath(path);
@@ -190,7 +165,6 @@ void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi()
sshPortEditingFinished();
timeoutEditingFinished();
userNameEditingFinished();
- passwordEditingFinished();
keyFileEditingFinished();
handleFreePortsChanged();
gdbServerEditingFinished();
@@ -220,16 +194,12 @@ void GenericLinuxDeviceConfigurationWidget::initGui()
const SshConnectionParameters &sshParams = device()->sshParameters();
switch (sshParams.authenticationType) {
- case SshConnectionParameters::AuthenticationTypePublicKey:
+ case SshConnectionParameters::AuthenticationTypeSpecificKey:
m_ui->keyButton->setChecked(true);
break;
- case SshConnectionParameters::AuthenticationTypeAgent:
- m_ui->agentButton->setChecked(true);
+ case SshConnectionParameters::AuthenticationTypeAll:
+ m_ui->defaultAuthButton->setChecked(true);
break;
- case SshConnectionParameters::AuthenticationTypePassword:
- case SshConnectionParameters::AuthenticationTypeKeyboardInteractive:
- case SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods:
- m_ui->passwordButton->setChecked(true);
}
m_ui->timeoutSpinBox->setValue(sshParams.timeout);
m_ui->hostLineEdit->setEnabled(!device()->isAutoDetected());
@@ -241,9 +211,7 @@ void GenericLinuxDeviceConfigurationWidget::initGui()
m_ui->portsLineEdit->setText(device()->freePorts().toString());
m_ui->timeoutSpinBox->setValue(sshParams.timeout);
m_ui->userLineEdit->setText(sshParams.userName());
- m_ui->pwdLineEdit->setText(sshParams.password());
m_ui->keyFileLineEdit->setPath(sshParams.privateKeyFile);
- m_ui->showPasswordCheckBox->setChecked(false);
m_ui->gdbServerLineEdit->setText(device()->debugServerPath());
updatePortsWarningLabel();
}
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h
index 217e5b1379b..7faf3494d6c 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h
@@ -49,10 +49,8 @@ private:
void sshPortEditingFinished();
void timeoutEditingFinished();
void userNameEditingFinished();
- void passwordEditingFinished();
void keyFileEditingFinished();
void gdbServerEditingFinished();
- void showPassword(bool showClearText);
void handleFreePortsChanged();
void setPrivateKey(const QString &path);
void createNewKey();
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui
index 108ab2f344e..6e08ace732d 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui
@@ -52,23 +52,16 @@
<number>0</number>
</property>
<item>
- <widget class="QRadioButton" name="passwordButton">
+ <widget class="QRadioButton" name="defaultAuthButton">
<property name="text">
- <string>Password</string>
+ <string>Default</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="keyButton">
<property name="text">
- <string>&amp;Key</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="agentButton">
- <property name="text">
- <string>Key via ssh-agent</string>
+ <string>Specific &amp;key</string>
</property>
</widget>
</item>
@@ -206,33 +199,8 @@
<item row="4" column="1">
<widget class="QLineEdit" name="userLineEdit"/>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="passwordLabel">
- <property name="text">
- <string>&amp;Password:</string>
- </property>
- <property name="buddy">
- <cstring>pwdLineEdit</cstring>
- </property>
- </widget>
- </item>
<item row="5" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_6">
- <item>
- <widget class="QLineEdit" name="pwdLineEdit">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="showPasswordCheckBox">
- <property name="text">
- <string>Show password</string>
- </property>
- </widget>
- </item>
- </layout>
+ <layout class="QHBoxLayout" name="horizontalLayout_6"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="keyLabel">
@@ -280,7 +248,6 @@
</widget>
</item>
</layout>
- <zorder>passwordLabel</zorder>
<zorder>authTypeButtonsWidget</zorder>
<zorder>hostNameLabel</zorder>
<zorder>userNameLabel</zorder>
@@ -302,7 +269,7 @@
</customwidget>
</customwidgets>
<tabstops>
- <tabstop>passwordButton</tabstop>
+ <tabstop>defaultAuthButton</tabstop>
<tabstop>keyButton</tabstop>
<tabstop>hostLineEdit</tabstop>
<tabstop>sshPortSpinBox</tabstop>
@@ -310,8 +277,6 @@
<tabstop>portsLineEdit</tabstop>
<tabstop>timeoutSpinBox</tabstop>
<tabstop>userLineEdit</tabstop>
- <tabstop>pwdLineEdit</tabstop>
- <tabstop>showPasswordCheckBox</tabstop>
<tabstop>createKeyButton</tabstop>
<tabstop>gdbServerLineEdit</tabstop>
</tabstops>
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
index f2eb58a6130..30a26d66d79 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
@@ -71,11 +71,10 @@ GenericLinuxDeviceConfigurationWizard::~GenericLinuxDeviceConfigurationWizard()
IDevice::Ptr GenericLinuxDeviceConfigurationWizard::device()
{
SshConnectionParameters sshParams;
- sshParams.options &= ~SshConnectionOptions(SshEnableStrictConformanceChecks); // For older SSH servers.
sshParams.url = d->setupPage.url();
sshParams.timeout = 10;
sshParams.authenticationType = d->setupPage.authenticationType();
- if (sshParams.authenticationType == SshConnectionParameters::AuthenticationTypePublicKey)
+ if (sshParams.authenticationType == SshConnectionParameters::AuthenticationTypeSpecificKey)
sshParams.privateKeyFile = d->setupPage.privateKeyFilePath();
IDevice::Ptr device = LinuxDevice::create(d->setupPage.configurationName(),
Core::Id(Constants::GenericLinuxOsType), IDevice::Hardware);
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
index 88c62bcaf88..2ed7f6b1fa7 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp
@@ -62,12 +62,10 @@ GenericLinuxDeviceConfigurationWizardSetupPage::GenericLinuxDeviceConfigurationW
connect(d->ui.userNameLineEdit, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
connect(d->ui.privateKeyPathChooser, &PathChooser::validChanged,
this, &QWizardPage::completeChanged);
- connect(d->ui.passwordButton, &QAbstractButton::toggled,
+ connect(d->ui.defaultAuthButton, &QAbstractButton::toggled,
this, &GenericLinuxDeviceConfigurationWizardSetupPage::handleAuthTypeChanged);
connect(d->ui.keyButton, &QAbstractButton::toggled,
this, &GenericLinuxDeviceConfigurationWizardSetupPage::handleAuthTypeChanged);
- connect(d->ui.agentButton, &QAbstractButton::toggled,
- this, &GenericLinuxDeviceConfigurationWizardSetupPage::handleAuthTypeChanged);
}
GenericLinuxDeviceConfigurationWizardSetupPage::~GenericLinuxDeviceConfigurationWizardSetupPage()
@@ -80,8 +78,7 @@ void GenericLinuxDeviceConfigurationWizardSetupPage::initializePage()
d->ui.nameLineEdit->setText(defaultConfigurationName());
d->ui.hostNameLineEdit->setText(defaultHostName());
d->ui.userNameLineEdit->setText(defaultUserName());
- d->ui.passwordButton->setChecked(true);
- d->ui.passwordLineEdit->setText(defaultPassWord());
+ d->ui.defaultAuthButton->setChecked(true);
d->ui.privateKeyPathChooser->setPath(ProjectExplorer::IDevice::defaultPrivateKeyFilePath());
handleAuthTypeChanged();
}
@@ -91,7 +88,7 @@ bool GenericLinuxDeviceConfigurationWizardSetupPage::isComplete() const
return !configurationName().isEmpty()
&& !d->ui.hostNameLineEdit->text().trimmed().isEmpty()
&& !d->ui.userNameLineEdit->text().trimmed().isEmpty()
- && (authenticationType() != SshConnectionParameters::AuthenticationTypePublicKey
+ && (authenticationType() != SshConnectionParameters::AuthenticationTypeSpecificKey
|| d->ui.privateKeyPathChooser->isValid());
}
@@ -105,17 +102,14 @@ QUrl GenericLinuxDeviceConfigurationWizardSetupPage::url() const
QUrl url;
url.setHost(d->ui.hostNameLineEdit->text().trimmed());
url.setUserName(d->ui.userNameLineEdit->text().trimmed());
- url.setPassword(d->ui.passwordLineEdit->text());
url.setPort(22);
return url;
}
SshConnectionParameters::AuthenticationType GenericLinuxDeviceConfigurationWizardSetupPage::authenticationType() const
{
- return d->ui.passwordButton->isChecked()
- ? SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- : d->ui.keyButton->isChecked() ? SshConnectionParameters::AuthenticationTypePublicKey
- : SshConnectionParameters::AuthenticationTypeAgent;
+ return d->ui.keyButton->isChecked() ? SshConnectionParameters::AuthenticationTypeSpecificKey
+ : SshConnectionParameters::AuthenticationTypeAll;
}
QString GenericLinuxDeviceConfigurationWizardSetupPage::privateKeyFilePath() const
@@ -145,10 +139,8 @@ QString GenericLinuxDeviceConfigurationWizardSetupPage::defaultPassWord() const
void GenericLinuxDeviceConfigurationWizardSetupPage::handleAuthTypeChanged()
{
- d->ui.passwordLineEdit->setEnabled(authenticationType()
- == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods);
d->ui.privateKeyPathChooser->setEnabled(authenticationType()
- == SshConnectionParameters::AuthenticationTypePublicKey);
+ == SshConnectionParameters::AuthenticationTypeSpecificKey);
emit completeChanged();
}
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardsetuppage.ui b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardsetuppage.ui
index 54ccf0d7b09..1c93a359b75 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardsetuppage.ui
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardsetuppage.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>564</width>
- <height>207</height>
+ <width>590</width>
+ <height>188</height>
</rect>
</property>
<property name="windowTitle">
@@ -92,23 +92,16 @@
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
- <widget class="QRadioButton" name="passwordButton">
+ <widget class="QRadioButton" name="defaultAuthButton">
<property name="text">
- <string>Password</string>
+ <string>Default</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="keyButton">
<property name="text">
- <string>Key</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="agentButton">
- <property name="text">
- <string>Agent</string>
+ <string>Specific key</string>
</property>
</widget>
</item>
@@ -128,44 +121,13 @@
</layout>
</item>
<item row="4" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>The user's password:</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_5">
- <item>
- <widget class="QLineEdit" name="passwordLineEdit">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>The file containing the user's private key:</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="Utils::PathChooser" name="privateKeyPathChooser" native="true"/>
diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp
index 913b3250e2b..0702c417385 100644
--- a/src/plugins/remotelinux/linuxdevicetester.cpp
+++ b/src/plugins/remotelinux/linuxdevicetester.cpp
@@ -28,7 +28,7 @@
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
#include <utils/port.h>
#include <utils/qtcassert.h>
-#include <ssh/sftpchannel.h>
+#include <ssh/sftptransfer.h>
#include <ssh/sshremoteprocess.h>
#include <ssh/sshconnection.h>
@@ -48,9 +48,9 @@ class GenericLinuxDeviceTesterPrivate
public:
IDevice::ConstPtr deviceConfiguration;
SshConnection *connection = nullptr;
- SshRemoteProcess::Ptr process;
+ SshRemoteProcessPtr process;
DeviceUsedPortsGatherer portsGatherer;
- SftpChannel::Ptr sftpChannel;
+ SftpTransferPtr sftpUpload;
State state = Inactive;
};
@@ -76,7 +76,7 @@ void GenericLinuxDeviceTester::testDevice(const IDevice::ConstPtr &deviceConfigu
d->connection = new SshConnection(deviceConfiguration->sshParameters(), this);
connect(d->connection, &SshConnection::connected,
this, &GenericLinuxDeviceTester::handleConnected);
- connect(d->connection, &SshConnection::error,
+ connect(d->connection, &SshConnection::errorOccurred,
this, &GenericLinuxDeviceTester::handleConnectionFailure);
emit progressMessage(tr("Connecting to host..."));
@@ -99,7 +99,7 @@ void GenericLinuxDeviceTester::stopTest()
d->process->close();
break;
case TestingSftp:
- d->sftpChannel->closeChannel();
+ d->sftpUpload->stop();
break;
case Inactive:
break;
@@ -113,7 +113,7 @@ void GenericLinuxDeviceTester::handleConnected()
QTC_ASSERT(d->state == Connecting, return);
d->process = d->connection->createRemoteProcess("uname -rsm");
- connect(d->process.data(), &SshRemoteProcess::closed,
+ connect(d->process.get(), &SshRemoteProcess::done,
this, &GenericLinuxDeviceTester::handleProcessFinished);
emit progressMessage(tr("Checking kernel version..."));
@@ -125,15 +125,16 @@ void GenericLinuxDeviceTester::handleConnectionFailure()
{
QTC_ASSERT(d->state != Inactive, return);
- emit errorMessage(tr("SSH connection failure: %1").arg(d->connection->errorString()) + QLatin1Char('\n'));
+ emit errorMessage(d->connection->errorString() + QLatin1Char('\n'));
+
setFinished(TestFailure);
}
-void GenericLinuxDeviceTester::handleProcessFinished(int exitStatus)
+void GenericLinuxDeviceTester::handleProcessFinished(const QString &error)
{
QTC_ASSERT(d->state == RunningUname, return);
- if (exitStatus != SshRemoteProcess::NormalExit || d->process->exitCode() != 0) {
+ if (!error.isEmpty() || d->process->exitCode() != 0) {
const QByteArray stderrOutput = d->process->readAllStandardError();
if (!stderrOutput.isEmpty())
emit errorMessage(tr("uname failed: %1").arg(QString::fromUtf8(stderrOutput)) + QLatin1Char('\n'));
@@ -176,34 +177,35 @@ void GenericLinuxDeviceTester::handlePortListReady()
.arg(portList) + QLatin1Char('\n'));
}
- emit progressMessage(tr("Checking if an SFTP channel can be set up..."));
- d->sftpChannel = d->connection->createSftpChannel();
- connect(d->sftpChannel.data(), &SftpChannel::initialized,
- this, &GenericLinuxDeviceTester::handleSftpInitialized);
- connect(d->sftpChannel.data(), &SftpChannel::channelError,
- this, &GenericLinuxDeviceTester::handleSftpError);
+ emit progressMessage(tr("Checking whether an SFTP connection can be set up..."));
+ d->sftpUpload = d->connection->createUpload(FilesToTransfer(),
+ FileTransferErrorHandling::Abort);
+ connect(d->sftpUpload.get(), &SftpTransfer::done,
+ this, &GenericLinuxDeviceTester::handleSftpFinished);
d->state = TestingSftp;
- d->sftpChannel->initialize();
-}
-
-void GenericLinuxDeviceTester::handleSftpInitialized()
-{
- QTC_ASSERT(d->state == TestingSftp, return);
- emit progressMessage(tr("SFTP channel successfully initialized.\n"));
- setFinished(TestSuccess);
+ d->sftpUpload->start();
}
-void GenericLinuxDeviceTester::handleSftpError(const QString &message)
+void GenericLinuxDeviceTester::handleSftpFinished(const QString &error)
{
QTC_ASSERT(d->state == TestingSftp, return);
- emit errorMessage(tr("Error setting up SFTP channel: %1\n").arg(message));
- setFinished(TestFailure);
+ if (!error.isEmpty()) {
+ emit errorMessage(tr("Error setting up SFTP connection: %1\n").arg(error));
+ setFinished(TestFailure);
+ } else {
+ emit progressMessage(tr("SFTP service available.\n"));
+ setFinished(TestSuccess);
+ }
}
void GenericLinuxDeviceTester::setFinished(TestResult result)
{
d->state = Inactive;
disconnect(&d->portsGatherer, nullptr, this, nullptr);
+ if (d->sftpUpload) {
+ disconnect(d->sftpUpload.get(), nullptr, this, nullptr);
+ d->sftpUpload.release()->deleteLater();
+ }
if (d->connection) {
disconnect(d->connection, nullptr, this, nullptr);
d->connection->deleteLater();
diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h
index d845c2e26c9..a63ec51d04c 100644
--- a/src/plugins/remotelinux/linuxdevicetester.h
+++ b/src/plugins/remotelinux/linuxdevicetester.h
@@ -47,11 +47,10 @@ public:
private:
void handleConnected();
void handleConnectionFailure();
- void handleProcessFinished(int exitStatus);
+ void handleProcessFinished(const QString &error);
void handlePortsGatheringError(const QString &message);
void handlePortListReady();
- void handleSftpInitialized();
- void handleSftpError(const QString &message);
+ void handleSftpFinished(const QString &error);
void setFinished(ProjectExplorer::DeviceTester::TestResult result);
Internal::GenericLinuxDeviceTesterPrivate * const d;
diff --git a/src/plugins/remotelinux/packageuploader.cpp b/src/plugins/remotelinux/packageuploader.cpp
index 5de62edf075..cb5af237840 100644
--- a/src/plugins/remotelinux/packageuploader.cpp
+++ b/src/plugins/remotelinux/packageuploader.cpp
@@ -26,7 +26,7 @@
#include "packageuploader.h"
#include <utils/qtcassert.h>
-#include <ssh/sftpchannel.h>
+#include <ssh/sftptransfer.h>
#include <ssh/sshconnection.h>
using namespace QSsh;
@@ -46,29 +46,24 @@ void PackageUploader::uploadPackage(SshConnection *connection,
{
QTC_ASSERT(m_state == Inactive, return);
- setState(InitializingSftp);
+ setState(Uploading);
emit progress(tr("Preparing SFTP connection..."));
- m_localFilePath = localFilePath;
- m_remoteFilePath = remoteFilePath;
m_connection = connection;
- connect(m_connection, &SshConnection::error,
+ connect(m_connection, &SshConnection::errorOccurred,
this, &PackageUploader::handleConnectionFailure);
- m_uploader = m_connection->createSftpChannel();
- connect(m_uploader.data(), &SftpChannel::initialized,
- this, &PackageUploader::handleSftpChannelInitialized);
- connect(m_uploader.data(), &SftpChannel::channelError,
- this, &PackageUploader::handleSftpChannelError);
- connect(m_uploader.data(), &SftpChannel::finished,
- this, &PackageUploader::handleSftpJobFinished);
- m_uploader->initialize();
+ m_uploader = m_connection->createUpload({FileToTransfer(localFilePath, remoteFilePath)},
+ FileTransferErrorHandling::Abort);
+ connect(m_uploader.get(), &SftpTransfer::done, this, &PackageUploader::handleUploadDone);
+ m_uploader->start();
}
void PackageUploader::cancelUpload()
{
- QTC_ASSERT(m_state == InitializingSftp || m_state == Uploading, return);
+ QTC_ASSERT(m_state == Uploading, return);
- cleanup();
+ setState(Inactive);
+ emit uploadFinished(tr("Package upload canceled."));
}
void PackageUploader::handleConnectionFailure()
@@ -81,53 +76,15 @@ void PackageUploader::handleConnectionFailure()
emit uploadFinished(tr("Connection failed: %1").arg(errorMsg));
}
-void PackageUploader::handleSftpChannelError(const QString &errorMsg)
+void PackageUploader::handleUploadDone(const QString &errorMsg)
{
- QTC_ASSERT(m_state == InitializingSftp || m_state == Inactive, return);
-
- if (m_state == Inactive)
- return;
+ QTC_ASSERT(m_state == Uploading, return);
setState(Inactive);
- emit uploadFinished(tr("SFTP error: %1").arg(errorMsg));
-}
-
-void PackageUploader::handleSftpChannelInitialized()
-{
- QTC_ASSERT(m_state == InitializingSftp || m_state == Inactive, return);
-
- if (m_state == Inactive)
- return;
-
- const SftpJobId job = m_uploader->uploadFile(m_localFilePath,
- m_remoteFilePath, SftpOverwriteExisting);
- if (job == SftpInvalidJob) {
- setState(Inactive);
- emit uploadFinished(tr("Package upload failed: Could not open file."));
- } else {
- emit progress(tr("Starting upload..."));
- setState(Uploading);
- }
-}
-
-void PackageUploader::handleSftpJobFinished(SftpJobId, const QString &errorMsg)
-{
- QTC_ASSERT(m_state == Uploading || m_state == Inactive, return);
-
- if (m_state == Inactive)
- return;
-
if (!errorMsg.isEmpty())
emit uploadFinished(tr("Failed to upload package: %2").arg(errorMsg));
else
emit uploadFinished();
- cleanup();
-}
-
-void PackageUploader::cleanup()
-{
- m_uploader->closeChannel();
- setState(Inactive);
}
void PackageUploader::setState(State newState)
@@ -136,8 +93,9 @@ void PackageUploader::setState(State newState)
return;
if (newState == Inactive) {
if (m_uploader) {
- disconnect(m_uploader.data(), nullptr, this, nullptr);
- m_uploader.clear();
+ disconnect(m_uploader.get(), nullptr, this, nullptr);
+ m_uploader->stop();
+ m_uploader.release()->deleteLater();
}
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);
diff --git a/src/plugins/remotelinux/packageuploader.h b/src/plugins/remotelinux/packageuploader.h
index 7e61eefbe33..99499e9a16d 100644
--- a/src/plugins/remotelinux/packageuploader.h
+++ b/src/plugins/remotelinux/packageuploader.h
@@ -26,7 +26,6 @@
#pragma once
#include <QObject>
-#include <QSharedPointer>
#include <QString>
#include <ssh/sftpdefs.h>
@@ -56,20 +55,15 @@ signals:
void uploadFinished(const QString &errorMsg = QString());
private:
- enum State { InitializingSftp, Uploading, Inactive };
+ enum State { Uploading, Inactive };
void handleConnectionFailure();
- void handleSftpChannelInitialized();
- void handleSftpChannelError(const QString &error);
- void handleSftpJobFinished(QSsh::SftpJobId job, const QString &error);
- void cleanup();
+ void handleUploadDone(const QString &error);
void setState(State newState);
State m_state;
QSsh::SshConnection *m_connection;
- QSharedPointer<QSsh::SftpChannel> m_uploader;
- QString m_localFilePath;
- QString m_remoteFilePath;
+ QSsh::SftpTransferPtr m_uploader;
};
} // namespace Internal
diff --git a/src/plugins/remotelinux/remotelinuxcheckforfreediskspaceservice.cpp b/src/plugins/remotelinux/remotelinuxcheckforfreediskspaceservice.cpp
index 5a336125ed1..de2d43906cf 100644
--- a/src/plugins/remotelinux/remotelinuxcheckforfreediskspaceservice.cpp
+++ b/src/plugins/remotelinux/remotelinuxcheckforfreediskspaceservice.cpp
@@ -69,17 +69,12 @@ void RemoteLinuxCheckForFreeDiskSpaceService::handleStdErr()
void RemoteLinuxCheckForFreeDiskSpaceService::handleProcessFinished()
{
- switch (d->processRunner->processExitStatus()) {
- case QSsh::SshRemoteProcess::FailedToStart:
- emit errorMessage(tr("Remote process failed to start."));
+ if (!d->processRunner->processErrorString().isEmpty()) {
+ emit errorMessage(tr("Remote process failed: %1")
+ .arg(d->processRunner->processErrorString()));
stopDeployment();
return;
- case QSsh::SshRemoteProcess::CrashExit:
- emit errorMessage(tr("Remote process crashed."));
- stopDeployment();
- return;
- case QSsh::SshRemoteProcess::NormalExit:
- break;
+
}
bool isNumber;
diff --git a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp
index eddcda0f195..ffa1dfe6af7 100644
--- a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp
+++ b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp
@@ -119,14 +119,12 @@ void RemoteLinuxCustomCommandDeployService::handleStderr()
emit stdErrData(QString::fromUtf8(d->runner->readAllStandardError()));
}
-void RemoteLinuxCustomCommandDeployService::handleProcessClosed(int exitStatus)
+void RemoteLinuxCustomCommandDeployService::handleProcessClosed(const QString &error)
{
QTC_ASSERT(d->state == Running, return);
- if (exitStatus == SshRemoteProcess::FailedToStart) {
- emit errorMessage(tr("Remote process failed to start."));
- } else if (exitStatus == SshRemoteProcess::CrashExit) {
- emit errorMessage(tr("Remote process was killed by a signal."));
+ if (!error.isEmpty()) {
+ emit errorMessage(tr("Remote process failed: %1").arg(error));
} else if (d->runner->processExitCode() != 0) {
emit errorMessage(tr("Remote process finished with exit code %1.")
.arg(d->runner->processExitCode()));
diff --git a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.h b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.h
index 75352420f6d..33b0e67b1d8 100644
--- a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.h
+++ b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.h
@@ -52,7 +52,7 @@ protected:
private:
void handleStdout();
void handleStderr();
- void handleProcessClosed(int exitStatus);
+ void handleProcessClosed(const QString &error);
Internal::RemoteLinuxCustomCommandDeployservicePrivate *d;
};
diff --git a/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp b/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp
index 3f84fa7c37a..4d3439931bb 100644
--- a/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp
+++ b/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp
@@ -98,12 +98,12 @@ void AbstractRemoteLinuxPackageInstaller::handleConnectionError()
setFinished();
}
-void AbstractRemoteLinuxPackageInstaller::handleInstallationFinished(int exitStatus)
+void AbstractRemoteLinuxPackageInstaller::handleInstallationFinished(const QString &error)
{
if (!d->isRunning)
return;
- if (exitStatus != SshRemoteProcess::NormalExit || d->installer->processExitCode() != 0)
+ if (!error.isEmpty() || d->installer->processExitCode() != 0)
emit finished(tr("Installing package failed."));
else if (!errorString().isEmpty())
emit finished(errorString());
diff --git a/src/plugins/remotelinux/remotelinuxpackageinstaller.h b/src/plugins/remotelinux/remotelinuxpackageinstaller.h
index 25f1b34f77e..ddf713eda28 100644
--- a/src/plugins/remotelinux/remotelinuxpackageinstaller.h
+++ b/src/plugins/remotelinux/remotelinuxpackageinstaller.h
@@ -54,7 +54,7 @@ protected:
private:
void handleConnectionError();
- void handleInstallationFinished(int exitStatus);
+ void handleInstallationFinished(const QString &error);
void handleInstallerOutput();
void handleInstallerErrorOutput();
diff --git a/src/plugins/remotelinux/sshkeydeployer.cpp b/src/plugins/remotelinux/sshkeydeployer.cpp
index 5d7cccdc8f7..7581a720185 100644
--- a/src/plugins/remotelinux/sshkeydeployer.cpp
+++ b/src/plugins/remotelinux/sshkeydeployer.cpp
@@ -79,19 +79,18 @@ void SshKeyDeployer::handleConnectionFailure()
emit error(tr("Connection failed: %1").arg(d->deployProcess.lastConnectionErrorString()));
}
-void SshKeyDeployer::handleKeyUploadFinished(int exitStatus)
+void SshKeyDeployer::handleKeyUploadFinished()
{
- Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart
- || exitStatus == SshRemoteProcess::CrashExit
- || exitStatus == SshRemoteProcess::NormalExit);
-
const int exitCode = d->deployProcess.processExitCode();
const QString errorMsg = d->deployProcess.processErrorString();
cleanup();
- if (exitStatus == SshRemoteProcess::NormalExit && exitCode == 0)
+ if (errorMsg.isEmpty() && exitCode == 0) {
emit finishedSuccessfully();
- else
- emit error(tr("Key deployment failed: %1.").arg(errorMsg));
+ } else {
+ emit error(tr("Key deployment failed: %1.").arg(errorMsg.isEmpty()
+ ? QString::fromUtf8(d->deployProcess.readAllStandardError())
+ : errorMsg));
+ }
}
void SshKeyDeployer::stopDeployment()
diff --git a/src/plugins/remotelinux/sshkeydeployer.h b/src/plugins/remotelinux/sshkeydeployer.h
index 8c5df26d8ab..664543cb3c3 100644
--- a/src/plugins/remotelinux/sshkeydeployer.h
+++ b/src/plugins/remotelinux/sshkeydeployer.h
@@ -52,7 +52,7 @@ signals:
private:
void handleConnectionFailure();
- void handleKeyUploadFinished(int exitStatus);
+ void handleKeyUploadFinished();
void cleanup();
Internal::SshKeyDeployerPrivate * const d;
diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
index 40a025b5d94..1974ced68f5 100644
--- a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
+++ b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp
@@ -25,7 +25,7 @@
#include "callgrindcontroller.h"
-#include <ssh/sftpchannel.h>
+#include <ssh/sftpsession.h>
#include <ssh/sshconnectionmanager.h>
#include <utils/fileutils.h>
@@ -237,12 +237,12 @@ void CallgrindController::foundRemoteFile()
{
m_remoteFile = m_findRemoteFile->readAllStandardOutput().trimmed();
- m_sftp = m_ssh->createSftpChannel();
- connect(m_sftp.data(), &QSsh::SftpChannel::finished,
+ m_sftp = m_ssh->createSftpSession();
+ connect(m_sftp.get(), &QSsh::SftpSession::commandFinished,
this, &CallgrindController::sftpJobFinished);
- connect(m_sftp.data(), &QSsh::SftpChannel::initialized,
+ connect(m_sftp.get(), &QSsh::SftpSession::started,
this, &CallgrindController::sftpInitialized);
- m_sftp->initialize();
+ m_sftp->start();
}
void CallgrindController::sftpInitialized()
@@ -254,14 +254,14 @@ void CallgrindController::sftpInitialized()
dataFile.setAutoRemove(false);
dataFile.close();
- m_downloadJob = m_sftp->downloadFile(QString::fromUtf8(m_remoteFile), m_tempDataFile, QSsh::SftpOverwriteExisting);
+ m_downloadJob = m_sftp->downloadFile(QString::fromUtf8(m_remoteFile), m_tempDataFile);
}
void CallgrindController::sftpJobFinished(QSsh::SftpJobId job, const QString &error)
{
QTC_ASSERT(job == m_downloadJob, return);
- m_sftp->closeChannel();
+ m_sftp->quit();
if (error.isEmpty())
emit localParseDataAvailable(m_tempDataFile);
diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.h b/src/plugins/valgrind/callgrind/callgrindcontroller.h
index 057ec794a83..d3a6639e4e2 100644
--- a/src/plugins/valgrind/callgrind/callgrindcontroller.h
+++ b/src/plugins/valgrind/callgrind/callgrindcontroller.h
@@ -26,7 +26,6 @@
#pragma once
#include <ssh/sshremoteprocess.h>
-#include <ssh/sftpchannel.h>
#include <ssh/sshconnection.h>
#include <projectexplorer/runconfiguration.h>
@@ -91,8 +90,8 @@ private:
// remote callgrind support
QSsh::SshConnection *m_ssh = nullptr;
QString m_tempDataFile;
- QSsh::SshRemoteProcess::Ptr m_findRemoteFile;
- QSsh::SftpChannel::Ptr m_sftp;
+ QSsh::SshRemoteProcessPtr m_findRemoteFile;
+ QSsh::SftpSessionPtr m_sftp;
QSsh::SftpJobId m_downloadJob = 0;
QByteArray m_remoteFile;
};
diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp
index 31fbab64cf9..a9e8fbd51cc 100644
--- a/src/plugins/valgrind/memchecktool.cpp
+++ b/src/plugins/valgrind/memchecktool.cpp
@@ -155,7 +155,7 @@ public:
*localServerAddress = connection.connectionInfo().localAddress;
reportStarted();
});
- connect(&connection, &QSsh::SshConnection::error, this, [this] {
+ connect(&connection, &QSsh::SshConnection::errorOccurred, this, [this] {
reportFailure();
});
}