summaryrefslogtreecommitdiff
path: root/src/plugins/remotelinux
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2018-11-23 11:07:57 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2018-12-13 15:10:11 +0000
commitd7178b88c4b2572fb83b28f8178940766216deed (patch)
tree861eb8069fb97c8e8e79f56cb8f88f05126639fc /src/plugins/remotelinux
parent030d4d01084b04af361f07dd6360dfad8e2cc19c (diff)
downloadqt-creator-d7178b88c4b2572fb83b28f8178940766216deed.tar.gz
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 <eike.ziller@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/plugins/remotelinux')
-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
20 files changed, 275 insertions, 602 deletions
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>&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 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;