From b3233035189cc323049b1f063c34daa0ae9feb22 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 14 Oct 2022 10:06:21 +0200 Subject: [PATCH] RemoteLinux: Fix deployment when building remotely By using a generic file transfer method based of FilePath::copyFile() that doesn't require either of the transfer end point to be the local host. Change-Id: Ia2e4273df52f5ce6533046d96be3f6b521b7f0a5 Reviewed-by: Christian Kandeler --- .../devicesupport/filetransfer.cpp | 16 +++-- .../devicesupport/filetransferinterface.h | 1 + src/plugins/remotelinux/linuxdevice.cpp | 61 +++++++++++++++++++ src/plugins/remotelinux/linuxdevicetester.cpp | 1 + .../remotelinuxdeployconfiguration.cpp | 10 ++- 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp index 54a135faf9e..bfbfdcf824c 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp @@ -98,12 +98,17 @@ void FileTransferPrivate::start() return startFailed(tr("No files to transfer.")); const FileTransferDirection direction = transferDirection(m_setup.m_files); - if (direction == FileTransferDirection::Invalid) - return startFailed(tr("Mixing different types of transfer in one go.")); - const IDeviceConstPtr device = matchedDevice(direction, m_setup.m_files); - if (!device) - return startFailed(tr("Trying to transfer into / from not matching device.")); + IDeviceConstPtr device; + if (direction != FileTransferDirection::Invalid) + device = matchedDevice(direction, m_setup.m_files); + + if (!device) { + // Fall back to generic copy. + const FilePath &filePath = m_setup.m_files.first().m_target; + device = DeviceManager::deviceForPath(filePath); + m_setup.m_method = FileTransferMethod::GenericCopy; + } run(m_setup, device); } @@ -190,6 +195,7 @@ QString FileTransfer::transferMethodName(FileTransferMethod method) switch (method) { case FileTransferMethod::Sftp: return FileTransfer::tr("sftp"); case FileTransferMethod::Rsync: return FileTransfer::tr("rsync"); + case FileTransferMethod::GenericCopy: return FileTransfer::tr("generic file copy"); } QTC_CHECK(false); return {}; diff --git a/src/plugins/projectexplorer/devicesupport/filetransferinterface.h b/src/plugins/projectexplorer/devicesupport/filetransferinterface.h index ad4ccc200ef..543e1ce6c29 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransferinterface.h +++ b/src/plugins/projectexplorer/devicesupport/filetransferinterface.h @@ -20,6 +20,7 @@ enum class FileTransferDirection { enum class FileTransferMethod { Sftp, Rsync, + GenericCopy, Default = Sftp }; diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 5f820126d95..6aee5591945 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1428,12 +1428,73 @@ private: int m_currentIndex = 0; }; +class GenericTransferImpl : public FileTransferInterface +{ +public: + GenericTransferImpl(const FileTransferSetupData &setup, LinuxDevicePrivate *) + : FileTransferInterface(setup) + {} + +private: + void start() final + { + m_fileCount = m_setup.m_files.size(); + m_currentIndex = 0; + m_checkedDirectories.clear(); + nextFile(); + } + + void nextFile() + { + ProcessResultData result; + if (m_currentIndex >= m_fileCount) { + emit done(result); + return; + } + + const FileToTransfer &file = m_setup.m_files.at(m_currentIndex); + const FilePath &source = file.m_source; + const FilePath &target = file.m_target; + ++m_currentIndex; + + const FilePath targetDir = target.parentDir(); + if (!m_checkedDirectories.contains(targetDir)) { + emit progress(tr("Creating directory: %1") + .arg(targetDir.toUserOutput())); + if (!targetDir.ensureWritableDir()) { + result.m_errorString = tr("Failed."); + result.m_exitCode = -1; // Random pick + emit done(result); + return; + } + m_checkedDirectories.insert(targetDir); + } + + emit progress(tr("Copying %1/%2: %3 -> %4") + .arg(m_currentIndex).arg(m_fileCount).arg(source.toUserOutput(), target.toUserOutput())); + if (!source.copyFile(target)) { + result.m_errorString = tr("Failed."); + result.m_exitCode = -1; // Random pick + emit done(result); + return; + } + + // FIXME: Use asyncCopyFile instead + nextFile(); + } + + int m_currentIndex = 0; + int m_fileCount = 0; + QSet m_checkedDirectories; +}; + FileTransferInterface *LinuxDevice::createFileTransferInterface( const FileTransferSetupData &setup) const { switch (setup.m_method) { case FileTransferMethod::Sftp: return new SftpTransferImpl(setup, d); case FileTransferMethod::Rsync: return new RsyncTransferImpl(setup, d); + case FileTransferMethod::GenericCopy: return new GenericTransferImpl(setup, d); } QTC_CHECK(false); return {}; diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 32875a54e28..e03b322bff3 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -236,6 +236,7 @@ void GenericLinuxDeviceTester::testFileTransfer(FileTransferMethod method) switch (method) { case FileTransferMethod::Sftp: d->state = TestingSftp; break; case FileTransferMethod::Rsync: d->state = TestingRsync; break; + case FileTransferMethod::GenericCopy: QTC_CHECK(false) /* not tested */; break; } emit progressMessage(Tr::tr("Checking whether \"%1\" works...") .arg(FileTransfer::transferMethodName(method))); diff --git a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp index 721107afebb..862925deb22 100644 --- a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp @@ -39,6 +39,9 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() addInitialStep(Constants::MakeInstallStepId, needsMakeInstall); addInitialStep(Constants::KillAppStepId); + + // Todo: Check: Instead of having two different steps here, have one + // and shift the logic into the implementation there? addInitialStep(Constants::RsyncDeployStepId, [](Target *target) { auto runDevice = DeviceKitAspect::device(target->kit()); auto buildDevice = BuildDeviceKitAspect::device(target->kit()); @@ -49,8 +52,11 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() return runDevice && runDevice->extraData(Constants::SupportsRSync).toBool(); }); addInitialStep(Constants::DirectUploadStepId, [](Target *target) { - auto device = DeviceKitAspect::device(target->kit()); - return device && !device->extraData(Constants::SupportsRSync).toBool(); + auto runDevice = DeviceKitAspect::device(target->kit()); + auto buildDevice = BuildDeviceKitAspect::device(target->kit()); + if (runDevice == buildDevice) + return true; + return runDevice && !runDevice->extraData(Constants::SupportsRSync).toBool(); }); }