RemoteLinux/Boot2Qt: Merge DeployStep and DeployService hierarchies

They were 1:1 now.

The change here is as small as possible, there are quite a few places
to clean up left.

Change-Id: I4f78d1de857b93d8372e2592a7723b02fe2fc947
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
hjk
2023-03-21 16:07:20 +01:00
parent 1bdc638e65
commit a4ed630c7d
11 changed files with 286 additions and 420 deletions

View File

@@ -22,12 +22,22 @@ using namespace Utils::Tasking;
namespace Qdb::Internal { namespace Qdb::Internal {
// QdbMakeDefaultAppService class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
class QdbMakeDefaultAppService : public RemoteLinux::AbstractRemoteLinuxDeployService
{ {
public: public:
void setMakeDefault(bool makeDefault) { m_makeDefault = makeDefault; } QdbMakeDefaultAppStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto selection = addAspect<SelectionAspect>();
selection->setSettingsKey("QdbMakeDefaultDeployStep.MakeDefault");
selection->addOption(Tr::tr("Set this application to start by default"));
selection->addOption(Tr::tr("Reset default application"));
setInternalInitializer([this, selection] {
m_makeDefault = selection->value() == 0;
return isDeploymentPossible();
});
}
private: private:
bool isDeploymentNecessary() const final { return true; } bool isDeploymentNecessary() const final { return true; }
@@ -66,30 +76,6 @@ private:
bool m_makeDefault = true; bool m_makeDefault = true;
}; };
// QdbMakeDefaultAppStep
class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
{
public:
QdbMakeDefaultAppStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new QdbMakeDefaultAppService;
setDeployService(service);
auto selection = addAspect<SelectionAspect>();
selection->setSettingsKey("QdbMakeDefaultDeployStep.MakeDefault");
selection->addOption(Tr::tr("Set this application to start by default"));
selection->addOption(Tr::tr("Reset default application"));
setInternalInitializer([service, selection] {
service->setMakeDefault(selection->value() == 0);
return service->isDeploymentPossible();
});
}
};
// QdbMakeDefaultAppStepFactory // QdbMakeDefaultAppStepFactory
QdbMakeDefaultAppStepFactory::QdbMakeDefaultAppStepFactory() QdbMakeDefaultAppStepFactory::QdbMakeDefaultAppStepFactory()

View File

@@ -21,16 +21,24 @@ using namespace Utils::Tasking;
namespace Qdb::Internal { namespace Qdb::Internal {
// QdbStopApplicationService // QdbStopApplicationStep
class QdbStopApplicationService : public RemoteLinux::AbstractRemoteLinuxDeployService class QdbStopApplicationStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
{ {
private: public:
QdbStopApplicationStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
setWidgetExpandedByDefault(false);
setInternalInitializer([this] { return isDeploymentPossible(); });
}
bool isDeploymentNecessary() const final { return true; } bool isDeploymentNecessary() const final { return true; }
Group deployRecipe() final; Group deployRecipe() final;
}; };
Group QdbStopApplicationService::deployRecipe() Group QdbStopApplicationStep::deployRecipe()
{ {
const auto setupHandler = [this](QtcProcess &process) { const auto setupHandler = [this](QtcProcess &process) {
const auto device = DeviceKitAspect::device(target()->kit()); const auto device = DeviceKitAspect::device(target()->kit());
@@ -67,24 +75,6 @@ Group QdbStopApplicationService::deployRecipe()
return Group { Process(setupHandler, doneHandler, errorHandler) }; return Group { Process(setupHandler, doneHandler, errorHandler) };
} }
// QdbStopApplicationStep
class QdbStopApplicationStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
{
public:
QdbStopApplicationStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new QdbStopApplicationService;
setDeployService(service);
setWidgetExpandedByDefault(false);
setInternalInitializer([service] { return service->isDeploymentPossible(); });
}
};
// QdbStopApplicationStepFactory // QdbStopApplicationStepFactory
QdbStopApplicationStepFactory::QdbStopApplicationStepFactory() QdbStopApplicationStepFactory::QdbStopApplicationStepFactory()

View File

@@ -24,137 +24,116 @@ using namespace Utils;
namespace RemoteLinux { namespace RemoteLinux {
namespace Internal { namespace Internal {
class AbstractRemoteLinuxDeployServicePrivate
{
public:
IDevice::ConstPtr deviceConfiguration;
QPointer<Target> target;
DeploymentTimeInfo deployTimes;
std::unique_ptr<TaskTree> m_taskTree;
};
class AbstractRemoteLinuxDeployStepPrivate class AbstractRemoteLinuxDeployStepPrivate
{ {
public: public:
bool hasError; bool hasError;
std::function<CheckResult()> internalInit; std::function<CheckResult()> internalInit;
std::function<void()> runPreparer; std::function<void()> runPreparer;
AbstractRemoteLinuxDeployService *deployService = nullptr;
DeploymentTimeInfo deployTimes;
std::unique_ptr<TaskTree> m_taskTree;
}; };
} // Internal } // Internal
using namespace Internal; using namespace Internal;
AbstractRemoteLinuxDeployService::AbstractRemoteLinuxDeployService(QObject *parent) AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Id id)
: QObject(parent), d(new AbstractRemoteLinuxDeployServicePrivate) : BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate)
{ {
connect(this, &AbstractRemoteLinuxDeployStep::errorMessage,
this, &AbstractRemoteLinuxDeployStep::handleErrorMessage);
connect(this, &AbstractRemoteLinuxDeployStep::progressMessage,
this, &AbstractRemoteLinuxDeployStep::handleProgressMessage);
connect(this, &AbstractRemoteLinuxDeployStep::warningMessage,
this, &AbstractRemoteLinuxDeployStep::handleWarningMessage);
connect(this, &AbstractRemoteLinuxDeployStep::stdOutData,
this, &AbstractRemoteLinuxDeployStep::handleStdOutData);
connect(this, &AbstractRemoteLinuxDeployStep::stdErrData,
this, &AbstractRemoteLinuxDeployStep::handleStdErrData);
} }
AbstractRemoteLinuxDeployService::~AbstractRemoteLinuxDeployService() AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep()
{ {
delete d; delete d;
} }
const Target *AbstractRemoteLinuxDeployService::target() const IDevice::ConstPtr AbstractRemoteLinuxDeployStep::deviceConfiguration() const
{ {
return d->target; return DeviceKitAspect::device(kit());
} }
const Kit *AbstractRemoteLinuxDeployService::kit() const void AbstractRemoteLinuxDeployStep::saveDeploymentTimeStamp(const DeployableFile &deployableFile,
{
return d->target ? d->target->kit() : nullptr;
}
IDevice::ConstPtr AbstractRemoteLinuxDeployService::deviceConfiguration() const
{
return d->deviceConfiguration;
}
void AbstractRemoteLinuxDeployService::saveDeploymentTimeStamp(const DeployableFile &deployableFile,
const QDateTime &remoteTimestamp) const QDateTime &remoteTimestamp)
{ {
d->deployTimes.saveDeploymentTimeStamp(deployableFile, kit(), remoteTimestamp); d->deployTimes.saveDeploymentTimeStamp(deployableFile, kit(), remoteTimestamp);
} }
bool AbstractRemoteLinuxDeployService::hasLocalFileChanged( bool AbstractRemoteLinuxDeployStep::hasLocalFileChanged(
const DeployableFile &deployableFile) const const DeployableFile &deployableFile) const
{ {
return d->deployTimes.hasLocalFileChanged(deployableFile, kit()); return d->deployTimes.hasLocalFileChanged(deployableFile, kit());
} }
bool AbstractRemoteLinuxDeployService::hasRemoteFileChanged( bool AbstractRemoteLinuxDeployStep::hasRemoteFileChanged(
const DeployableFile &deployableFile, const QDateTime &remoteTimestamp) const const DeployableFile &deployableFile, const QDateTime &remoteTimestamp) const
{ {
return d->deployTimes.hasRemoteFileChanged(deployableFile, kit(), remoteTimestamp); return d->deployTimes.hasRemoteFileChanged(deployableFile, kit(), remoteTimestamp);
} }
void AbstractRemoteLinuxDeployService::setTarget(Target *target) void AbstractRemoteLinuxDeployStep::start()
{
d->target = target;
d->deviceConfiguration = DeviceKitAspect::device(kit());
}
void AbstractRemoteLinuxDeployService::start()
{ {
QTC_ASSERT(!d->m_taskTree, return); QTC_ASSERT(!d->m_taskTree, return);
const CheckResult check = isDeploymentPossible(); const CheckResult check = isDeploymentPossible();
if (!check) { if (!check) {
emit errorMessage(check.errorMessage()); emit errorMessage(check.errorMessage());
emit finished(); handleFinished();
return; return;
} }
if (!isDeploymentNecessary()) { if (!isDeploymentNecessary()) {
emit progressMessage(Tr::tr("No deployment action necessary. Skipping.")); emit progressMessage(Tr::tr("No deployment action necessary. Skipping."));
emit finished(); handleFinished();
return; return;
} }
d->m_taskTree.reset(new TaskTree(deployRecipe())); d->m_taskTree.reset(new TaskTree(deployRecipe()));
const auto endHandler = [this] { const auto endHandler = [this] {
d->m_taskTree.release()->deleteLater(); d->m_taskTree.release()->deleteLater();
emit finished(); handleFinished();
}; };
connect(d->m_taskTree.get(), &TaskTree::done, this, endHandler); connect(d->m_taskTree.get(), &TaskTree::done, this, endHandler);
connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, endHandler); connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, endHandler);
d->m_taskTree->start(); d->m_taskTree->start();
} }
void AbstractRemoteLinuxDeployService::stop() void AbstractRemoteLinuxDeployStep::stop()
{ {
if (!d->m_taskTree) if (!d->m_taskTree)
return; return;
d->m_taskTree.reset(); d->m_taskTree.reset();
emit finished(); handleFinished();
} }
CheckResult AbstractRemoteLinuxDeployService::isDeploymentPossible() const CheckResult AbstractRemoteLinuxDeployStep::isDeploymentPossible() const
{ {
if (!deviceConfiguration()) if (!deviceConfiguration())
return CheckResult::failure(Tr::tr("No device configuration set.")); return CheckResult::failure(Tr::tr("No device configuration set."));
return CheckResult::success(); return CheckResult::success();
} }
QVariantMap AbstractRemoteLinuxDeployService::exportDeployTimes() const QVariantMap AbstractRemoteLinuxDeployStep::exportDeployTimes() const
{ {
return d->deployTimes.exportDeployTimes(); return d->deployTimes.exportDeployTimes();
} }
void AbstractRemoteLinuxDeployService::importDeployTimes(const QVariantMap &map) void AbstractRemoteLinuxDeployStep::importDeployTimes(const QVariantMap &map)
{ {
d->deployTimes.importDeployTimes(map); d->deployTimes.importDeployTimes(map);
} }
AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Utils::Id id)
: BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate)
{
}
void AbstractRemoteLinuxDeployStep::setInternalInitializer(const std::function<CheckResult ()> &init) void AbstractRemoteLinuxDeployStep::setInternalInitializer(const std::function<CheckResult ()> &init)
{ {
d->internalInit = init; d->internalInit = init;
@@ -165,36 +144,23 @@ void AbstractRemoteLinuxDeployStep::setRunPreparer(const std::function<void ()>
d->runPreparer = prep; d->runPreparer = prep;
} }
void AbstractRemoteLinuxDeployStep::setDeployService(AbstractRemoteLinuxDeployService *service)
{
d->deployService = service;
}
AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep()
{
delete d->deployService;
delete d;
}
bool AbstractRemoteLinuxDeployStep::fromMap(const QVariantMap &map) bool AbstractRemoteLinuxDeployStep::fromMap(const QVariantMap &map)
{ {
if (!BuildStep::fromMap(map)) if (!BuildStep::fromMap(map))
return false; return false;
d->deployService->importDeployTimes(map); importDeployTimes(map);
return true; return true;
} }
QVariantMap AbstractRemoteLinuxDeployStep::toMap() const QVariantMap AbstractRemoteLinuxDeployStep::toMap() const
{ {
QVariantMap map = BuildStep::toMap(); QVariantMap map = BuildStep::toMap();
map.insert(d->deployService->exportDeployTimes()); map.insert(exportDeployTimes());
return map; return map;
} }
bool AbstractRemoteLinuxDeployStep::init() bool AbstractRemoteLinuxDeployStep::init()
{ {
d->deployService->setTarget(target());
QTC_ASSERT(d->internalInit, return false); QTC_ASSERT(d->internalInit, return false);
const CheckResult canDeploy = d->internalInit(); const CheckResult canDeploy = d->internalInit();
if (!canDeploy) { if (!canDeploy) {
@@ -209,21 +175,8 @@ void AbstractRemoteLinuxDeployStep::doRun()
if (d->runPreparer) if (d->runPreparer)
d->runPreparer(); d->runPreparer();
connect(d->deployService, &AbstractRemoteLinuxDeployService::errorMessage,
this, &AbstractRemoteLinuxDeployStep::handleErrorMessage);
connect(d->deployService, &AbstractRemoteLinuxDeployService::progressMessage,
this, &AbstractRemoteLinuxDeployStep::handleProgressMessage);
connect(d->deployService, &AbstractRemoteLinuxDeployService::warningMessage,
this, &AbstractRemoteLinuxDeployStep::handleWarningMessage);
connect(d->deployService, &AbstractRemoteLinuxDeployService::stdOutData,
this, &AbstractRemoteLinuxDeployStep::handleStdOutData);
connect(d->deployService, &AbstractRemoteLinuxDeployService::stdErrData,
this, &AbstractRemoteLinuxDeployStep::handleStdErrData);
connect(d->deployService, &AbstractRemoteLinuxDeployService::finished,
this, &AbstractRemoteLinuxDeployStep::handleFinished);
d->hasError = false; d->hasError = false;
d->deployService->start(); start();
} }
void AbstractRemoteLinuxDeployStep::doCancel() void AbstractRemoteLinuxDeployStep::doCancel()
@@ -234,7 +187,7 @@ void AbstractRemoteLinuxDeployStep::doCancel()
emit addOutput(Tr::tr("User requests deployment to stop; cleaning up."), emit addOutput(Tr::tr("User requests deployment to stop; cleaning up."),
OutputFormat::NormalMessage); OutputFormat::NormalMessage);
d->hasError = true; d->hasError = true;
d->deployService->stop(); stop();
} }
void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message) void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message)
@@ -261,7 +214,6 @@ void AbstractRemoteLinuxDeployStep::handleFinished()
emit addOutput(Tr::tr("Deploy step failed."), OutputFormat::ErrorMessage); emit addOutput(Tr::tr("Deploy step failed."), OutputFormat::ErrorMessage);
else else
emit addOutput(Tr::tr("Deploy step finished."), OutputFormat::NormalMessage); emit addOutput(Tr::tr("Deploy step finished."), OutputFormat::NormalMessage);
disconnect(d->deployService, nullptr, this, nullptr);
emit finished(!d->hasError); emit finished(!d->hasError);
} }
@@ -275,4 +227,14 @@ void AbstractRemoteLinuxDeployStep::handleStdErrData(const QString &data)
emit addOutput(data, OutputFormat::Stderr, DontAppendNewline); emit addOutput(data, OutputFormat::Stderr, DontAppendNewline);
} }
bool AbstractRemoteLinuxDeployStep::isDeploymentNecessary() const
{
return true;
}
Tasking::Group AbstractRemoteLinuxDeployStep::deployRecipe()
{
return {};
}
} // namespace RemoteLinux } // namespace RemoteLinux

View File

@@ -21,42 +21,9 @@ namespace Utils::Tasking { class Group; }
namespace RemoteLinux { namespace RemoteLinux {
class AbstractRemoteLinuxDeployService;
class CheckResult; class CheckResult;
namespace Internal { class AbstractRemoteLinuxDeployStepPrivate; } namespace Internal { class AbstractRemoteLinuxDeployStepPrivate; }
namespace Internal { class AbstractRemoteLinuxDeployServicePrivate; }
class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep
{
Q_OBJECT
public:
~AbstractRemoteLinuxDeployStep() override;
protected:
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
bool init() override;
void doRun() final;
void doCancel() override;
explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
void setInternalInitializer(const std::function<CheckResult()> &init);
void setRunPreparer(const std::function<void()> &prep);
void setDeployService(AbstractRemoteLinuxDeployService *service);
private:
void handleProgressMessage(const QString &message);
void handleErrorMessage(const QString &message);
void handleWarningMessage(const QString &message);
void handleFinished();
void handleStdOutData(const QString &data);
void handleStdErrData(const QString &data);
Internal::AbstractRemoteLinuxDeployStepPrivate *d;
};
class REMOTELINUX_EXPORT CheckResult class REMOTELINUX_EXPORT CheckResult
{ {
@@ -74,21 +41,20 @@ private:
QString m_error; QString m_error;
}; };
class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployService : public QObject class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(AbstractRemoteLinuxDeployService)
public:
explicit AbstractRemoteLinuxDeployService(QObject *parent = nullptr);
~AbstractRemoteLinuxDeployService() override;
void setTarget(ProjectExplorer::Target *bc); public:
explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
~AbstractRemoteLinuxDeployStep() override;
void start(); void start();
void stop(); void stop();
QVariantMap exportDeployTimes() const; QVariantMap exportDeployTimes() const;
void importDeployTimes(const QVariantMap &map); void importDeployTimes(const QVariantMap &map);
ProjectExplorer::IDeviceConstPtr deviceConfiguration() const;
virtual CheckResult isDeploymentPossible() const; virtual CheckResult isDeploymentPossible() const;
@@ -98,12 +64,16 @@ signals:
void warningMessage(const QString &message); void warningMessage(const QString &message);
void stdOutData(const QString &data); void stdOutData(const QString &data);
void stdErrData(const QString &data); void stdErrData(const QString &data);
void finished(); // Used by Qnx.
protected: protected:
const ProjectExplorer::Target *target() const; bool fromMap(const QVariantMap &map) override;
const ProjectExplorer::Kit *kit() const; QVariantMap toMap() const override;
ProjectExplorer::IDeviceConstPtr deviceConfiguration() const; bool init() override;
void doRun() final;
void doCancel() override;
void setInternalInitializer(const std::function<CheckResult()> &init);
void setRunPreparer(const std::function<void()> &prep);
void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile, void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile,
const QDateTime &remoteTimestamp); const QDateTime &remoteTimestamp);
@@ -112,10 +82,17 @@ protected:
const QDateTime &remoteTimestamp) const; const QDateTime &remoteTimestamp) const;
private: private:
virtual bool isDeploymentNecessary() const = 0; void handleProgressMessage(const QString &message);
virtual Utils::Tasking::Group deployRecipe() = 0; void handleErrorMessage(const QString &message);
void handleWarningMessage(const QString &message);
void handleFinished();
void handleStdOutData(const QString &data);
void handleStdErrData(const QString &data);
Internal::AbstractRemoteLinuxDeployServicePrivate * const d; virtual bool isDeploymentNecessary() const;
virtual Utils::Tasking::Group deployRecipe();
Internal::AbstractRemoteLinuxDeployStepPrivate *d;
}; };
} // RemoteLinux } // RemoteLinux

View File

@@ -19,9 +19,26 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal { namespace RemoteLinux::Internal {
class CustomCommandDeployService : public AbstractRemoteLinuxDeployService class CustomCommandDeployStep : public AbstractRemoteLinuxDeployStep
{ {
public: public:
CustomCommandDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto commandLine = addAspect<StringAspect>();
commandLine->setSettingsKey("RemoteLinuxCustomCommandDeploymentStep.CommandLine");
commandLine->setLabelText(Tr::tr("Command line:"));
commandLine->setDisplayStyle(StringAspect::LineEditDisplay);
commandLine->setHistoryCompleter("RemoteLinuxCustomCommandDeploymentStep.History");
setInternalInitializer([this, commandLine] {
setCommandLine(commandLine->value().trimmed());
return isDeploymentPossible();
});
addMacroExpander();
}
void setCommandLine(const QString &commandLine); void setCommandLine(const QString &commandLine);
CheckResult isDeploymentPossible() const final; CheckResult isDeploymentPossible() const final;
@@ -34,20 +51,20 @@ private:
QString m_commandLine; QString m_commandLine;
}; };
void CustomCommandDeployService::setCommandLine(const QString &commandLine) void CustomCommandDeployStep::setCommandLine(const QString &commandLine)
{ {
m_commandLine = commandLine; m_commandLine = commandLine;
} }
CheckResult CustomCommandDeployService::isDeploymentPossible() const CheckResult CustomCommandDeployStep::isDeploymentPossible() const
{ {
if (m_commandLine.isEmpty()) if (m_commandLine.isEmpty())
return CheckResult::failure(Tr::tr("No command line given.")); return CheckResult::failure(Tr::tr("No command line given."));
return AbstractRemoteLinuxDeployService::isDeploymentPossible(); return AbstractRemoteLinuxDeployStep::isDeploymentPossible();
} }
Group CustomCommandDeployService::deployRecipe() Group CustomCommandDeployStep::deployRecipe()
{ {
const auto setupHandler = [this](QtcProcess &process) { const auto setupHandler = [this](QtcProcess &process) {
emit progressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine)); emit progressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine));
@@ -76,30 +93,6 @@ Group CustomCommandDeployService::deployRecipe()
return Group { Process(setupHandler, doneHandler, errorHandler) }; return Group { Process(setupHandler, doneHandler, errorHandler) };
} }
class CustomCommandDeployStep : public AbstractRemoteLinuxDeployStep
{
public:
CustomCommandDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new CustomCommandDeployService;
setDeployService(service);
auto commandLine = addAspect<StringAspect>();
commandLine->setSettingsKey("RemoteLinuxCustomCommandDeploymentStep.CommandLine");
commandLine->setLabelText(Tr::tr("Command line:"));
commandLine->setDisplayStyle(StringAspect::LineEditDisplay);
commandLine->setHistoryCompleter("RemoteLinuxCustomCommandDeploymentStep.History");
setInternalInitializer([service, commandLine] {
service->setCommandLine(commandLine->value().trimmed());
return service->isDeploymentPossible();
});
addMacroExpander();
}
};
// CustomCommandDeployStepFactory // CustomCommandDeployStepFactory

View File

@@ -25,7 +25,6 @@ using namespace Utils;
using namespace Utils::Tasking; using namespace Utils::Tasking;
namespace RemoteLinux { namespace RemoteLinux {
namespace Internal {
const int MaxConcurrentStatCalls = 10; const int MaxConcurrentStatCalls = 10;
@@ -36,21 +35,13 @@ struct UploadStorage
enum class IncrementalDeployment { Enabled, Disabled, NotSupported }; enum class IncrementalDeployment { Enabled, Disabled, NotSupported };
class GenericDirectUploadService : public AbstractRemoteLinuxDeployService class GenericDirectUploadStepPrivate
{ {
public: public:
GenericDirectUploadService(QObject *parent = nullptr) GenericDirectUploadStepPrivate(GenericDirectUploadStep *parent)
: AbstractRemoteLinuxDeployService(parent) : q(parent)
{} {}
void setDeployableFiles(const QList<ProjectExplorer::DeployableFile> &deployableFiles);
void setIncrementalDeployment(IncrementalDeployment incremental);
void setIgnoreMissingFiles(bool ignoreMissingFiles);
private:
bool isDeploymentNecessary() const final;
Utils::Tasking::Group deployRecipe() final;
QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc);
using FilesToStat = std::function<QList<DeployableFile>(UploadStorage *)>; using FilesToStat = std::function<QList<DeployableFile>(UploadStorage *)>;
@@ -64,6 +55,7 @@ private:
TaskItem chmodTask(const DeployableFile &file); TaskItem chmodTask(const DeployableFile &file);
TaskItem chmodTree(const TreeStorage<UploadStorage> &storage); TaskItem chmodTree(const TreeStorage<UploadStorage> &storage);
GenericDirectUploadStep *q;
IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported; IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported;
bool m_ignoreMissingFiles = false; bool m_ignoreMissingFiles = false;
mutable QList<DeployableFile> m_deployableFiles; mutable QList<DeployableFile> m_deployableFiles;
@@ -84,38 +76,19 @@ QList<DeployableFile> collectFilesToUpload(const DeployableFile &deployable)
return collected; return collected;
} }
} // namespace Internal bool GenericDirectUploadStep::isDeploymentNecessary() const
using namespace Internal;
void GenericDirectUploadService::setDeployableFiles(const QList<DeployableFile> &deployableFiles)
{
m_deployableFiles = deployableFiles;
}
void GenericDirectUploadService::setIncrementalDeployment(IncrementalDeployment incremental)
{
m_incremental = incremental;
}
void GenericDirectUploadService::setIgnoreMissingFiles(bool ignoreMissingFiles)
{
m_ignoreMissingFiles = ignoreMissingFiles;
}
bool GenericDirectUploadService::isDeploymentNecessary() const
{ {
QList<DeployableFile> collected; QList<DeployableFile> collected;
for (int i = 0; i < m_deployableFiles.count(); ++i) for (int i = 0; i < d->m_deployableFiles.count(); ++i)
collected.append(collectFilesToUpload(m_deployableFiles.at(i))); collected.append(collectFilesToUpload(d->m_deployableFiles.at(i)));
QTC_CHECK(collected.size() >= m_deployableFiles.size()); QTC_CHECK(collected.size() >= d->m_deployableFiles.size());
m_deployableFiles = collected; d->m_deployableFiles = collected;
return !m_deployableFiles.isEmpty(); return !d->m_deployableFiles.isEmpty();
} }
QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &file, QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile &file,
QtcProcess *statProc) QtcProcess *statProc)
{ {
bool succeeded = false; bool succeeded = false;
QString error; QString error;
@@ -130,7 +103,7 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi
succeeded = true; succeeded = true;
} }
if (!succeeded) { if (!succeeded) {
emit warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " emit q->warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". "
"Incremental deployment will not work. Error message was: %2") "Incremental deployment will not work. Error message was: %2")
.arg(file.remoteFilePath(), error)); .arg(file.remoteFilePath(), error));
return {}; return {};
@@ -139,30 +112,30 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi
const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2")
.arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); .arg(file.remoteFilePath()).arg(QString::fromUtf8(output)));
if (!output.startsWith(file.remoteFilePath().toUtf8())) { if (!output.startsWith(file.remoteFilePath().toUtf8())) {
emit warningMessage(warningString); emit q->warningMessage(warningString);
return {}; return {};
} }
const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' ');
if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns
emit warningMessage(warningString); emit q->warningMessage(warningString);
return {}; return {};
} }
bool isNumber; bool isNumber;
const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber);
if (!isNumber) { if (!isNumber) {
emit warningMessage(warningString); emit q->warningMessage(warningString);
return {}; return {};
} }
return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); return QDateTime::fromSecsSinceEpoch(secsSinceEpoch);
} }
TaskItem GenericDirectUploadService::statTask(UploadStorage *storage, TaskItem GenericDirectUploadStepPrivate::statTask(UploadStorage *storage,
const DeployableFile &file, const DeployableFile &file,
StatEndHandler statEndHandler) StatEndHandler statEndHandler)
{ {
const auto setupHandler = [=](QtcProcess &process) { const auto setupHandler = [=](QtcProcess &process) {
// We'd like to use --format=%Y, but it's not supported by busybox. // We'd like to use --format=%Y, but it's not supported by busybox.
process.setCommand({deviceConfiguration()->filePath("stat"), process.setCommand({q->deviceConfiguration()->filePath("stat"),
{"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}});
}; };
const auto endHandler = [=](const QtcProcess &process) { const auto endHandler = [=](const QtcProcess &process) {
@@ -173,8 +146,8 @@ TaskItem GenericDirectUploadService::statTask(UploadStorage *storage,
return Process(setupHandler, endHandler, endHandler); return Process(setupHandler, endHandler, endHandler);
} }
TaskItem GenericDirectUploadService::statTree(const TreeStorage<UploadStorage> &storage, TaskItem GenericDirectUploadStepPrivate::statTree(const TreeStorage<UploadStorage> &storage,
FilesToStat filesToStat, StatEndHandler statEndHandler) FilesToStat filesToStat, StatEndHandler statEndHandler)
{ {
const auto setupHandler = [=](TaskTree &tree) { const auto setupHandler = [=](TaskTree &tree) {
UploadStorage *storagePtr = storage.activeStorage(); UploadStorage *storagePtr = storage.activeStorage();
@@ -189,14 +162,14 @@ TaskItem GenericDirectUploadService::statTree(const TreeStorage<UploadStorage> &
return Tree(setupHandler); return Tree(setupHandler);
} }
TaskItem GenericDirectUploadService::uploadTask(const TreeStorage<UploadStorage> &storage) TaskItem GenericDirectUploadStepPrivate::uploadTask(const TreeStorage<UploadStorage> &storage)
{ {
const auto setupHandler = [this, storage](FileTransfer &transfer) { const auto setupHandler = [this, storage](FileTransfer &transfer) {
if (storage->filesToUpload.isEmpty()) { if (storage->filesToUpload.isEmpty()) {
emit progressMessage(Tr::tr("No files need to be uploaded.")); emit q->progressMessage(Tr::tr("No files need to be uploaded."));
return TaskAction::StopWithDone; return TaskAction::StopWithDone;
} }
emit progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", emit q->progressMessage(Tr::tr("%n file(s) need to be uploaded.", "",
storage->filesToUpload.size())); storage->filesToUpload.size()));
FilesToTransfer files; FilesToTransfer files;
for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { for (const DeployableFile &file : std::as_const(storage->filesToUpload)) {
@@ -204,51 +177,51 @@ TaskItem GenericDirectUploadService::uploadTask(const TreeStorage<UploadStorage>
const QString message = Tr::tr("Local file \"%1\" does not exist.") const QString message = Tr::tr("Local file \"%1\" does not exist.")
.arg(file.localFilePath().toUserOutput()); .arg(file.localFilePath().toUserOutput());
if (m_ignoreMissingFiles) { if (m_ignoreMissingFiles) {
emit warningMessage(message); emit q->warningMessage(message);
continue; continue;
} }
emit errorMessage(message); emit q->errorMessage(message);
return TaskAction::StopWithError; return TaskAction::StopWithError;
} }
files.append({file.localFilePath(), files.append({file.localFilePath(),
deviceConfiguration()->filePath(file.remoteFilePath())}); q->deviceConfiguration()->filePath(file.remoteFilePath())});
} }
if (files.isEmpty()) { if (files.isEmpty()) {
emit progressMessage(Tr::tr("No files need to be uploaded.")); emit q->progressMessage(Tr::tr("No files need to be uploaded."));
return TaskAction::StopWithDone; return TaskAction::StopWithDone;
} }
transfer.setFilesToTransfer(files); transfer.setFilesToTransfer(files);
QObject::connect(&transfer, &FileTransfer::progress, QObject::connect(&transfer, &FileTransfer::progress,
this, &GenericDirectUploadService::progressMessage); q, &GenericDirectUploadStep::progressMessage);
return TaskAction::Continue; return TaskAction::Continue;
}; };
const auto errorHandler = [this](const FileTransfer &transfer) { const auto errorHandler = [this](const FileTransfer &transfer) {
emit errorMessage(transfer.resultData().m_errorString); emit q->errorMessage(transfer.resultData().m_errorString);
}; };
return Transfer(setupHandler, {}, errorHandler); return Transfer(setupHandler, {}, errorHandler);
} }
TaskItem GenericDirectUploadService::chmodTask(const DeployableFile &file) TaskItem GenericDirectUploadStepPrivate::chmodTask(const DeployableFile &file)
{ {
const auto setupHandler = [=](QtcProcess &process) { const auto setupHandler = [=](QtcProcess &process) {
process.setCommand({deviceConfiguration()->filePath("chmod"), process.setCommand({q->deviceConfiguration()->filePath("chmod"),
{"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}});
}; };
const auto errorHandler = [=](const QtcProcess &process) { const auto errorHandler = [=](const QtcProcess &process) {
const QString error = process.errorString(); const QString error = process.errorString();
if (!error.isEmpty()) { if (!error.isEmpty()) {
emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2")
.arg(file.remoteFilePath(), error)); .arg(file.remoteFilePath(), error));
} else if (process.exitCode() != 0) { } else if (process.exitCode() != 0) {
emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2")
.arg(file.remoteFilePath(), process.cleanedStdErr())); .arg(file.remoteFilePath(), process.cleanedStdErr()));
} }
}; };
return Process(setupHandler, {}, errorHandler); return Process(setupHandler, {}, errorHandler);
} }
TaskItem GenericDirectUploadService::chmodTree(const TreeStorage<UploadStorage> &storage) TaskItem GenericDirectUploadStepPrivate::chmodTree(const TreeStorage<UploadStorage> &storage)
{ {
const auto setupChmodHandler = [=](TaskTree &tree) { const auto setupChmodHandler = [=](TaskTree &tree) {
QList<DeployableFile> filesToChmod; QList<DeployableFile> filesToChmod;
@@ -266,16 +239,16 @@ TaskItem GenericDirectUploadService::chmodTree(const TreeStorage<UploadStorage>
return Tree(setupChmodHandler); return Tree(setupChmodHandler);
} }
Group GenericDirectUploadService::deployRecipe() Group GenericDirectUploadStep::deployRecipe()
{ {
const auto preFilesToStat = [this](UploadStorage *storage) { const auto preFilesToStat = [this](UploadStorage *storage) {
QList<DeployableFile> filesToStat; QList<DeployableFile> filesToStat;
for (const DeployableFile &file : std::as_const(m_deployableFiles)) { for (const DeployableFile &file : std::as_const(d->m_deployableFiles)) {
if (m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { if (d->m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) {
storage->filesToUpload.append(file); storage->filesToUpload.append(file);
continue; continue;
} }
if (m_incremental == IncrementalDeployment::NotSupported) if (d->m_incremental == IncrementalDeployment::NotSupported)
continue; continue;
filesToStat << file; filesToStat << file;
} }
@@ -288,7 +261,7 @@ Group GenericDirectUploadService::deployRecipe()
}; };
const auto postFilesToStat = [this](UploadStorage *storage) { const auto postFilesToStat = [this](UploadStorage *storage) {
return m_incremental == IncrementalDeployment::NotSupported return d->m_incremental == IncrementalDeployment::NotSupported
? QList<DeployableFile>() : storage->filesToUpload; ? QList<DeployableFile>() : storage->filesToUpload;
}; };
const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file,
@@ -304,11 +277,11 @@ Group GenericDirectUploadService::deployRecipe()
const TreeStorage<UploadStorage> storage; const TreeStorage<UploadStorage> storage;
const Group root { const Group root {
Storage(storage), Storage(storage),
statTree(storage, preFilesToStat, preStatEndHandler), d->statTree(storage, preFilesToStat, preStatEndHandler),
uploadTask(storage), d->uploadTask(storage),
Group { Group {
chmodTree(storage), d->chmodTree(storage),
statTree(storage, postFilesToStat, postStatEndHandler) d->statTree(storage, postFilesToStat, postStatEndHandler)
}, },
OnGroupDone(doneHandler) OnGroupDone(doneHandler)
}; };
@@ -317,11 +290,9 @@ Group GenericDirectUploadService::deployRecipe()
GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id, GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id,
bool offerIncrementalDeployment) bool offerIncrementalDeployment)
: AbstractRemoteLinuxDeployStep(bsl, id) : AbstractRemoteLinuxDeployStep(bsl, id),
d(new GenericDirectUploadStepPrivate(this))
{ {
auto service = new GenericDirectUploadService;
setDeployService(service);
BoolAspect *incremental = nullptr; BoolAspect *incremental = nullptr;
if (offerIncrementalDeployment) { if (offerIncrementalDeployment) {
incremental = addAspect<BoolAspect>(); incremental = addAspect<BoolAspect>();
@@ -338,23 +309,26 @@ GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id i
BoolAspect::LabelPlacement::AtCheckBox); BoolAspect::LabelPlacement::AtCheckBox);
ignoreMissingFiles->setValue(false); ignoreMissingFiles->setValue(false);
setInternalInitializer([incremental, ignoreMissingFiles, service] { setInternalInitializer([this, incremental, ignoreMissingFiles] {
if (incremental) { if (incremental) {
service->setIncrementalDeployment(incremental->value() d->m_incremental = incremental->value()
? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled); ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled;
} else { } else {
service->setIncrementalDeployment(IncrementalDeployment::NotSupported); d->m_incremental = IncrementalDeployment::NotSupported;
} }
service->setIgnoreMissingFiles(ignoreMissingFiles->value()); d->m_ignoreMissingFiles = ignoreMissingFiles->value();
return service->isDeploymentPossible(); return isDeploymentPossible();
}); });
setRunPreparer([this, service] { setRunPreparer([this] {
service->setDeployableFiles(target()->deploymentData().allFiles()); d->m_deployableFiles = target()->deploymentData().allFiles();
}); });
} }
GenericDirectUploadStep::~GenericDirectUploadStep() = default; GenericDirectUploadStep::~GenericDirectUploadStep()
{
delete d;
}
Utils::Id GenericDirectUploadStep::stepId() Utils::Id GenericDirectUploadStep::stepId()
{ {

View File

@@ -18,8 +18,14 @@ public:
bool offerIncrementalDeployment = true); bool offerIncrementalDeployment = true);
~GenericDirectUploadStep() override; ~GenericDirectUploadStep() override;
bool isDeploymentNecessary() const final;
Utils::Tasking::Group deployRecipe() final;
static Utils::Id stepId(); static Utils::Id stepId();
static QString displayName(); static QString displayName();
private:
class GenericDirectUploadStepPrivate *d;
}; };
} //namespace RemoteLinux } // RemoteLinux

View File

@@ -20,10 +20,21 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal { namespace RemoteLinux::Internal {
class KillAppService : public AbstractRemoteLinuxDeployService class KillAppStep : public AbstractRemoteLinuxDeployStep
{ {
public: public:
void setRemoteExecutable(const FilePath &filePath) { m_remoteExecutable = filePath; } KillAppStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id)
{
setWidgetExpandedByDefault(false);
setInternalInitializer([this] {
Target * const theTarget = target();
QTC_ASSERT(theTarget, return CheckResult::failure());
RunConfiguration * const rc = theTarget->activeRunConfiguration();
m_remoteExecutable = rc ? rc->runnable().command.executable() : FilePath();
return CheckResult::success();
});
}
private: private:
bool isDeploymentNecessary() const final { return !m_remoteExecutable.isEmpty(); } bool isDeploymentNecessary() const final { return !m_remoteExecutable.isEmpty(); }
@@ -32,7 +43,7 @@ private:
FilePath m_remoteExecutable; FilePath m_remoteExecutable;
}; };
Group KillAppService::deployRecipe() Group KillAppStep::deployRecipe()
{ {
const auto setupHandler = [this](DeviceProcessKiller &killer) { const auto setupHandler = [this](DeviceProcessKiller &killer) {
killer.setProcessPath(m_remoteExecutable); killer.setProcessPath(m_remoteExecutable);
@@ -49,27 +60,6 @@ Group KillAppService::deployRecipe()
return Group { Killer(setupHandler, doneHandler, errorHandler) }; return Group { Killer(setupHandler, doneHandler, errorHandler) };
} }
class KillAppStep : public AbstractRemoteLinuxDeployStep
{
public:
KillAppStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new Internal::KillAppService;
setDeployService(service);
setWidgetExpandedByDefault(false);
setInternalInitializer([this, service] {
Target * const theTarget = target();
QTC_ASSERT(theTarget, return CheckResult::failure());
RunConfiguration * const rc = theTarget->activeRunConfiguration();
const FilePath remoteExe = rc ? rc->runnable().command.executable() : FilePath();
service->setRemoteExecutable(remoteExe);
return CheckResult::success();
});
}
};
KillAppStepFactory::KillAppStepFactory() KillAppStepFactory::KillAppStepFactory()
{ {
registerStep<KillAppStep>(Constants::KillAppStepId); registerStep<KillAppStep>(Constants::KillAppStepId);

View File

@@ -25,39 +25,57 @@ using namespace Utils::Tasking;
namespace RemoteLinux { namespace RemoteLinux {
class RsyncDeployService : public AbstractRemoteLinuxDeployService // RsyncDeployStep
RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{ {
public: auto flags = addAspect<StringAspect>();
void setDeployableFiles(const QList<DeployableFile> &files); flags->setDisplayStyle(StringAspect::LineEditDisplay);
void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; } flags->setSettingsKey("RemoteLinux.RsyncDeployStep.Flags");
void setFlags(const QString &flags) { m_flags = flags; } flags->setLabelText(Tr::tr("Flags:"));
flags->setValue(FileTransferSetupData::defaultRsyncFlags());
private: auto ignoreMissingFiles = addAspect<BoolAspect>();
bool isDeploymentNecessary() const final; ignoreMissingFiles->setSettingsKey("RemoteLinux.RsyncDeployStep.IgnoreMissingFiles");
Group deployRecipe() final; ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files:"),
TaskItem mkdirTask(); BoolAspect::LabelPlacement::InExtraLabel);
TaskItem transferTask(); ignoreMissingFiles->setValue(false);
mutable FilesToTransfer m_files; setInternalInitializer([this, ignoreMissingFiles, flags] {
bool m_ignoreMissingFiles = false; if (BuildDeviceKitAspect::device(kit()) == DeviceKitAspect::device(kit())) {
QString m_flags; // rsync transfer on the same device currently not implemented
}; // and typically not wanted.
return CheckResult::failure(
Tr::tr("rsync is only supported for transfers between different devices."));
}
setIgnoreMissingFiles(ignoreMissingFiles->value());
setFlags(flags->value());
return isDeploymentPossible();
});
void RsyncDeployService::setDeployableFiles(const QList<DeployableFile> &files) setRunPreparer([this] {
setDeployableFiles(target()->deploymentData().allFiles());
});
}
RsyncDeployStep::~RsyncDeployStep() = default;
void RsyncDeployStep::setDeployableFiles(const QList<DeployableFile> &files)
{ {
m_files.clear(); m_files.clear();
for (const DeployableFile &f : files) for (const DeployableFile &f : files)
m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())}); m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())});
} }
bool RsyncDeployService::isDeploymentNecessary() const bool RsyncDeployStep::isDeploymentNecessary() const
{ {
if (m_ignoreMissingFiles) if (m_ignoreMissingFiles)
Utils::erase(m_files, [](const FileToTransfer &file) { return !file.m_source.exists(); }); Utils::erase(m_files, [](const FileToTransfer &file) { return !file.m_source.exists(); });
return !m_files.empty(); return !m_files.empty();
} }
TaskItem RsyncDeployService::mkdirTask() TaskItem RsyncDeployStep::mkdirTask()
{ {
const auto setupHandler = [this](QtcProcess &process) { const auto setupHandler = [this](QtcProcess &process) {
QStringList remoteDirs; QStringList remoteDirs;
@@ -85,14 +103,14 @@ TaskItem RsyncDeployService::mkdirTask()
return Process(setupHandler, {}, errorHandler); return Process(setupHandler, {}, errorHandler);
} }
TaskItem RsyncDeployService::transferTask() TaskItem RsyncDeployStep::transferTask()
{ {
const auto setupHandler = [this](FileTransfer &transfer) { const auto setupHandler = [this](FileTransfer &transfer) {
transfer.setTransferMethod(FileTransferMethod::Rsync); transfer.setTransferMethod(FileTransferMethod::Rsync);
transfer.setRsyncFlags(m_flags); transfer.setRsyncFlags(m_flags);
transfer.setFilesToTransfer(m_files); transfer.setFilesToTransfer(m_files);
connect(&transfer, &FileTransfer::progress, connect(&transfer, &FileTransfer::progress,
this, &AbstractRemoteLinuxDeployService::stdOutData); this, &AbstractRemoteLinuxDeployStep::stdOutData);
}; };
const auto errorHandler = [this](const FileTransfer &transfer) { const auto errorHandler = [this](const FileTransfer &transfer) {
const ProcessResultData result = transfer.resultData(); const ProcessResultData result = transfer.resultData();
@@ -108,50 +126,11 @@ TaskItem RsyncDeployService::transferTask()
return Transfer(setupHandler, {}, errorHandler); return Transfer(setupHandler, {}, errorHandler);
} }
Group RsyncDeployService::deployRecipe() Group RsyncDeployStep::deployRecipe()
{ {
return Group { mkdirTask(), transferTask() }; return Group { mkdirTask(), transferTask() };
} }
// RsyncDeployStep
RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new RsyncDeployService;
setDeployService(service);
auto flags = addAspect<StringAspect>();
flags->setDisplayStyle(StringAspect::LineEditDisplay);
flags->setSettingsKey("RemoteLinux.RsyncDeployStep.Flags");
flags->setLabelText(Tr::tr("Flags:"));
flags->setValue(FileTransferSetupData::defaultRsyncFlags());
auto ignoreMissingFiles = addAspect<BoolAspect>();
ignoreMissingFiles->setSettingsKey("RemoteLinux.RsyncDeployStep.IgnoreMissingFiles");
ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files:"),
BoolAspect::LabelPlacement::InExtraLabel);
ignoreMissingFiles->setValue(false);
setInternalInitializer([this, service, flags, ignoreMissingFiles] {
if (BuildDeviceKitAspect::device(kit()) == DeviceKitAspect::device(kit())) {
// rsync transfer on the same device currently not implemented
// and typically not wanted.
return CheckResult::failure(
Tr::tr("rsync is only supported for transfers between different devices."));
}
service->setIgnoreMissingFiles(ignoreMissingFiles->value());
service->setFlags(flags->value());
return service->isDeploymentPossible();
});
setRunPreparer([this, service] {
service->setDeployableFiles(target()->deploymentData().allFiles());
});
}
RsyncDeployStep::~RsyncDeployStep() = default;
Utils::Id RsyncDeployStep::stepId() Utils::Id RsyncDeployStep::stepId()
{ {
return Constants::RsyncDeployStepId; return Constants::RsyncDeployStepId;

View File

@@ -7,6 +7,10 @@
#include "abstractremotelinuxdeploystep.h" #include "abstractremotelinuxdeploystep.h"
#include <projectexplorer/devicesupport/filetransfer.h>
#include <utils/tasktree.h>
namespace RemoteLinux { namespace RemoteLinux {
class REMOTELINUX_EXPORT RsyncDeployStep : public AbstractRemoteLinuxDeployStep class REMOTELINUX_EXPORT RsyncDeployStep : public AbstractRemoteLinuxDeployStep
@@ -17,6 +21,20 @@ public:
static Utils::Id stepId(); static Utils::Id stepId();
static QString displayName(); static QString displayName();
void setDeployableFiles(const QList<ProjectExplorer::DeployableFile> &files);
void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; }
void setFlags(const QString &flags) { m_flags = flags; }
private:
bool isDeploymentNecessary() const final;
Utils::Tasking::Group deployRecipe() final;
Utils::Tasking::TaskItem mkdirTask();
Utils::Tasking::TaskItem transferTask();
mutable ProjectExplorer::FilesToTransfer m_files;
bool m_ignoreMissingFiles = false;
QString m_flags;
}; };
} // namespace RemoteLinux } // namespace RemoteLinux

View File

@@ -21,9 +21,36 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal { namespace RemoteLinux::Internal {
class TarPackageDeployService : public AbstractRemoteLinuxDeployService // TarPackageDeployStep
class TarPackageDeployStep : public AbstractRemoteLinuxDeployStep
{ {
public: public:
TarPackageDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
setWidgetExpandedByDefault(false);
setInternalInitializer([this] {
const BuildStep *tarCreationStep = nullptr;
for (BuildStep *step : deployConfiguration()->stepList()->steps()) {
if (step == this)
break;
if (step->id() == Constants::TarPackageCreationStepId) {
tarCreationStep = step;
break;
}
}
if (!tarCreationStep)
return CheckResult::failure(Tr::tr("No tarball creation step found."));
const FilePath tarFile =
FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId));
setPackageFilePath(tarFile);
return isDeploymentPossible();
});
}
void setPackageFilePath(const FilePath &filePath); void setPackageFilePath(const FilePath &filePath);
private: private:
@@ -36,29 +63,28 @@ private:
FilePath m_packageFilePath; FilePath m_packageFilePath;
}; };
void TarPackageDeployService::setPackageFilePath(const FilePath &filePath) void TarPackageDeployStep::setPackageFilePath(const FilePath &filePath)
{ {
m_packageFilePath = filePath; m_packageFilePath = filePath;
} }
QString TarPackageDeployService::remoteFilePath() const QString TarPackageDeployStep::remoteFilePath() const
{ {
return QLatin1String("/tmp/") + m_packageFilePath.fileName(); return QLatin1String("/tmp/") + m_packageFilePath.fileName();
} }
bool TarPackageDeployService::isDeploymentNecessary() const bool TarPackageDeployStep::isDeploymentNecessary() const
{ {
return hasLocalFileChanged(DeployableFile(m_packageFilePath, {})); return hasLocalFileChanged(DeployableFile(m_packageFilePath, {}));
} }
TaskItem TarPackageDeployService::uploadTask() TaskItem TarPackageDeployStep::uploadTask()
{ {
const auto setupHandler = [this](FileTransfer &transfer) { const auto setupHandler = [this](FileTransfer &transfer) {
const FilesToTransfer files {{m_packageFilePath, const FilesToTransfer files {{m_packageFilePath,
deviceConfiguration()->filePath(remoteFilePath())}}; deviceConfiguration()->filePath(remoteFilePath())}};
transfer.setFilesToTransfer(files); transfer.setFilesToTransfer(files);
connect(&transfer, &FileTransfer::progress, connect(&transfer, &FileTransfer::progress, this, &TarPackageDeployStep::progressMessage);
this, &TarPackageDeployService::progressMessage);
emit progressMessage(Tr::tr("Uploading package to device...")); emit progressMessage(Tr::tr("Uploading package to device..."));
}; };
const auto doneHandler = [this](const FileTransfer &) { const auto doneHandler = [this](const FileTransfer &) {
@@ -71,7 +97,7 @@ TaskItem TarPackageDeployService::uploadTask()
return Transfer(setupHandler, doneHandler, errorHandler); return Transfer(setupHandler, doneHandler, errorHandler);
} }
TaskItem TarPackageDeployService::installTask() TaskItem TarPackageDeployStep::installTask()
{ {
const auto setupHandler = [this](QtcProcess &process) { const auto setupHandler = [this](QtcProcess &process) {
const QString cmdLine = QLatin1String("cd / && tar xvf ") + remoteFilePath() const QString cmdLine = QLatin1String("cd / && tar xvf ") + remoteFilePath()
@@ -96,46 +122,11 @@ TaskItem TarPackageDeployService::installTask()
return Process(setupHandler, doneHandler, errorHandler); return Process(setupHandler, doneHandler, errorHandler);
} }
Group TarPackageDeployService::deployRecipe() Group TarPackageDeployStep::deployRecipe()
{ {
return Group { uploadTask(), installTask() }; return Group { uploadTask(), installTask() };
} }
// TarPackageDeployStep
class TarPackageDeployStep : public AbstractRemoteLinuxDeployStep
{
public:
TarPackageDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
auto service = new TarPackageDeployService;
setDeployService(service);
setWidgetExpandedByDefault(false);
setInternalInitializer([this, service] {
const BuildStep *tarCreationStep = nullptr;
for (BuildStep *step : deployConfiguration()->stepList()->steps()) {
if (step == this)
break;
if (step->id() == Constants::TarPackageCreationStepId) {
tarCreationStep = step;
break;
}
}
if (!tarCreationStep)
return CheckResult::failure(Tr::tr("No tarball creation step found."));
const FilePath tarFile =
FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId));
service->setPackageFilePath(tarFile);
return service->isDeploymentPossible();
});
}
};
// TarPackageDeployStepFactory // TarPackageDeployStepFactory