From 9198aa23f2ebc156daea3f20a132697a2ce5da45 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 13 Jul 2011 12:57:04 +0200 Subject: [PATCH] RemoteLinux: Improve handling of symbolic links when deploying. We used to follow the links, resulting in unnecessary traffic. Now we just recreate the links. Note: This requires the user to not have dependencies that resolve to something outside the set of files to deploy. Change-Id: I3f439739115b4d07b36a71fe2041d8725a25abfd Reviewed-on: http://codereview.qt.nokia.com/1582 Reviewed-by: Christian Kandeler --- src/libs/utils/ssh/sftpoutgoingpacket_p.h | 3 + .../genericdirectuploadservice.cpp | 78 +++++++++++++++---- .../remotelinux/genericdirectuploadservice.h | 3 + .../remotelinux/maemoremotecopyfacility.cpp | 2 +- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/libs/utils/ssh/sftpoutgoingpacket_p.h b/src/libs/utils/ssh/sftpoutgoingpacket_p.h index da76aaee945..6ec48c2068c 100644 --- a/src/libs/utils/ssh/sftpoutgoingpacket_p.h +++ b/src/libs/utils/ssh/sftpoutgoingpacket_p.h @@ -64,6 +64,9 @@ public: quint32 requestId); SftpOutgoingPacket &generateWriteFile(const QByteArray &handle, quint64 offset, const QByteArray &data, quint32 requestId); + + // Note: OpenSSH's SFTP server has a bug that reverses the filePath and target + // arguments, so this operation is not portable. SftpOutgoingPacket &generateCreateLink(const QString &filePath, const QString &target, quint32 requestId); diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp index 4f741b001cc..3555a526e34 100644 --- a/src/plugins/remotelinux/genericdirectuploadservice.cpp +++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp @@ -61,6 +61,7 @@ public: QList filesToUpload; SftpChannel::Ptr uploader; SshRemoteProcess::Ptr mkdirProc; + SshRemoteProcess::Ptr lnProc; QList deployableFiles; }; @@ -161,6 +162,28 @@ void GenericDirectUploadService::handleUploadFinished(Utils::SftpJobId jobId, co } } +void GenericDirectUploadService::handleLnFinished(int exitStatus) +{ + QTC_ASSERT(m_d->state == Uploading, setFinished(); return); + + if (m_d->stopRequested) { + setFinished(); + handleDeploymentDone(); + } + + const DeployableFile d = m_d->filesToUpload.takeFirst(); + const QString nativePath = QDir::toNativeSeparators(d.localFilePath); + if (exitStatus != SshRemoteProcess::ExitedNormally || m_d->lnProc->exitCode() != 0) { + emit errorMessage(tr("Failed to upload file '%1'.").arg(nativePath)); + setFinished(); + handleDeploymentDone(); + return; + } else { + saveDeploymentTimeStamp(d); + uploadNextFile(); + } +} + void GenericDirectUploadService::handleMkdirFinished(int exitStatus) { QTC_ASSERT(m_d->state == Uploading, setFinished(); return); @@ -182,18 +205,43 @@ void GenericDirectUploadService::handleMkdirFinished(int exitStatus) m_d->filesToUpload.removeFirst(); uploadNextFile(); } else { - const SftpJobId job = m_d->uploader->uploadFile(d.localFilePath, - d.remoteDir + QLatin1Char('/') + fi.fileName(), - SftpOverwriteExisting); - if (job == SftpInvalidJob) { - emit errorMessage(tr("Failed to upload file '%1': " - "Could not open for reading.").arg(nativePath)); - setFinished(); - handleDeploymentDone(); + const QString remoteFilePath = d.remoteDir + QLatin1Char('/') + fi.fileName(); + if (fi.isSymLink()) { + const QString target = fi.dir().relativeFilePath(fi.symLinkTarget()); // see QTBUG-5817. + const QString command = QLatin1String("ln -vsf ") + target + QLatin1Char(' ') + + remoteFilePath; + + // See comment in SftpChannel::createLink as to why we can't use it. + m_d->lnProc = connection()->createRemoteProcess(command.toUtf8()); + connect(m_d->lnProc.data(), SIGNAL(closed(int)), SLOT(handleLnFinished(int))); + connect(m_d->lnProc.data(), SIGNAL(outputAvailable(QByteArray)), + SLOT(handleStdOutData(QByteArray))); + connect(m_d->lnProc.data(), SIGNAL(errorOutputAvailable(QByteArray)), + SLOT(handleStdErrData(QByteArray))); + m_d->lnProc->start(); + } else { + const SftpJobId job = m_d->uploader->uploadFile(d.localFilePath, remoteFilePath, + SftpOverwriteExisting); + if (job == SftpInvalidJob) { + emit errorMessage(tr("Failed to upload file '%1': " + "Could not open for reading.").arg(nativePath)); + setFinished(); + handleDeploymentDone(); + } } } } +void GenericDirectUploadService::handleStdOutData(const QByteArray &data) +{ + emit stdOutData(QString::fromUtf8(data)); +} + +void GenericDirectUploadService::handleStdErrData(const QByteArray &data) +{ + emit stdErrData(QString::fromUtf8(data)); +} + void GenericDirectUploadService::stopDeployment() { QTC_ASSERT(m_d->state == InitializingSftp || m_d->state == Uploading, setFinished(); return); @@ -226,9 +274,10 @@ void GenericDirectUploadService::setFinished() { m_d->stopRequested = false; m_d->state = Inactive; - if (m_d->mkdirProc) { + if (m_d->mkdirProc) disconnect(m_d->mkdirProc.data(), 0, this, 0); - } + if (m_d->lnProc) + disconnect(m_d->lnProc.data(), 0, this, 0); if (m_d->uploader) { disconnect(m_d->uploader.data(), 0, this, 0); m_d->uploader->closeChannel(); @@ -249,10 +298,13 @@ void GenericDirectUploadService::uploadNextFile() QFileInfo fi(d.localFilePath); if (fi.isDir()) dirToCreate += QLatin1Char('/') + fi.fileName(); - const QByteArray command = "mkdir -p " + dirToCreate.toUtf8(); - m_d->mkdirProc = connection()->createRemoteProcess(command); + const QString command = QLatin1String("mkdir -vp ") + dirToCreate; + m_d->mkdirProc = connection()->createRemoteProcess(command.toUtf8()); connect(m_d->mkdirProc.data(), SIGNAL(closed(int)), SLOT(handleMkdirFinished(int))); - // TODO: Connect stderr. + connect(m_d->mkdirProc.data(), SIGNAL(outputAvailable(QByteArray)), + SLOT(handleStdOutData(QByteArray))); + connect(m_d->mkdirProc.data(), SIGNAL(errorOutputAvailable(QByteArray)), + SLOT(handleStdErrData(QByteArray))); emit progressMessage(tr("Uploading file '%1'...") .arg(QDir::toNativeSeparators(d.localFilePath))); m_d->mkdirProc->start(); diff --git a/src/plugins/remotelinux/genericdirectuploadservice.h b/src/plugins/remotelinux/genericdirectuploadservice.h index c13451923f6..5e6c458cfbd 100644 --- a/src/plugins/remotelinux/genericdirectuploadservice.h +++ b/src/plugins/remotelinux/genericdirectuploadservice.h @@ -58,6 +58,9 @@ private slots: void handleSftpInitializationFailed(const QString &errorMessage); void handleUploadFinished(Utils::SftpJobId jobId, const QString &errorMsg); void handleMkdirFinished(int exitStatus); + void handleLnFinished(int exitStatus); + void handleStdOutData(const QByteArray &data); + void handleStdErrData(const QByteArray &data); private: bool isDeploymentNecessary() const; diff --git a/src/plugins/remotelinux/maemoremotecopyfacility.cpp b/src/plugins/remotelinux/maemoremotecopyfacility.cpp index abab92e9398..521ad96e2f4 100644 --- a/src/plugins/remotelinux/maemoremotecopyfacility.cpp +++ b/src/plugins/remotelinux/maemoremotecopyfacility.cpp @@ -138,7 +138,7 @@ void MaemoRemoteCopyFacility::copyNextFile() sourceFilePath += d.localFilePath; #endif - QString command = QString::fromLatin1("%1 mkdir -p %3 && %1 cp -r %2 %3") + QString command = QString::fromLatin1("%1 mkdir -p %3 && %1 cp -a %2 %3") .arg(MaemoGlobal::remoteSudo(m_devConf->osType(), m_copyRunner->connection()->connectionParameters().userName), sourceFilePath, d.remoteDir);