aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp16
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxdeployservice.h8
-rw-r--r--src/plugins/remotelinux/abstractuploadandinstallpackageservice.cpp5
-rw-r--r--src/plugins/remotelinux/deploymenttimeinfo.cpp99
-rw-r--r--src/plugins/remotelinux/deploymenttimeinfo.h11
-rw-r--r--src/plugins/remotelinux/genericdirectuploadservice.cpp324
-rw-r--r--src/plugins/remotelinux/genericdirectuploadservice.h16
-rw-r--r--src/plugins/remotelinux/tarpackagecreationstep.cpp4
8 files changed, 328 insertions, 155 deletions
diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
index 4da0fff0fe..6e663bf817 100644
--- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
+++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp
@@ -96,14 +96,22 @@ SshConnection *AbstractRemoteLinuxDeployService::connection() const
return d->connection;
}
-void AbstractRemoteLinuxDeployService::saveDeploymentTimeStamp(const DeployableFile &deployableFile)
+void AbstractRemoteLinuxDeployService::saveDeploymentTimeStamp(const DeployableFile &deployableFile,
+ const QDateTime &remoteTimestamp)
{
- d->deployTimes.saveDeploymentTimeStamp(deployableFile, profile());
+ d->deployTimes.saveDeploymentTimeStamp(deployableFile, profile(), remoteTimestamp);
}
-bool AbstractRemoteLinuxDeployService::hasChangedSinceLastDeployment(const DeployableFile &deployableFile) const
+bool AbstractRemoteLinuxDeployService::hasLocalFileChanged(
+ const DeployableFile &deployableFile) const
{
- return d->deployTimes.hasChangedSinceLastDeployment(deployableFile, profile());
+ return d->deployTimes.hasLocalFileChanged(deployableFile, profile());
+}
+
+bool AbstractRemoteLinuxDeployService::hasRemoteFileChanged(
+ const DeployableFile &deployableFile, const QDateTime &remoteTimestamp) const
+{
+ return d->deployTimes.hasRemoteFileChanged(deployableFile, profile(), remoteTimestamp);
}
void AbstractRemoteLinuxDeployService::setTarget(Target *target)
diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.h b/src/plugins/remotelinux/abstractremotelinuxdeployservice.h
index 0553472b95..9e55708d65 100644
--- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.h
+++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.h
@@ -76,8 +76,12 @@ protected:
ProjectExplorer::IDevice::ConstPtr deviceConfiguration() const;
QSsh::SshConnection *connection() const;
- void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile);
- bool hasChangedSinceLastDeployment(const ProjectExplorer::DeployableFile &deployableFile) const;
+ void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile,
+ const QDateTime &remoteTimestamp);
+
+ bool hasLocalFileChanged(const ProjectExplorer::DeployableFile &deployableFile) const;
+ bool hasRemoteFileChanged(const ProjectExplorer::DeployableFile &deployableFile,
+ const QDateTime &remoteTimestamp) const;
void handleDeviceSetupDone(bool success);
void handleDeploymentDone();
diff --git a/src/plugins/remotelinux/abstractuploadandinstallpackageservice.cpp b/src/plugins/remotelinux/abstractuploadandinstallpackageservice.cpp
index 5974a6d557..16c1e6fc29 100644
--- a/src/plugins/remotelinux/abstractuploadandinstallpackageservice.cpp
+++ b/src/plugins/remotelinux/abstractuploadandinstallpackageservice.cpp
@@ -31,6 +31,7 @@
#include <projectexplorer/deployablefile.h>
#include <utils/qtcassert.h>
+#include <QDateTime>
#include <QString>
using namespace ProjectExplorer;
@@ -87,7 +88,7 @@ QString AbstractUploadAndInstallPackageService::uploadDir() const
bool AbstractUploadAndInstallPackageService::isDeploymentNecessary() const
{
- return hasChangedSinceLastDeployment(DeployableFile(packageFilePath(), QString()));
+ return hasLocalFileChanged(DeployableFile(packageFilePath(), QString()));
}
void AbstractUploadAndInstallPackageService::doDeviceSetup()
@@ -164,7 +165,7 @@ void AbstractUploadAndInstallPackageService::handleInstallationFinished(const QS
QTC_ASSERT(d->state == Installing, return);
if (errorMsg.isEmpty()) {
- saveDeploymentTimeStamp(DeployableFile(packageFilePath(), QString()));
+ saveDeploymentTimeStamp(DeployableFile(packageFilePath(), QString()), QDateTime());
emit progressMessage(tr("Package installed."));
} else {
emit errorMessage(errorMsg);
diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp
index fea219769b..31a4c22eef 100644
--- a/src/plugins/remotelinux/deploymenttimeinfo.cpp
+++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp
@@ -46,6 +46,8 @@ const char LastDeployedSysrootsKey[] = "ProjectExplorer.RunConfiguration.LastDep
const char LastDeployedFilesKey[] = "ProjectExplorer.RunConfiguration.LastDeployedFiles";
const char LastDeployedRemotePathsKey[] = "ProjectExplorer.RunConfiguration.LastDeployedRemotePaths";
const char LastDeployedTimesKey[] = "ProjectExplorer.RunConfiguration.LastDeployedTimes";
+const char LastDeployedLocalTimesKey[] = "RemoteLinux.LastDeployedLocalTimes";
+const char LastDeployedRemoteTimesKey[] = "RemoteLinux.LastDeployedRemoteTimes";
class DeployParameters
{
@@ -72,7 +74,29 @@ uint qHash(const DeployParameters &p) {
class DeploymentTimeInfoPrivate
{
public:
- QHash<DeployParameters, QDateTime> lastDeployed;
+ struct Timestamps
+ {
+ QDateTime local;
+ QDateTime remote;
+ };
+ QHash<DeployParameters, Timestamps> lastDeployed;
+
+ DeployParameters parameters(const ProjectExplorer::DeployableFile &deployableFile,
+ const ProjectExplorer::Kit *kit) const
+ {
+ QString systemRoot;
+ QString host;
+
+ if (kit) {
+ if (SysRootKitInformation::hasSysRoot(kit))
+ systemRoot = SysRootKitInformation::sysRoot(kit).toString();
+
+ const IDevice::ConstPtr deviceConfiguration = DeviceKitInformation::device(kit);
+ host = deviceConfiguration->sshParameters().host();
+ }
+
+ return DeployParameters(deployableFile, host, systemRoot);
+ }
};
@@ -87,42 +111,27 @@ DeploymentTimeInfo::~DeploymentTimeInfo()
}
void DeploymentTimeInfo::saveDeploymentTimeStamp(const DeployableFile &deployableFile,
- const Kit *kit)
+ const Kit *kit, const QDateTime &remoteTimestamp)
{
- if (!kit)
- return;
-
- QString systemRoot;
- if (SysRootKitInformation::hasSysRoot(kit))
- systemRoot = SysRootKitInformation::sysRoot(kit).toString();
-
- const IDevice::ConstPtr deviceConfiguration = DeviceKitInformation::device(kit);
- const QString host = deviceConfiguration->sshParameters().host();
-
d->lastDeployed.insert(
- DeployParameters(deployableFile, host, systemRoot),
- QDateTime::currentDateTime());
+ d->parameters(deployableFile, kit),
+ { deployableFile.localFilePath().toFileInfo().lastModified(), remoteTimestamp });
}
-bool DeploymentTimeInfo::hasChangedSinceLastDeployment(const DeployableFile &deployableFile,
- const ProjectExplorer::Kit *kit) const
+bool DeploymentTimeInfo::hasLocalFileChanged(const DeployableFile &deployableFile,
+ const ProjectExplorer::Kit *kit) const
{
- if (!kit)
- return false;
-
- QString systemRoot;
- if (SysRootKitInformation::hasSysRoot(kit))
- systemRoot = SysRootKitInformation::sysRoot(kit).toString();
-
- const IDevice::ConstPtr deviceConfiguration = DeviceKitInformation::device(kit);
- const QString host = deviceConfiguration->sshParameters().host();
-
- const DeployParameters dp(deployableFile, host, systemRoot);
-
- const QDateTime &lastDeployed = d->lastDeployed.value(dp);
+ const auto &lastDeployed = d->lastDeployed.value(d->parameters(deployableFile, kit));
const QDateTime lastModified = deployableFile.localFilePath().toFileInfo().lastModified();
+ return !lastDeployed.local.isValid() || lastModified != lastDeployed.local;
+}
- return !lastDeployed.isValid() || (lastModified > lastDeployed);
+bool DeploymentTimeInfo::hasRemoteFileChanged(const DeployableFile &deployableFile,
+ const ProjectExplorer::Kit *kit,
+ const QDateTime &remoteTimestamp) const
+{
+ const auto &lastDeployed = d->lastDeployed.value(d->parameters(deployableFile, kit));
+ return !lastDeployed.remote.isValid() || remoteTimestamp != lastDeployed.remote;
}
QVariantMap DeploymentTimeInfo::exportDeployTimes() const
@@ -132,21 +141,24 @@ QVariantMap DeploymentTimeInfo::exportDeployTimes() const
QVariantList fileList;
QVariantList sysrootList;
QVariantList remotePathList;
- QVariantList timeList;
- typedef QHash<DeployParameters, QDateTime>::ConstIterator DepIt;
+ QVariantList localTimeList;
+ QVariantList remoteTimeList;
+ using DepIt = QHash<DeployParameters, DeploymentTimeInfoPrivate::Timestamps>::ConstIterator;
for (DepIt it = d->lastDeployed.constBegin(); it != d->lastDeployed.constEnd(); ++it) {
fileList << it.key().file.localFilePath().toString();
remotePathList << it.key().file.remoteDirectory();
hostList << it.key().host;
sysrootList << it.key().sysroot;
- timeList << it.value();
+ localTimeList << it.value().local;
+ remoteTimeList << it.value().remote;
}
map.insert(QLatin1String(LastDeployedHostsKey), hostList);
map.insert(QLatin1String(LastDeployedSysrootsKey), sysrootList);
map.insert(QLatin1String(LastDeployedFilesKey), fileList);
map.insert(QLatin1String(LastDeployedRemotePathsKey), remotePathList);
- map.insert(QLatin1String(LastDeployedTimesKey), timeList);
+ map.insert(QLatin1String(LastDeployedLocalTimesKey), localTimeList);
+ map.insert(QLatin1String(LastDeployedRemoteTimesKey), remoteTimeList);
return map;
}
@@ -157,16 +169,29 @@ void DeploymentTimeInfo::importDeployTimes(const QVariantMap &map)
const QVariantList &fileList = map.value(QLatin1String(LastDeployedFilesKey)).toList();
const QVariantList &remotePathList
= map.value(QLatin1String(LastDeployedRemotePathsKey)).toList();
- const QVariantList &timeList = map.value(QLatin1String(LastDeployedTimesKey)).toList();
+
+ QVariantList localTimesList;
+ const auto localTimes = map.find(QLatin1String(LastDeployedLocalTimesKey));
+ if (localTimes != map.end()) {
+ localTimesList = localTimes.value().toList();
+ } else {
+ localTimesList = map.value(QLatin1String(LastDeployedTimesKey)).toList();
+ }
+
+ const QVariantList remoteTimesList
+ = map.value(QLatin1String(LastDeployedRemoteTimesKey)).toList();
const int elemCount = qMin(qMin(qMin(hostList.size(), fileList.size()),
- qMin(remotePathList.size(), timeList.size())),
+ qMin(remotePathList.size(), localTimesList.size())),
sysrootList.size());
for (int i = 0; i < elemCount; ++i) {
const DeployableFile df(fileList.at(i).toString(), remotePathList.at(i).toString());
const DeployParameters dp(df, hostList.at(i).toString(), sysrootList.at(i).toString());
- d->lastDeployed.insert(dp, timeList.at(i).toDateTime());
+ d->lastDeployed.insert(dp, { localTimesList.at(i).toDateTime(),
+ remoteTimesList.length() > i
+ ? remoteTimesList.at(i).toDateTime()
+ : QDateTime() });
}
}
diff --git a/src/plugins/remotelinux/deploymenttimeinfo.h b/src/plugins/remotelinux/deploymenttimeinfo.h
index b0d14f829d..3c91be74c7 100644
--- a/src/plugins/remotelinux/deploymenttimeinfo.h
+++ b/src/plugins/remotelinux/deploymenttimeinfo.h
@@ -47,10 +47,15 @@ public:
QVariantMap exportDeployTimes() const;
void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile,
- const ProjectExplorer::Kit *kit);
+ const ProjectExplorer::Kit *kit,
+ const QDateTime &remoteTimestamp);
- bool hasChangedSinceLastDeployment(const ProjectExplorer::DeployableFile &deployableFile,
- const ProjectExplorer::Kit *kit) const;
+ bool hasLocalFileChanged(const ProjectExplorer::DeployableFile &deployableFile,
+ const ProjectExplorer::Kit *kit) const;
+
+ bool hasRemoteFileChanged(const ProjectExplorer::DeployableFile &deployableFile,
+ const ProjectExplorer::Kit *kit,
+ const QDateTime &remoteTimestamp) const;
private:
DeploymentTimeInfoPrivate *d;
diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp
index e9cfaf5dc7..8ea7dbac2a 100644
--- a/src/plugins/remotelinux/genericdirectuploadservice.cpp
+++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp
@@ -36,6 +36,8 @@
#include <QFileInfo>
#include <QList>
#include <QString>
+#include <QDateTime>
+#include <QHash>
using namespace ProjectExplorer;
using namespace QSsh;
@@ -46,6 +48,23 @@ namespace {
enum State { Inactive, InitializingSftp, Uploading };
} // anonymous namespace
+enum class JobType {
+ PreQuery,
+ Upload,
+ Mkdir,
+ Ln,
+ Chmod,
+ PostQuery,
+ None
+};
+
+struct Job
+{
+ DeployableFile file;
+ JobType type = JobType::None;
+ QDateTime result;
+};
+
class GenericDirectUploadServicePrivate
{
public:
@@ -54,12 +73,17 @@ public:
bool incremental;
bool ignoreMissingFiles;
+ bool uploadJobRunning = false;
State state;
+
QList<DeployableFile> filesToUpload;
+
+ QHash<SftpJobId, Job> runningJobs;
+
+ SshRemoteProcess::Ptr runningProc;
+ DeployableFile runningProcFile;
+
SftpChannel::Ptr uploader;
- SshRemoteProcess::Ptr mkdirProc;
- SshRemoteProcess::Ptr lnProc;
- SshRemoteProcess::Ptr chmodProc;
QList<DeployableFile> deployableFiles;
};
@@ -94,10 +118,14 @@ void GenericDirectUploadService::setIgnoreMissingFiles(bool ignoreMissingFiles)
bool GenericDirectUploadService::isDeploymentNecessary() const
{
- d->filesToUpload.clear();
+ QTC_ASSERT(d->filesToUpload.isEmpty(), d->filesToUpload.clear());
+ QList<DeployableFile> collected;
for (int i = 0; i < d->deployableFiles.count(); ++i)
- checkDeploymentNeeded(d->deployableFiles.at(i));
- return !d->filesToUpload.isEmpty();
+ collected.append(collectFilesToUpload(d->deployableFiles.at(i)));
+
+ QTC_CHECK(collected.size() >= d->deployableFiles.size());
+ d->deployableFiles = collected;
+ return !d->deployableFiles.isEmpty();
}
void GenericDirectUploadService::doDeviceSetup()
@@ -130,12 +158,13 @@ void GenericDirectUploadService::doDeploy()
void GenericDirectUploadService::handleSftpInitialized()
{
QTC_ASSERT(d->state == InitializingSftp, setFinished(); return);
-
- Q_ASSERT(!d->filesToUpload.isEmpty());
+ QTC_ASSERT(!d->deployableFiles.isEmpty(), setFinished(); return);
connect(d->uploader.data(), &SftpChannel::finished,
- this, &GenericDirectUploadService::handleUploadFinished);
+ this, &GenericDirectUploadService::handleJobFinished);
+ connect(d->uploader.data(), &SftpChannel::fileInfoAvailable,
+ this, &GenericDirectUploadService::handleFileInfoAvailable);
d->state = Uploading;
- uploadNextFile();
+ queryFiles();
}
void GenericDirectUploadService::handleSftpChannelError(const QString &message)
@@ -147,94 +176,154 @@ void GenericDirectUploadService::handleSftpChannelError(const QString &message)
handleDeploymentDone();
}
-void GenericDirectUploadService::handleUploadFinished(SftpJobId jobId, const QString &errorMsg)
+void GenericDirectUploadService::handleFileInfoAvailable(SftpJobId jobId,
+ const QList<SftpFileInfo> &fileInfos)
{
- Q_UNUSED(jobId);
-
- QTC_ASSERT(d->state == Uploading, setFinished(); return);
+ 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::fromTime_t(fileInfos.at(0).mtime);
+}
- const DeployableFile df = d->filesToUpload.takeFirst();
- if (!errorMsg.isEmpty()) {
- QString errorString = tr("Upload of file \"%1\" failed. The server said: \"%2\".")
- .arg(df.localFilePath().toUserOutput(), errorMsg);
- if (errorMsg == QLatin1String("Failure")
- && df.remoteDirectory().contains(QLatin1String("/bin"))) {
- errorString += QLatin1Char(' ') + tr("If \"%1\" is currently running "
- "on the remote host, you might need to stop it first.").arg(df.remoteFilePath());
+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();
}
- emit errorMessage(errorString);
- setFinished();
- handleDeploymentDone();
- } else {
- saveDeploymentTimeStamp(df);
// This is done for Windows.
- if (df.isExecutable()) {
+ if (job.file.isExecutable()) {
const QString command = QLatin1String("chmod a+x ")
- + Utils::QtcProcess::quoteArgUnix(df.remoteFilePath());
- d->chmodProc = connection()->createRemoteProcess(command.toUtf8());
- connect(d->chmodProc.data(), &SshRemoteProcess::closed,
- this, &GenericDirectUploadService::handleChmodFinished);
- connect(d->chmodProc.data(), &SshRemoteProcess::readyReadStandardOutput,
+ + 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->chmodProc.data(), &SshRemoteProcess::readyReadStandardError,
+ connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
this, &GenericDirectUploadService::handleStdErrData);
- connect(d->chmodProc.data(), &SshRemoteProcess::readChannelFinished,
+ connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
this, &GenericDirectUploadService::handleReadChannelFinished);
- d->chmodProc->start();
+ 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.file, JobType::PostQuery, QDateTime() });
+ }
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;
}
}
-void GenericDirectUploadService::handleLnFinished(int exitStatus)
+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);
- const DeployableFile df = d->filesToUpload.takeFirst();
- const QString nativePath = df.localFilePath().toUserOutput();
- if (exitStatus != SshRemoteProcess::NormalExit || d->lnProc->exitCode() != 0) {
- emit errorMessage(tr("Failed to upload file \"%1\".").arg(nativePath));
- setFinished();
- handleDeploymentDone();
- 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 {
- saveDeploymentTimeStamp(df);
- uploadNextFile();
+ d->runningJobs.insert(jobId, { d->runningProcFile, JobType::PostQuery, QDateTime() });
}
+ clearRunningProc();
+ uploadNextFile();
}
-void GenericDirectUploadService::handleChmodFinished(int exitStatus)
+void GenericDirectUploadService::tryFinish()
{
- QTC_ASSERT(d->state == Uploading, setFinished(); return);
-
- if (exitStatus != SshRemoteProcess::NormalExit || d->chmodProc->exitCode() != 0) {
- emit errorMessage(tr("Failed to set executable flag."));
+ if (d->filesToUpload.isEmpty() && d->runningJobs.isEmpty() && d->runningProc.isNull()) {
+ emit progressMessage(tr("All files successfully deployed."));
setFinished();
handleDeploymentDone();
- return;
}
- uploadNextFile();
}
void GenericDirectUploadService::handleMkdirFinished(int exitStatus)
{
QTC_ASSERT(d->state == Uploading, setFinished(); return);
- const DeployableFile &df = d->filesToUpload.first();
- QFileInfo fi = df.localFilePath().toFileInfo();
- const QString nativePath = df.localFilePath().toUserOutput();
- if (exitStatus != SshRemoteProcess::NormalExit || d->mkdirProc->exitCode() != 0) {
- emit errorMessage(tr("Failed to upload file \"%1\".").arg(nativePath));
- setFinished();
- handleDeploymentDone();
+ QFileInfo fi = d->runningProcFile.localFilePath().toFileInfo();
+ if (exitStatus != SshRemoteProcess::NormalExit || d->runningProc->exitCode() != 0) {
+ handleProcFailure();
} else if (fi.isDir()) {
- saveDeploymentTimeStamp(df);
- d->filesToUpload.removeFirst();
- uploadNextFile();
+ runPostQueryOnProcResult();
} else {
- const QString remoteFilePath = df.remoteDirectory() + QLatin1Char('/') + fi.fileName();
+ 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")
@@ -242,31 +331,37 @@ void GenericDirectUploadService::handleMkdirFinished(int exitStatus)
const QString command = Utils::QtcProcess::joinArgs(args, Utils::OsTypeLinux);
// See comment in SftpChannel::createLink as to why we can't use it.
- d->lnProc = connection()->createRemoteProcess(command.toUtf8());
- connect(d->lnProc.data(), &SshRemoteProcess::closed,
- this, &GenericDirectUploadService::handleLnFinished);
- connect(d->lnProc.data(), &SshRemoteProcess::readyReadStandardOutput,
+ 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->lnProc.data(), &SshRemoteProcess::readyReadStandardError,
+ connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
this, &GenericDirectUploadService::handleStdErrData);
- connect(d->lnProc.data(), &SshRemoteProcess::readChannelFinished,
+ connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
this, &GenericDirectUploadService::handleReadChannelFinished);
- d->lnProc->start();
+ d->runningProc->start();
} else {
- const SftpJobId job = d->uploader->uploadFile(df.localFilePath().toString(),
- remoteFilePath, SftpOverwriteExisting);
+ 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(nativePath);
+ "Could not open for reading.")
+ .arg(d->runningProcFile.localFilePath().toUserOutput());
+ clearRunningProc();
if (d->ignoreMissingFiles) {
emit warningMessage(message);
- d->filesToUpload.removeFirst();
uploadNextFile();
} else {
emit errorMessage(message);
setFinished();
handleDeploymentDone();
}
+ } else {
+ d->runningJobs[job] = { d->runningProcFile, JobType::Upload, QDateTime() };
+ clearRunningProc();
+ d->uploadJobRunning = true;
}
}
}
@@ -301,54 +396,55 @@ void GenericDirectUploadService::stopDeployment()
handleDeploymentDone();
}
-void GenericDirectUploadService::checkDeploymentNeeded(const DeployableFile &deployable) const
+QList<DeployableFile> GenericDirectUploadService::collectFilesToUpload(
+ const DeployableFile &deployable) const
{
+ QList<DeployableFile> collected({deployable});
QFileInfo fileInfo = deployable.localFilePath().toFileInfo();
if (fileInfo.isDir()) {
const QStringList files = QDir(deployable.localFilePath().toString())
.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
- if (files.isEmpty() && (!d->incremental || hasChangedSinceLastDeployment(deployable)))
- d->filesToUpload << deployable;
- foreach (const QString &fileName, files) {
+ for (const QString &fileName : files) {
const QString localFilePath = deployable.localFilePath().toString()
+ QLatin1Char('/') + fileName;
const QString remoteDir = deployable.remoteDirectory() + QLatin1Char('/')
+ fileInfo.fileName();
- checkDeploymentNeeded(DeployableFile(localFilePath, remoteDir));
+ collected.append(collectFilesToUpload(DeployableFile(localFilePath, remoteDir)));
}
- } else if (!d->incremental || hasChangedSinceLastDeployment(deployable)) {
- d->filesToUpload << deployable;
}
+ return collected;
}
void GenericDirectUploadService::setFinished()
{
d->state = Inactive;
- if (d->mkdirProc)
- disconnect(d->mkdirProc.data(), 0, this, 0);
- if (d->lnProc)
- disconnect(d->lnProc.data(), 0, this, 0);
+ if (d->runningProc)
+ disconnect(d->runningProc.data(), nullptr, this, nullptr);
if (d->uploader) {
- disconnect(d->uploader.data(), 0, this, 0);
+ disconnect(d->uploader.data(), nullptr, this, nullptr);
d->uploader->closeChannel();
}
+ clearRunningProc();
+ d->uploadJobRunning = false;
+ d->runningJobs.clear();
+ d->filesToUpload.clear();
}
void GenericDirectUploadService::uploadNextFile()
{
+ QTC_ASSERT(!d->uploadJobRunning, return);
+
if (d->filesToUpload.isEmpty()) {
- emit progressMessage(tr("All files successfully deployed."));
- setFinished();
- handleDeploymentDone();
+ tryFinish();
return;
}
- const DeployableFile &df = d->filesToUpload.first();
+ 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()));
- d->filesToUpload.takeFirst();
+ emit warningMessage(tr("Warning: No remote path set for local file \"%1\". "
+ "Skipping upload.").arg(df.localFilePath().toUserOutput()));
uploadNextFile();
return;
}
@@ -358,18 +454,44 @@ void GenericDirectUploadService::uploadNextFile()
dirToCreate += QLatin1Char('/') + fi.fileName();
const QString command = QLatin1String("mkdir -p ")
+ Utils::QtcProcess::quoteArgUnix(dirToCreate);
- d->mkdirProc = connection()->createRemoteProcess(command.toUtf8());
- connect(d->mkdirProc.data(), &SshRemoteProcess::closed,
+ QTC_CHECK(d->runningProc.isNull());
+ d->runningProc = connection()->createRemoteProcess(command.toUtf8());
+ connect(d->runningProc.data(), &SshRemoteProcess::closed,
this, &GenericDirectUploadService::handleMkdirFinished);
- connect(d->mkdirProc.data(), &SshRemoteProcess::readyReadStandardOutput,
+ connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardOutput,
this, &GenericDirectUploadService::handleStdOutData);
- connect(d->mkdirProc.data(), &SshRemoteProcess::readyReadStandardError,
+ connect(d->runningProc.data(), &SshRemoteProcess::readyReadStandardError,
this, &GenericDirectUploadService::handleStdErrData);
- connect(d->mkdirProc.data(), &SshRemoteProcess::readChannelFinished,
+ connect(d->runningProc.data(), &SshRemoteProcess::readChannelFinished,
this, &GenericDirectUploadService::handleReadChannelFinished);
emit progressMessage(tr("Uploading file \"%1\"...")
- .arg(df.localFilePath().toUserOutput()));
- d->mkdirProc->start();
+ .arg(df.localFilePath().toUserOutput()));
+ d->runningProcFile = df;
+ d->runningProc->start();
+ d->uploadJobRunning = true;
+}
+
+void GenericDirectUploadService::queryFiles()
+{
+ QTC_ASSERT(d->state == Uploading, return);
+
+ for (const DeployableFile &file : 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);
+ continue;
+ }
+
+ d->runningJobs.insert(jobId, { file, JobType::PreQuery, QDateTime() });
+ }
+
+ uploadNextFile();
}
} //namespace RemoteLinux
diff --git a/src/plugins/remotelinux/genericdirectuploadservice.h b/src/plugins/remotelinux/genericdirectuploadservice.h
index 6659619140..4f5dbb71b2 100644
--- a/src/plugins/remotelinux/genericdirectuploadservice.h
+++ b/src/plugins/remotelinux/genericdirectuploadservice.h
@@ -62,17 +62,25 @@ public:
private:
void handleSftpInitialized();
void handleSftpChannelError(const QString &errorMessage);
- void handleUploadFinished(QSsh::SftpJobId jobId, const QString &errorMsg);
+ 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 handleLnFinished(int exitStatus);
- void handleChmodFinished(int exitStatus);
void handleStdOutData();
void handleStdErrData();
void handleReadChannelFinished();
- void checkDeploymentNeeded(const ProjectExplorer::DeployableFile &file) const;
+ QList<ProjectExplorer::DeployableFile> collectFilesToUpload(
+ const ProjectExplorer::DeployableFile &file) const;
void setFinished();
void uploadNextFile();
+ void queryFiles();
+ void clearRunningProc();
+
+ void handleProcFailure();
+ void runPostQueryOnProcResult();
+
+ void tryFinish();
Internal::GenericDirectUploadServicePrivate * const d;
};
diff --git a/src/plugins/remotelinux/tarpackagecreationstep.cpp b/src/plugins/remotelinux/tarpackagecreationstep.cpp
index 2a2955d3f5..010b127a63 100644
--- a/src/plugins/remotelinux/tarpackagecreationstep.cpp
+++ b/src/plugins/remotelinux/tarpackagecreationstep.cpp
@@ -197,7 +197,7 @@ void TarPackageCreationStep::addNeededDeploymentFiles(
{
const QFileInfo fileInfo = deployable.localFilePath().toFileInfo();
if (!fileInfo.isDir()) {
- if (m_deployTimes.hasChangedSinceLastDeployment(deployable, kit))
+ if (m_deployTimes.hasLocalFileChanged(deployable, kit))
m_files << deployable;
return;
}
@@ -400,7 +400,7 @@ void TarPackageCreationStep::deployFinished(bool success)
// Store files that have been tar'd and successfully deployed
const auto files = m_files;
for (const DeployableFile &file : files)
- m_deployTimes.saveDeploymentTimeStamp(file, kit);
+ m_deployTimes.saveDeploymentTimeStamp(file, kit, QDateTime());
}
QString TarPackageCreationStep::packageFileName() const