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 {
// QdbMakeDefaultAppService
class QdbMakeDefaultAppService : public RemoteLinux::AbstractRemoteLinuxDeployService
class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep
{
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:
bool isDeploymentNecessary() const final { return true; }
@@ -66,30 +76,6 @@ private:
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()

View File

@@ -21,16 +21,24 @@ using namespace Utils::Tasking;
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; }
Group deployRecipe() final;
};
Group QdbStopApplicationService::deployRecipe()
Group QdbStopApplicationStep::deployRecipe()
{
const auto setupHandler = [this](QtcProcess &process) {
const auto device = DeviceKitAspect::device(target()->kit());
@@ -67,24 +75,6 @@ Group QdbStopApplicationService::deployRecipe()
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()

View File

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

View File

@@ -21,42 +21,9 @@ namespace Utils::Tasking { class Group; }
namespace RemoteLinux {
class AbstractRemoteLinuxDeployService;
class CheckResult;
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
{
@@ -74,21 +41,20 @@ private:
QString m_error;
};
class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployService : public QObject
class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep
{
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 stop();
QVariantMap exportDeployTimes() const;
void importDeployTimes(const QVariantMap &map);
ProjectExplorer::IDeviceConstPtr deviceConfiguration() const;
virtual CheckResult isDeploymentPossible() const;
@@ -98,12 +64,16 @@ signals:
void warningMessage(const QString &message);
void stdOutData(const QString &data);
void stdErrData(const QString &data);
void finished(); // Used by Qnx.
protected:
const ProjectExplorer::Target *target() const;
const ProjectExplorer::Kit *kit() const;
ProjectExplorer::IDeviceConstPtr deviceConfiguration() const;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
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,
const QDateTime &remoteTimestamp);
@@ -112,10 +82,17 @@ protected:
const QDateTime &remoteTimestamp) const;
private:
virtual bool isDeploymentNecessary() const = 0;
virtual Utils::Tasking::Group deployRecipe() = 0;
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::AbstractRemoteLinuxDeployServicePrivate * const d;
virtual bool isDeploymentNecessary() const;
virtual Utils::Tasking::Group deployRecipe();
Internal::AbstractRemoteLinuxDeployStepPrivate *d;
};
} // RemoteLinux

View File

@@ -19,9 +19,26 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal {
class CustomCommandDeployService : public AbstractRemoteLinuxDeployService
class CustomCommandDeployStep : public AbstractRemoteLinuxDeployStep
{
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);
CheckResult isDeploymentPossible() const final;
@@ -34,20 +51,20 @@ private:
QString m_commandLine;
};
void CustomCommandDeployService::setCommandLine(const QString &commandLine)
void CustomCommandDeployStep::setCommandLine(const QString &commandLine)
{
m_commandLine = commandLine;
}
CheckResult CustomCommandDeployService::isDeploymentPossible() const
CheckResult CustomCommandDeployStep::isDeploymentPossible() const
{
if (m_commandLine.isEmpty())
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) {
emit progressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine));
@@ -76,30 +93,6 @@ Group CustomCommandDeployService::deployRecipe()
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

View File

@@ -25,7 +25,6 @@ using namespace Utils;
using namespace Utils::Tasking;
namespace RemoteLinux {
namespace Internal {
const int MaxConcurrentStatCalls = 10;
@@ -36,21 +35,13 @@ struct UploadStorage
enum class IncrementalDeployment { Enabled, Disabled, NotSupported };
class GenericDirectUploadService : public AbstractRemoteLinuxDeployService
class GenericDirectUploadStepPrivate
{
public:
GenericDirectUploadService(QObject *parent = nullptr)
: AbstractRemoteLinuxDeployService(parent)
GenericDirectUploadStepPrivate(GenericDirectUploadStep *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);
using FilesToStat = std::function<QList<DeployableFile>(UploadStorage *)>;
@@ -64,6 +55,7 @@ private:
TaskItem chmodTask(const DeployableFile &file);
TaskItem chmodTree(const TreeStorage<UploadStorage> &storage);
GenericDirectUploadStep *q;
IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported;
bool m_ignoreMissingFiles = false;
mutable QList<DeployableFile> m_deployableFiles;
@@ -84,37 +76,18 @@ QList<DeployableFile> collectFilesToUpload(const DeployableFile &deployable)
return collected;
}
} // namespace Internal
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
bool GenericDirectUploadStep::isDeploymentNecessary() const
{
QList<DeployableFile> collected;
for (int i = 0; i < m_deployableFiles.count(); ++i)
collected.append(collectFilesToUpload(m_deployableFiles.at(i)));
for (int i = 0; i < d->m_deployableFiles.count(); ++i)
collected.append(collectFilesToUpload(d->m_deployableFiles.at(i)));
QTC_CHECK(collected.size() >= m_deployableFiles.size());
m_deployableFiles = collected;
return !m_deployableFiles.isEmpty();
QTC_CHECK(collected.size() >= d->m_deployableFiles.size());
d->m_deployableFiles = collected;
return !d->m_deployableFiles.isEmpty();
}
QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &file,
QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile &file,
QtcProcess *statProc)
{
bool succeeded = false;
@@ -130,7 +103,7 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi
succeeded = true;
}
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")
.arg(file.remoteFilePath(), error));
return {};
@@ -139,30 +112,30 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi
const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2")
.arg(file.remoteFilePath()).arg(QString::fromUtf8(output)));
if (!output.startsWith(file.remoteFilePath().toUtf8())) {
emit warningMessage(warningString);
emit q->warningMessage(warningString);
return {};
}
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
emit warningMessage(warningString);
emit q->warningMessage(warningString);
return {};
}
bool isNumber;
const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber);
if (!isNumber) {
emit warningMessage(warningString);
emit q->warningMessage(warningString);
return {};
}
return QDateTime::fromSecsSinceEpoch(secsSinceEpoch);
}
TaskItem GenericDirectUploadService::statTask(UploadStorage *storage,
TaskItem GenericDirectUploadStepPrivate::statTask(UploadStorage *storage,
const DeployableFile &file,
StatEndHandler statEndHandler)
{
const auto setupHandler = [=](QtcProcess &process) {
// 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())}});
};
const auto endHandler = [=](const QtcProcess &process) {
@@ -173,7 +146,7 @@ TaskItem GenericDirectUploadService::statTask(UploadStorage *storage,
return Process(setupHandler, endHandler, endHandler);
}
TaskItem GenericDirectUploadService::statTree(const TreeStorage<UploadStorage> &storage,
TaskItem GenericDirectUploadStepPrivate::statTree(const TreeStorage<UploadStorage> &storage,
FilesToStat filesToStat, StatEndHandler statEndHandler)
{
const auto setupHandler = [=](TaskTree &tree) {
@@ -189,14 +162,14 @@ TaskItem GenericDirectUploadService::statTree(const TreeStorage<UploadStorage> &
return Tree(setupHandler);
}
TaskItem GenericDirectUploadService::uploadTask(const TreeStorage<UploadStorage> &storage)
TaskItem GenericDirectUploadStepPrivate::uploadTask(const TreeStorage<UploadStorage> &storage)
{
const auto setupHandler = [this, storage](FileTransfer &transfer) {
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;
}
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()));
FilesToTransfer files;
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.")
.arg(file.localFilePath().toUserOutput());
if (m_ignoreMissingFiles) {
emit warningMessage(message);
emit q->warningMessage(message);
continue;
}
emit errorMessage(message);
emit q->errorMessage(message);
return TaskAction::StopWithError;
}
files.append({file.localFilePath(),
deviceConfiguration()->filePath(file.remoteFilePath())});
q->deviceConfiguration()->filePath(file.remoteFilePath())});
}
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;
}
transfer.setFilesToTransfer(files);
QObject::connect(&transfer, &FileTransfer::progress,
this, &GenericDirectUploadService::progressMessage);
q, &GenericDirectUploadStep::progressMessage);
return TaskAction::Continue;
};
const auto errorHandler = [this](const FileTransfer &transfer) {
emit errorMessage(transfer.resultData().m_errorString);
emit q->errorMessage(transfer.resultData().m_errorString);
};
return Transfer(setupHandler, {}, errorHandler);
}
TaskItem GenericDirectUploadService::chmodTask(const DeployableFile &file)
TaskItem GenericDirectUploadStepPrivate::chmodTask(const DeployableFile &file)
{
const auto setupHandler = [=](QtcProcess &process) {
process.setCommand({deviceConfiguration()->filePath("chmod"),
process.setCommand({q->deviceConfiguration()->filePath("chmod"),
{"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}});
};
const auto errorHandler = [=](const QtcProcess &process) {
const QString error = process.errorString();
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));
} 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()));
}
};
return Process(setupHandler, {}, errorHandler);
}
TaskItem GenericDirectUploadService::chmodTree(const TreeStorage<UploadStorage> &storage)
TaskItem GenericDirectUploadStepPrivate::chmodTree(const TreeStorage<UploadStorage> &storage)
{
const auto setupChmodHandler = [=](TaskTree &tree) {
QList<DeployableFile> filesToChmod;
@@ -266,16 +239,16 @@ TaskItem GenericDirectUploadService::chmodTree(const TreeStorage<UploadStorage>
return Tree(setupChmodHandler);
}
Group GenericDirectUploadService::deployRecipe()
Group GenericDirectUploadStep::deployRecipe()
{
const auto preFilesToStat = [this](UploadStorage *storage) {
QList<DeployableFile> filesToStat;
for (const DeployableFile &file : std::as_const(m_deployableFiles)) {
if (m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) {
for (const DeployableFile &file : std::as_const(d->m_deployableFiles)) {
if (d->m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) {
storage->filesToUpload.append(file);
continue;
}
if (m_incremental == IncrementalDeployment::NotSupported)
if (d->m_incremental == IncrementalDeployment::NotSupported)
continue;
filesToStat << file;
}
@@ -288,7 +261,7 @@ Group GenericDirectUploadService::deployRecipe()
};
const auto postFilesToStat = [this](UploadStorage *storage) {
return m_incremental == IncrementalDeployment::NotSupported
return d->m_incremental == IncrementalDeployment::NotSupported
? QList<DeployableFile>() : storage->filesToUpload;
};
const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file,
@@ -304,11 +277,11 @@ Group GenericDirectUploadService::deployRecipe()
const TreeStorage<UploadStorage> storage;
const Group root {
Storage(storage),
statTree(storage, preFilesToStat, preStatEndHandler),
uploadTask(storage),
d->statTree(storage, preFilesToStat, preStatEndHandler),
d->uploadTask(storage),
Group {
chmodTree(storage),
statTree(storage, postFilesToStat, postStatEndHandler)
d->chmodTree(storage),
d->statTree(storage, postFilesToStat, postStatEndHandler)
},
OnGroupDone(doneHandler)
};
@@ -317,11 +290,9 @@ Group GenericDirectUploadService::deployRecipe()
GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id,
bool offerIncrementalDeployment)
: AbstractRemoteLinuxDeployStep(bsl, id)
: AbstractRemoteLinuxDeployStep(bsl, id),
d(new GenericDirectUploadStepPrivate(this))
{
auto service = new GenericDirectUploadService;
setDeployService(service);
BoolAspect *incremental = nullptr;
if (offerIncrementalDeployment) {
incremental = addAspect<BoolAspect>();
@@ -338,23 +309,26 @@ GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id i
BoolAspect::LabelPlacement::AtCheckBox);
ignoreMissingFiles->setValue(false);
setInternalInitializer([incremental, ignoreMissingFiles, service] {
setInternalInitializer([this, incremental, ignoreMissingFiles] {
if (incremental) {
service->setIncrementalDeployment(incremental->value()
? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled);
d->m_incremental = incremental->value()
? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled;
} else {
service->setIncrementalDeployment(IncrementalDeployment::NotSupported);
d->m_incremental = IncrementalDeployment::NotSupported;
}
service->setIgnoreMissingFiles(ignoreMissingFiles->value());
return service->isDeploymentPossible();
d->m_ignoreMissingFiles = ignoreMissingFiles->value();
return isDeploymentPossible();
});
setRunPreparer([this, service] {
service->setDeployableFiles(target()->deploymentData().allFiles());
setRunPreparer([this] {
d->m_deployableFiles = target()->deploymentData().allFiles();
});
}
GenericDirectUploadStep::~GenericDirectUploadStep() = default;
GenericDirectUploadStep::~GenericDirectUploadStep()
{
delete d;
}
Utils::Id GenericDirectUploadStep::stepId()
{

View File

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

View File

@@ -20,10 +20,21 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal {
class KillAppService : public AbstractRemoteLinuxDeployService
class KillAppStep : public AbstractRemoteLinuxDeployStep
{
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:
bool isDeploymentNecessary() const final { return !m_remoteExecutable.isEmpty(); }
@@ -32,7 +43,7 @@ private:
FilePath m_remoteExecutable;
};
Group KillAppService::deployRecipe()
Group KillAppStep::deployRecipe()
{
const auto setupHandler = [this](DeviceProcessKiller &killer) {
killer.setProcessPath(m_remoteExecutable);
@@ -49,27 +60,6 @@ Group KillAppService::deployRecipe()
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()
{
registerStep<KillAppStep>(Constants::KillAppStepId);

View File

@@ -25,39 +25,57 @@ using namespace Utils::Tasking;
namespace RemoteLinux {
class RsyncDeployService : public AbstractRemoteLinuxDeployService
// RsyncDeployStep
RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id)
: AbstractRemoteLinuxDeployStep(bsl, id)
{
public:
void setDeployableFiles(const QList<DeployableFile> &files);
void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; }
void setFlags(const QString &flags) { m_flags = flags; }
auto flags = addAspect<StringAspect>();
flags->setDisplayStyle(StringAspect::LineEditDisplay);
flags->setSettingsKey("RemoteLinux.RsyncDeployStep.Flags");
flags->setLabelText(Tr::tr("Flags:"));
flags->setValue(FileTransferSetupData::defaultRsyncFlags());
private:
bool isDeploymentNecessary() const final;
Group deployRecipe() final;
TaskItem mkdirTask();
TaskItem transferTask();
auto ignoreMissingFiles = addAspect<BoolAspect>();
ignoreMissingFiles->setSettingsKey("RemoteLinux.RsyncDeployStep.IgnoreMissingFiles");
ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files:"),
BoolAspect::LabelPlacement::InExtraLabel);
ignoreMissingFiles->setValue(false);
mutable FilesToTransfer m_files;
bool m_ignoreMissingFiles = false;
QString m_flags;
};
setInternalInitializer([this, ignoreMissingFiles, flags] {
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."));
}
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();
for (const DeployableFile &f : files)
m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())});
}
bool RsyncDeployService::isDeploymentNecessary() const
bool RsyncDeployStep::isDeploymentNecessary() const
{
if (m_ignoreMissingFiles)
Utils::erase(m_files, [](const FileToTransfer &file) { return !file.m_source.exists(); });
return !m_files.empty();
}
TaskItem RsyncDeployService::mkdirTask()
TaskItem RsyncDeployStep::mkdirTask()
{
const auto setupHandler = [this](QtcProcess &process) {
QStringList remoteDirs;
@@ -85,14 +103,14 @@ TaskItem RsyncDeployService::mkdirTask()
return Process(setupHandler, {}, errorHandler);
}
TaskItem RsyncDeployService::transferTask()
TaskItem RsyncDeployStep::transferTask()
{
const auto setupHandler = [this](FileTransfer &transfer) {
transfer.setTransferMethod(FileTransferMethod::Rsync);
transfer.setRsyncFlags(m_flags);
transfer.setFilesToTransfer(m_files);
connect(&transfer, &FileTransfer::progress,
this, &AbstractRemoteLinuxDeployService::stdOutData);
this, &AbstractRemoteLinuxDeployStep::stdOutData);
};
const auto errorHandler = [this](const FileTransfer &transfer) {
const ProcessResultData result = transfer.resultData();
@@ -108,50 +126,11 @@ TaskItem RsyncDeployService::transferTask()
return Transfer(setupHandler, {}, errorHandler);
}
Group RsyncDeployService::deployRecipe()
Group RsyncDeployStep::deployRecipe()
{
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()
{
return Constants::RsyncDeployStepId;

View File

@@ -7,6 +7,10 @@
#include "abstractremotelinuxdeploystep.h"
#include <projectexplorer/devicesupport/filetransfer.h>
#include <utils/tasktree.h>
namespace RemoteLinux {
class REMOTELINUX_EXPORT RsyncDeployStep : public AbstractRemoteLinuxDeployStep
@@ -17,6 +21,20 @@ public:
static Utils::Id stepId();
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

View File

@@ -21,9 +21,36 @@ using namespace Utils::Tasking;
namespace RemoteLinux::Internal {
class TarPackageDeployService : public AbstractRemoteLinuxDeployService
// TarPackageDeployStep
class TarPackageDeployStep : public AbstractRemoteLinuxDeployStep
{
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);
private:
@@ -36,29 +63,28 @@ private:
FilePath m_packageFilePath;
};
void TarPackageDeployService::setPackageFilePath(const FilePath &filePath)
void TarPackageDeployStep::setPackageFilePath(const FilePath &filePath)
{
m_packageFilePath = filePath;
}
QString TarPackageDeployService::remoteFilePath() const
QString TarPackageDeployStep::remoteFilePath() const
{
return QLatin1String("/tmp/") + m_packageFilePath.fileName();
}
bool TarPackageDeployService::isDeploymentNecessary() const
bool TarPackageDeployStep::isDeploymentNecessary() const
{
return hasLocalFileChanged(DeployableFile(m_packageFilePath, {}));
}
TaskItem TarPackageDeployService::uploadTask()
TaskItem TarPackageDeployStep::uploadTask()
{
const auto setupHandler = [this](FileTransfer &transfer) {
const FilesToTransfer files {{m_packageFilePath,
deviceConfiguration()->filePath(remoteFilePath())}};
transfer.setFilesToTransfer(files);
connect(&transfer, &FileTransfer::progress,
this, &TarPackageDeployService::progressMessage);
connect(&transfer, &FileTransfer::progress, this, &TarPackageDeployStep::progressMessage);
emit progressMessage(Tr::tr("Uploading package to device..."));
};
const auto doneHandler = [this](const FileTransfer &) {
@@ -71,7 +97,7 @@ TaskItem TarPackageDeployService::uploadTask()
return Transfer(setupHandler, doneHandler, errorHandler);
}
TaskItem TarPackageDeployService::installTask()
TaskItem TarPackageDeployStep::installTask()
{
const auto setupHandler = [this](QtcProcess &process) {
const QString cmdLine = QLatin1String("cd / && tar xvf ") + remoteFilePath()
@@ -96,46 +122,11 @@ TaskItem TarPackageDeployService::installTask()
return Process(setupHandler, doneHandler, errorHandler);
}
Group TarPackageDeployService::deployRecipe()
Group TarPackageDeployStep::deployRecipe()
{
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