diff options
Diffstat (limited to 'src/plugins')
39 files changed, 623 insertions, 755 deletions
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 939d4d3884..e5bcc779a9 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 2b086f0683..bd9c2b606e 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 2ff4090ffd..0487954312 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 9feb7e7166..e3cc959a5d 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 19acc31769..7bbe942354 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 589b3d1721..c1c7b0a45f 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 8ecefce9b9..60937e65cc 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 0000000000..c87d27d978 --- /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 0000000000..e43ef93826 --- /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 5048c2d0ca..068b4f720b 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 21f70f48e2..8ef32ae9ba 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 d25b52c7d4..5836c06c45 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 61f1429fbe..de81a42833 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 3c8c37e98a..004de59acb 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 67acf1c776..91d5548bda 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 58b71f9586..2ca8968388 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 c63e16ce5a..12e47ca0d2 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 3112d519c8..100cf04020 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 4f5dbb71b2..c41f8f99cc 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 9ef6561a3e..5957ac428b 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 217e5b1379..7faf3494d6 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 108ab2f344..6e08ace732 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>&Key</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="agentButton"> - <property name="text"> - <string>Key via ssh-agent</string> + <string>Specific &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>&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 f2eb58a613..30a26d66d7 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 88c62bcaf8..2ed7f6b1fa 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 54ccf0d7b0..1c93a359b7 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 913b3250e2..0702c41738 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 d845c2e26c..a63ec51d04 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 5de62edf07..cb5af23784 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 7e61eefbe3..99499e9a16 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 5a336125ed..de2d43906c 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 eddcda0f19..ffa1dfe6af 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 75352420f6..33b0e67b1d 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 3f84fa7c37..4d3439931b 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 25f1b34f77..ddf713eda2 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 5d7cccdc8f..7581a72018 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 8c5df26d8a..664543cb3c 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 40a025b5d9..1974ced68f 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 057ec794a8..d3a6639e4e 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 31fbab64cf..a9e8fbd51c 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(); }); } |