TaskTree: Get rid of onGroupError element

Make it possible to setup onGroupDone element with additional
OnDone argument.
The onGroupDone handler may accept extra DoneResult argument.
The onGroupDone handler may also tweak the success bit of a group.

All above features conform to the behavior of the task done handler.

Task-number: QTCREATORBUG-29834
Change-Id: I125bdfe155e585678fb33410632246401cbc9390
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2023-11-03 18:50:32 +01:00
parent fbe359308d
commit 37b6cb7f90
27 changed files with 253 additions and 275 deletions

View File

@@ -707,6 +707,8 @@ private:
\sa onGroupDone(), onGroupError()
*/
// TODO: Fix docs
/*!
\fn template <typename SetupHandler> GroupItem onGroupSetup(SetupHandler &&handler)
@@ -726,6 +728,8 @@ private:
\sa GroupItem::GroupSetupHandler, onGroupDone(), onGroupError()
*/
// TODO: Fix docs
/*!
Constructs a group's element holding the group done handler.
The \a handler is invoked whenever the group finishes with success.
@@ -740,10 +744,8 @@ private:
\sa GroupItem::GroupEndHandler, onGroupSetup(), onGroupError()
*/
GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler)
{
return Group::onGroupDone(handler);
}
// TODO: Fix docs
/*!
Constructs a group's element holding the group error handler.
@@ -759,10 +761,6 @@ GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler)
\sa GroupItem::GroupEndHandler, onGroupSetup(), onGroupDone()
*/
GroupItem onGroupError(const GroupItem::GroupEndHandler &handler)
{
return Group::onGroupError(handler);
}
/*!
Constructs a group's element describing the \l{Execution Mode}{execution mode}.
@@ -924,12 +922,6 @@ void GroupItem::addChildren(const QList<GroupItem> &children)
m_groupData.m_groupHandler.m_doneHandler
= child.m_groupData.m_groupHandler.m_doneHandler;
}
if (child.m_groupData.m_groupHandler.m_errorHandler) {
QTC_ASSERT(!m_groupData.m_groupHandler.m_errorHandler,
qWarning("Group Error Handler redefinition, overriding..."));
m_groupData.m_groupHandler.m_errorHandler
= child.m_groupData.m_groupHandler.m_errorHandler;
}
if (child.m_groupData.m_parallelLimit) {
QTC_ASSERT(!m_groupData.m_parallelLimit,
qWarning("Group Execution Mode redefinition, overriding..."));
@@ -954,7 +946,7 @@ void GroupItem::addChildren(const QList<GroupItem> &children)
}
GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout,
const GroupEndHandler &handler)
const std::function<void()> &handler)
{
const auto onSetup = [timeout](milliseconds &timeoutData) { timeoutData = timeout; };
return Group {
@@ -1032,7 +1024,7 @@ public:
SetupResult startChildren(int nextChild);
SetupResult childDone(bool success);
void stop();
void invokeEndHandler();
bool invokeDoneHandler(DoneWith result);
bool isRunning() const { return m_runtimeData.has_value(); }
bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); }
@@ -1329,14 +1321,14 @@ SetupResult TaskContainer::continueStart(SetupResult startAction, int nextChild)
: startAction;
QTC_CHECK(isRunning()); // TODO: superfluous
if (groupAction != SetupResult::Continue) {
const bool success = m_runtimeData->updateSuccessBit(groupAction == SetupResult::StopWithDone);
invokeEndHandler();
const bool bit = m_runtimeData->updateSuccessBit(groupAction == SetupResult::StopWithDone);
const bool result = invokeDoneHandler(bit ? DoneWith::Success : DoneWith::Error);
if (TaskContainer *parentContainer = m_constData.m_parentContainer) {
QTC_CHECK(parentContainer->isRunning());
if (!parentContainer->isStarting())
parentContainer->childDone(success);
parentContainer->childDone(result);
} else {
m_constData.m_taskTreePrivate->emitDone(success ? DoneWith::Success : DoneWith::Error);
m_constData.m_taskTreePrivate->emitDone(result ? DoneWith::Success : DoneWith::Error);
}
}
return groupAction;
@@ -1406,15 +1398,22 @@ void TaskContainer::stop()
m_constData.m_taskTreePrivate->advanceProgress(skippedTaskCount);
}
void TaskContainer::invokeEndHandler()
static bool shouldCall(CallDoneIf callDoneIf, DoneWith result)
{
if (result == DoneWith::Success)
return callDoneIf != CallDoneIf::Error;
return callDoneIf != CallDoneIf::Success;
}
bool TaskContainer::invokeDoneHandler(DoneWith result)
{
bool success = result == DoneWith::Success;
const GroupItem::GroupHandler &groupHandler = m_constData.m_groupHandler;
if (m_runtimeData->m_successBit && groupHandler.m_doneHandler)
invokeHandler(this, groupHandler.m_doneHandler);
else if (!m_runtimeData->m_successBit && groupHandler.m_errorHandler)
invokeHandler(this, groupHandler.m_errorHandler);
if (groupHandler.m_doneHandler && shouldCall(groupHandler.m_callDoneIf, result))
success = invokeHandler(this, groupHandler.m_doneHandler, result);
m_runtimeData->callStorageDoneHandlers();
m_runtimeData.reset();
return success;
}
SetupResult TaskNode::start()
@@ -1457,7 +1456,7 @@ void TaskNode::stop()
if (!m_task) {
m_container.stop();
m_container.m_runtimeData->updateSuccessBit(false);
m_container.invokeEndHandler();
m_container.invokeDoneHandler(DoneWith::Cancel);
return;
}
@@ -1467,13 +1466,6 @@ void TaskNode::stop()
m_task.reset();
}
static bool shouldCall(CallDoneIf callDoneIf, DoneWith result)
{
if (result == DoneWith::Success)
return callDoneIf != CallDoneIf::Error;
return callDoneIf != CallDoneIf::Success;
}
bool TaskNode::invokeDoneHandler(DoneWith result)
{
bool success = result == DoneWith::Success;

View File

@@ -157,10 +157,10 @@ public:
using TaskSetupHandler = std::function<SetupResult(TaskInterface &)>;
// Called on task done, just before deleteLater
using TaskDoneHandler = std::function<bool(const TaskInterface &, DoneWith)>;
// Called when group entered
// Called when group entered, after group's storages are created
using GroupSetupHandler = std::function<SetupResult()>;
// Called when group done / error
using GroupEndHandler = std::function<void()>;
// Called when group done, before group's storages are deleted
using GroupDoneHandler = std::function<bool(DoneWith)>;
struct TaskHandler {
TaskCreateHandler m_createHandler;
@@ -171,8 +171,8 @@ public:
struct GroupHandler {
GroupSetupHandler m_setupHandler;
GroupEndHandler m_doneHandler = {};
GroupEndHandler m_errorHandler = {};
GroupDoneHandler m_doneHandler = {};
CallDoneIf m_callDoneIf = CallDoneIf::SuccessOrError;
};
struct GroupData {
@@ -210,7 +210,7 @@ protected:
static GroupItem parallelLimit(int limit) { return GroupItem({{}, limit}); }
static GroupItem workflowPolicy(WorkflowPolicy policy) { return GroupItem({{}, {}, policy}); }
static GroupItem withTimeout(const GroupItem &item, std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {});
const std::function<void()> &handler = {});
private:
Type m_type = Type::Group;
@@ -227,32 +227,30 @@ public:
Group(std::initializer_list<GroupItem> children) { addChildren(children); }
// GroupData related:
template <typename SetupHandler>
static GroupItem onGroupSetup(SetupHandler &&handler) {
return groupHandler({wrapGroupSetup(std::forward<SetupHandler>(handler))});
template <typename Handler>
static GroupItem onGroupSetup(Handler &&handler) {
return groupHandler({wrapGroupSetup(std::forward<Handler>(handler))});
}
static GroupItem onGroupDone(const GroupEndHandler &handler) {
return groupHandler({{}, handler});
}
static GroupItem onGroupError(const GroupEndHandler &handler) {
return groupHandler({{}, {}, handler});
template <typename Handler>
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDoneIf::SuccessOrError) {
return groupHandler({{}, wrapGroupDone(std::forward<Handler>(handler)), callDoneIf});
}
using GroupItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
using GroupItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
GroupItem withTimeout(std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {}) const {
const std::function<void()> &handler = {}) const {
return GroupItem::withTimeout(*this, timeout, handler);
}
private:
template<typename SetupHandler>
static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler)
template<typename Handler>
static GroupSetupHandler wrapGroupSetup(Handler &&handler)
{
static constexpr bool isDynamic
= std::is_same_v<SetupResult, std::invoke_result_t<std::decay_t<SetupHandler>>>;
= std::is_same_v<SetupResult, std::invoke_result_t<std::decay_t<Handler>>>;
constexpr bool isVoid
= std::is_same_v<void, std::invoke_result_t<std::decay_t<SetupHandler>>>;
= std::is_same_v<void, std::invoke_result_t<std::decay_t<Handler>>>;
static_assert(isDynamic || isVoid,
"Group setup handler needs to take no arguments and has to return "
"void or SetupResult. The passed handler doesn't fulfill these requirements.");
@@ -263,16 +261,49 @@ private:
return SetupResult::Continue;
};
};
template<typename Handler>
static GroupDoneHandler wrapGroupDone(Handler &&handler)
{
static constexpr bool isBD // stands for [B]ool, [D]oneWith
= std::is_invocable_r_v<bool, std::decay_t<Handler>, DoneWith>;
static constexpr bool isB
= std::is_invocable_r_v<bool, std::decay_t<Handler>>;
static constexpr bool isVD // stands for [V]oid, [D]oneWith
= std::is_invocable_r_v<void, std::decay_t<Handler>, DoneWith>;
static constexpr bool isV
= std::is_invocable_r_v<void, std::decay_t<Handler>>;
static constexpr bool isInvocable = isBD || isB || isVD || isV;
static_assert(isInvocable,
"Group done handler needs to take (DoneWith) or (void) "
"as arguments and has to return void or bool. "
"The passed handler doesn't fulfill these requirements.");
return [=](DoneWith result) {
if constexpr (isBD)
return std::invoke(handler, result);
if constexpr (isB)
return std::invoke(handler);
if constexpr (isVD)
std::invoke(handler, result);
else if constexpr (isV)
std::invoke(handler);
return result == DoneWith::Success;
};
};
};
template <typename SetupHandler>
static GroupItem onGroupSetup(SetupHandler &&handler)
template <typename Handler>
static GroupItem onGroupSetup(Handler &&handler)
{
return Group::onGroupSetup(std::forward<SetupHandler>(handler));
return Group::onGroupSetup(std::forward<Handler>(handler));
}
template <typename Handler>
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDoneIf::SuccessOrError)
{
return Group::onGroupDone(std::forward<Handler>(handler), callDoneIf);
}
TASKING_EXPORT GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler);
TASKING_EXPORT GroupItem onGroupError(const GroupItem::GroupEndHandler &handler);
TASKING_EXPORT GroupItem parallelLimit(int limit);
TASKING_EXPORT GroupItem workflowPolicy(WorkflowPolicy policy);
@@ -354,7 +385,8 @@ public:
{}
GroupItem withTimeout(std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {}) const {
const std::function<void()> &handler = {}) const
{
return GroupItem::withTimeout(*this, timeout, handler);
}

View File

@@ -834,7 +834,7 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe()
const Group root {
onGroupSetup(onSetup),
onGroupDone(onDone),
onGroupDone(onDone, CallDoneIf::Success),
defaultProcessTask()
};
return root;

View File

@@ -94,9 +94,12 @@ Tasking::GroupItem AutogenStep::runRecipe()
}
return SetupResult::Continue;
};
const auto onDone = [this] { m_runAutogen = false; };
return Group { onGroupSetup(onSetup), onGroupDone(onDone), defaultProcessTask() };
return Group {
onGroupSetup(onSetup),
onGroupDone([this] { m_runAutogen = false; }, CallDoneIf::Success),
defaultProcessTask()
};
}
// AutogenStepFactory

View File

@@ -79,9 +79,12 @@ private:
}
return SetupResult::Continue;
};
const auto onDone = [this] { m_runAutoreconf = false; };
return Group { onGroupSetup(onSetup), onGroupDone(onDone), defaultProcessTask() };
return Group {
onGroupSetup(onSetup),
onGroupDone([this] { m_runAutoreconf = false; }, CallDoneIf::Success),
defaultProcessTask()
};
}
bool m_runAutoreconf = false;

View File

@@ -98,9 +98,12 @@ Tasking::GroupItem ConfigureStep::runRecipe()
}
return SetupResult::Continue;
};
const auto onDone = [this] { m_runConfigure = false; };
return Group { onGroupSetup(onSetup), onGroupDone(onDone), defaultProcessTask() };
return Group {
onGroupSetup(onSetup),
onGroupDone([this] { m_runConfigure = false; }, CallDoneIf::Success),
defaultProcessTask()
};
}
// ConfigureStepFactory

View File

@@ -369,15 +369,11 @@ GroupItem CMakeBuildStep::runRecipe()
emit addOutput(Tr::tr("Project did not parse successfully, cannot build."),
OutputFormat::ErrorMessage);
};
const auto onEnd = [this] {
updateDeploymentData();
};
Group root {
ignoreReturnValue() ? finishAllAndDone : stopOnError,
ProjectParserTask(onParserSetup, onParserError, CallDoneIf::Error),
defaultProcessTask(),
onGroupDone(onEnd),
onGroupError(onEnd)
onGroupDone([this] { updateDeploymentData(); })
};
return root;
}

View File

@@ -457,10 +457,6 @@ void LocatorMatcher::start()
};
};
const auto onDone = [](const TreeStorage<LocatorStorage> &storage) {
return [storage] { storage->finalize(); };
};
int index = 0;
for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) {
const auto storage = task.storage;
@@ -468,8 +464,7 @@ void LocatorMatcher::start()
finishAllAndDone,
Storage(storage),
onGroupSetup(onSetup(storage, index)),
onGroupDone(onDone(storage)),
onGroupError(onDone(storage)),
onGroupDone([storage] { storage->finalize(); }),
task.task
};
parallelTasks << group;

View File

@@ -390,7 +390,7 @@ void Locator::refresh(const QList<ILocatorFilter *> &filters)
const Group group {
finishAllAndDone,
*task,
onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); })
onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); }, CallDoneIf::Success)
};
tasks.append(group);
}

View File

@@ -68,7 +68,10 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo,
tasks.append(compiler->compileFileItem());
}
const auto onDone = [this, storage, compilers] {
const auto onDone = [this, storage, compilers](DoneWith result) {
m_taskTree.release()->deleteLater();
if (result != DoneWith::Success)
return;
QList<ExtraCompiler *> extraCompilers;
QSet<FilePath> compilerFiles;
for (const QPointer<ExtraCompiler> &compiler : compilers) {
@@ -80,17 +83,12 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo,
GeneratedCodeModelSupport::update(extraCompilers);
auto updateFuture = CppModelManager::updateProjectInfo(storage->projectInfo, compilerFiles);
m_futureSynchronizer.addFuture(updateFuture);
m_taskTree.release()->deleteLater();
};
const auto onError = [this] {
m_taskTree.release()->deleteLater();
};
const Group root {
Tasking::Storage(storage),
Group(tasks),
onGroupDone(onDone),
onGroupError(onError)
onGroupDone(onDone)
};
m_taskTree.reset(new TaskTree(root));
auto progress = new Core::TaskProgress(m_taskTree.get());

View File

@@ -132,24 +132,21 @@ DiffFilesController::DiffFilesController(IDocument *document)
}
taskTree.setRecipe(tasks);
};
const auto onTreeDone = [this, storage] {
const QList<std::optional<FileData>> &results = *storage;
const auto onTreeDone = [this, storage](DoneWith result) {
QList<FileData> finalList;
if (result == DoneWith::Success) {
const QList<std::optional<FileData>> &results = *storage;
for (const std::optional<FileData> &result : results) {
if (result.has_value())
finalList.append(*result);
}
}
setDiffFiles(finalList);
};
const auto onTreeError = [this, storage] {
setDiffFiles({});
};
const Group root = {
Storage(storage),
TaskTreeTask(onTreeSetup),
onGroupDone(onTreeDone),
onGroupError(onTreeError)
TaskTreeTask(onTreeSetup, onTreeDone)
};
setReloadRecipe(root);
}

View File

@@ -468,8 +468,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError)
const Group root {
topRevisionProc,
ProcessTask(onForEachRefSetup, onForEachRefDone),
onGroupDone(finalize),
onGroupError(finalize)
onGroupDone(finalize)
};
d->refreshTask.reset(new TaskTree(root));
d->refreshTask->start();

View File

@@ -568,7 +568,7 @@ TaskTree *BranchView::onFastForwardMerge(const std::function<void()> &callback)
onGroupDone([storage, callback] {
if (storage->mergeBase == storage->topRevision)
callback();
})
}, CallDoneIf::Success)
};
auto taskTree = new TaskTree(root);
taskTree->start();

View File

@@ -340,7 +340,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin
continueOnDone,
ProcessTask(onStagedSetup, onStagedDone, CallDoneIf::Success),
ProcessTask(onUnstagedSetup, onUnstagedDone, CallDoneIf::Success),
onGroupDone(onDone)
onGroupDone(onDone, CallDoneIf::Success)
},
postProcessTask(diffInputStorage)
};
@@ -498,7 +498,11 @@ ShowController::ShowController(IDocument *document, const QString &id)
updateDescription(*data);
};
QList<GroupItem> tasks { parallel, continueOnDone, onGroupError(onFollowsError) };
QList<GroupItem> tasks {
parallel,
continueOnDone,
onGroupDone(onFollowsError, CallDoneIf::Error)
};
for (int i = 0, total = parents.size(); i < total; ++i) {
const auto onFollowSetup = [this, parent = parents.at(i)](Process &process) {
setupCommand(process, {"describe", "--tags", "--abbrev=0", parent});

View File

@@ -648,15 +648,14 @@ void BuildManager::startBuildQueue()
if (d->m_futureProgress)
d->m_futureProgress.data()->setTitle(name);
};
const auto onRecipeDone = [buildStep] {
const auto onRecipeDone = [buildStep, target](DoneWith result) {
disconnect(buildStep, &BuildStep::progress, instance(), nullptr);
d->m_outputWindow->flush();
++d->m_progress;
d->m_progressFutureInterface->setProgressValueAndText(
100 * d->m_progress, msgProgress(d->m_progress, d->m_maxProgress));
};
const auto onRecipeError = [buildStep, target, onRecipeDone] {
onRecipeDone();
if (result == DoneWith::Success)
return;
const QString projectName = buildStep->project()->displayName();
const QString targetName = target->displayName();
addToOutputWindow(Tr::tr("Error while building/deploying project %1 (kit: %2)")
@@ -673,8 +672,7 @@ void BuildManager::startBuildQueue()
const Group recipeGroup {
onGroupSetup(onRecipeSetup),
buildStep->runRecipe(),
onGroupDone(onRecipeDone),
onGroupError(onRecipeError),
onGroupDone(onRecipeDone)
};
targetTasks.append(recipeGroup);
}

View File

@@ -229,7 +229,7 @@ Tasking::GroupItem QmakeMakeStep::runRecipe()
return Group {
ignoreReturnValue() ? finishAllAndDone : stopOnError,
onGroupSetup(onSetup),
onGroupError(onError),
onGroupDone(onError, CallDoneIf::Error),
defaultProcessTask()
};
}

View File

@@ -299,7 +299,7 @@ Tasking::GroupItem QMakeStep::runRecipe()
};
QList<GroupItem> processList = {onGroupSetup(onSetup),
onGroupDone(onDone),
onGroupDone(onDone, CallDoneIf::Success),
ProcessTask(onQMakeSetup, onProcessDone)};
if (m_runMakeQmake)
processList << ProcessTask(onMakeQMakeSetup, onProcessDone);

View File

@@ -272,7 +272,7 @@ Group QnxDeployQtLibrariesDialogPrivate::deployRecipe()
uploadTask(),
chmodTree()
},
onGroupDone(doneHandler)
onGroupDone(doneHandler, CallDoneIf::Success)
};
return root;
}

View File

@@ -148,17 +148,16 @@ GroupItem AbstractRemoteLinuxDeployStep::runRecipe()
}
return SetupResult::Continue;
};
const auto onDone = [this] {
const auto onDone = [this](DoneWith result) {
if (result == DoneWith::Success)
emit addOutput(Tr::tr("Deploy step finished."), OutputFormat::NormalMessage);
};
const auto onError = [this] {
else
emit addOutput(Tr::tr("Deploy step failed."), OutputFormat::ErrorMessage);
};
return Group {
onGroupSetup(onSetup),
deployRecipe(),
onGroupDone(onDone),
onGroupError(onError)
onGroupDone(onDone)
};
}

View File

@@ -297,7 +297,7 @@ GroupItem GenericDirectUploadStep::deployRecipe()
uploadTask(storage),
chmodTree(storage),
statTree(storage, postFilesToStat, postStatEndHandler),
onGroupDone(doneHandler)
onGroupDone(doneHandler, CallDoneIf::Success)
};
return root;
}

View File

@@ -227,16 +227,17 @@ GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod metho
GroupItem GenericLinuxDeviceTesterPrivate::transferTasks() const
{
TreeStorage<TransferStorage> storage;
return Group{continueOnDone,
return Group {
continueOnDone,
Tasking::Storage(storage),
transferTask(FileTransferMethod::GenericCopy, storage),
transferTask(FileTransferMethod::Sftp, storage),
transferTask(FileTransferMethod::Rsync, storage),
onGroupError([this] {
emit q->errorMessage(Tr::tr("Deployment to this device will not "
"work out of the box.")
onGroupDone([this] {
emit q->errorMessage(Tr::tr("Deployment to this device will not work out of the box.")
+ "\n");
})};
}, CallDoneIf::Error)
};
}
GroupItem GenericLinuxDeviceTesterPrivate::commandTask(const QString &commandName) const
@@ -299,8 +300,8 @@ void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguratio
d->m_device = deviceConfiguration;
auto allFinished = [this](DeviceTester::TestResult testResult) {
emit finished(testResult);
auto onDone = [this](DoneWith result) {
emit finished(result == DoneWith::Success ? TestSuccess : TestFailure);
d->m_taskTree.release()->deleteLater();
};
@@ -313,9 +314,7 @@ void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguratio
};
if (!d->m_extraTests.isEmpty())
taskItems << Group { d->m_extraTests };
taskItems << d->commandTasks()
<< onGroupDone(std::bind(allFinished, TestSuccess))
<< onGroupError(std::bind(allFinished, TestFailure));
taskItems << d->commandTasks() << onGroupDone(onDone);
d->m_taskTree.reset(new TaskTree(taskItems));
d->m_taskTree->start();

View File

@@ -192,7 +192,14 @@ Tasking::GroupItem MakeInstallStep::runRecipe()
{
using namespace Tasking;
const auto onDone = [this] {
const auto onDone = [this](DoneWith result) {
if (result != DoneWith::Success) {
if (m_noInstallTarget && m_isCmakeProject) {
emit addTask(DeploymentTask(Task::Warning, Tr::tr("You need to add an install "
"statement to your CMakeLists.txt file for deployment to work.")));
}
return;
}
const FilePath rootDir = makeCommand().withNewPath(m_installRoot().path()); // FIXME: Needed?
m_deploymentData = DeploymentData();
@@ -215,14 +222,8 @@ Tasking::GroupItem MakeInstallStep::runRecipe()
buildSystem()->setDeploymentData(m_deploymentData);
};
const auto onError = [this] {
if (m_noInstallTarget && m_isCmakeProject) {
emit addTask(DeploymentTask(Task::Warning, Tr::tr("You need to add an install "
"statement to your CMakeLists.txt file for deployment to work.")));
}
};
return Group { onGroupDone(onDone), onGroupError(onError), defaultProcessTask() };
return Group { onGroupDone(onDone), defaultProcessTask() };
}
void MakeInstallStep::updateCommandFromAspect()

View File

@@ -24,7 +24,7 @@ enum class Handler {
Canceled,
GroupSetup,
GroupSuccess,
GroupError,
GroupError, // TODO: Add GroupCanceled
Sync,
BarrierAdvance,
Timeout
@@ -116,8 +116,7 @@ void tst_Tasking::validConstructs()
}
},
task,
onGroupDone([] {}),
onGroupError([] {})
onGroupDone([] {})
};
const auto setupHandler = [](TaskObject &) {};
@@ -213,6 +212,11 @@ GroupItem createBarrierAdvance(const TreeStorage<CustomStorage> &storage,
});
}
static Handler resultToGroupHandler(DoneWith result)
{
return result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError;
}
void tst_Tasking::testTree_data()
{
QTest::addColumn<TestData>("testData");
@@ -267,13 +271,14 @@ void tst_Tasking::testTree_data()
};
const auto groupSetup = [storage](int taskId) {
return onGroupSetup([=] { storage->m_log.append({taskId, Handler::GroupSetup}); });
return onGroupSetup([storage, taskId] {
storage->m_log.append({taskId, Handler::GroupSetup});
});
};
const auto groupDone = [storage](int taskId) {
return onGroupDone([=] { storage->m_log.append({taskId, Handler::GroupSuccess}); });
};
const auto groupError = [storage](int taskId) {
return onGroupError([=] { storage->m_log.append({taskId, Handler::GroupError}); });
return onGroupDone([storage, taskId](DoneWith result) {
storage->m_log.append({taskId, resultToGroupHandler(result)});
});
};
const auto createSync = [storage](int taskId) {
return Sync([=] { storage->m_log.append({taskId, Handler::Sync}); });
@@ -285,26 +290,22 @@ void tst_Tasking::testTree_data()
{
const Group root1 {
Storage(storage),
groupDone(0),
groupError(0)
groupDone(0)
};
const Group root2 {
Storage(storage),
onGroupSetup([] { return SetupResult::Continue; }),
groupDone(0),
groupError(0)
groupDone(0)
};
const Group root3 {
Storage(storage),
onGroupSetup([] { return SetupResult::StopWithDone; }),
groupDone(0),
groupError(0)
groupDone(0)
};
const Group root4 {
Storage(storage),
onGroupSetup([] { return SetupResult::StopWithError; }),
groupDone(0),
groupError(0)
groupDone(0)
};
const Log logDone {{0, Handler::GroupSuccess}};
@@ -322,8 +323,7 @@ void tst_Tasking::testTree_data()
Storage(storage),
workflowPolicy(policy),
onGroupSetup([setupResult] { return setupResult; }),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -641,8 +641,7 @@ void tst_Tasking::testTree_data()
createFailingTask(3),
createSuccessTask(4),
createSuccessTask(5),
groupDone(0),
groupError(0)
groupDone(0)
};
const Log log {
{1, Handler::Setup},
@@ -657,12 +656,11 @@ void tst_Tasking::testTree_data()
}
{
const auto createRoot = [storage, groupDone, groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, groupDone](WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -699,14 +697,13 @@ void tst_Tasking::testTree_data()
}
{
const auto createRoot = [storage, createSuccessTask, groupDone, groupError](
const auto createRoot = [storage, createSuccessTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
createSuccessTask(1),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -752,14 +749,13 @@ void tst_Tasking::testTree_data()
}
{
const auto createRoot = [storage, createFailingTask, groupDone, groupError](
const auto createRoot = [storage, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
createFailingTask(1),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -808,16 +804,15 @@ void tst_Tasking::testTree_data()
// These tests check whether the proper root's group end handler is called
// when the group is stopped. Test it with different workflow policies.
// The root starts one short failing task together with one long task.
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
parallel,
workflowPolicy(policy),
createFailingTask(1, 1ms),
createSuccessTask(2, 1ms),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -879,8 +874,8 @@ void tst_Tasking::testTree_data()
// when the group is stopped. Test it with different workflow policies.
// The root starts in parallel: one very short successful task, one short failing task
// and one long task.
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
parallel,
@@ -888,8 +883,7 @@ void tst_Tasking::testTree_data()
createSuccessTask(1),
createFailingTask(2, 1ms),
createSuccessTask(3, 1ms),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -966,24 +960,22 @@ void tst_Tasking::testTree_data()
// These tests check whether the proper subgroup's end handler is called
// when the group is stopped. Test it with different workflow policies.
// The subgroup starts one long task.
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
parallel,
Group {
workflowPolicy(policy),
createSuccessTask(1, 1000ms),
groupDone(1),
groupError(1)
groupDone(1)
},
createFailingTask(2, 1ms),
groupDone(2),
groupError(2)
groupDone(2)
};
};
const Log errorLog = {
const Log log = {
{1, Handler::Setup},
{2, Handler::Setup},
{2, Handler::Error},
@@ -992,50 +984,43 @@ void tst_Tasking::testTree_data()
{2, Handler::GroupError}
};
const Log doneLog = {
{1, Handler::Setup},
{2, Handler::Setup},
{2, Handler::Error},
{1, Handler::Canceled},
{1, Handler::GroupSuccess},
{2, Handler::GroupError}
};
const Group root1 = createRoot(WorkflowPolicy::StopOnError);
QTest::newRow("StopGroupWithStopOnError")
<< TestData{storage, root1, errorLog, 2, OnDone::Failure};
<< TestData{storage, root1, log, 2, OnDone::Failure};
const Group root2 = createRoot(WorkflowPolicy::ContinueOnError);
QTest::newRow("StopGroupWithContinueOnError")
<< TestData{storage, root2, errorLog, 2, OnDone::Failure};
<< TestData{storage, root2, log, 2, OnDone::Failure};
const Group root3 = createRoot(WorkflowPolicy::StopOnDone);
QTest::newRow("StopGroupWithStopOnDone")
<< TestData{storage, root3, errorLog, 2, OnDone::Failure};
<< TestData{storage, root3, log, 2, OnDone::Failure};
const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone);
QTest::newRow("StopGroupWithContinueOnDone")
<< TestData{storage, root4, errorLog, 2, OnDone::Failure};
<< TestData{storage, root4, log, 2, OnDone::Failure};
const Group root5 = createRoot(WorkflowPolicy::StopOnFinished);
QTest::newRow("StopGroupWithStopOnFinished")
<< TestData{storage, root5, errorLog, 2, OnDone::Failure};
<< TestData{storage, root5, log, 2, OnDone::Failure};
// TODO: Behavioral change! Fix Docs!
// Cancellation always invokes error handler (i.e. DoneWith is Cancel)
const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone);
QTest::newRow("StopGroupWithFinishAllAndDone")
<< TestData{storage, root6, doneLog, 2, OnDone::Failure};
<< TestData{storage, root6, log, 2, OnDone::Failure};
const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError);
QTest::newRow("StopGroupWithFinishAllAndError")
<< TestData{storage, root7, errorLog, 2, OnDone::Failure};
<< TestData{storage, root7, log, 2, OnDone::Failure};
}
{
// These tests check whether the proper subgroup's end handler is called
// when the group is stopped. Test it with different workflow policies.
// The sequential subgroup starts one short successful task followed by one long task.
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
parallel,
@@ -1043,12 +1028,10 @@ void tst_Tasking::testTree_data()
workflowPolicy(policy),
createSuccessTask(1),
createSuccessTask(2, 1000ms),
groupDone(1),
groupError(1)
groupDone(1)
},
createFailingTask(3, 1ms),
groupDone(2),
groupError(2)
groupDone(2)
};
};
@@ -1063,7 +1046,7 @@ void tst_Tasking::testTree_data()
{2, Handler::GroupError}
};
const Log shortDoneLog = {
const Log doneLog = {
{1, Handler::Setup},
{3, Handler::Setup},
{1, Handler::Success},
@@ -1072,17 +1055,6 @@ void tst_Tasking::testTree_data()
{2, Handler::GroupError}
};
const Log longDoneLog = {
{1, Handler::Setup},
{3, Handler::Setup},
{1, Handler::Success},
{2, Handler::Setup},
{3, Handler::Error},
{2, Handler::Canceled},
{1, Handler::GroupSuccess},
{2, Handler::GroupError}
};
const Group root1 = createRoot(WorkflowPolicy::StopOnError);
QTest::newRow("StopGroupAfterDoneWithStopOnError")
<< TestData{storage, root1, errorLog, 3, OnDone::Failure};
@@ -1093,19 +1065,21 @@ void tst_Tasking::testTree_data()
const Group root3 = createRoot(WorkflowPolicy::StopOnDone);
QTest::newRow("StopGroupAfterDoneWithStopOnDone")
<< TestData{storage, root3, shortDoneLog, 3, OnDone::Failure};
<< TestData{storage, root3, doneLog, 3, OnDone::Failure};
// TODO: Behavioral change!
const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone);
QTest::newRow("StopGroupAfterDoneWithContinueOnDone")
<< TestData{storage, root4, longDoneLog, 3, OnDone::Failure};
<< TestData{storage, root4, errorLog, 3, OnDone::Failure};
const Group root5 = createRoot(WorkflowPolicy::StopOnFinished);
QTest::newRow("StopGroupAfterDoneWithStopOnFinished")
<< TestData{storage, root5, shortDoneLog, 3, OnDone::Failure};
<< TestData{storage, root5, doneLog, 3, OnDone::Failure};
// TODO: Behavioral change!
const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone);
QTest::newRow("StopGroupAfterDoneWithFinishAllAndDone")
<< TestData{storage, root6, longDoneLog, 3, OnDone::Failure};
<< TestData{storage, root6, errorLog, 3, OnDone::Failure};
const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError);
QTest::newRow("StopGroupAfterDoneWithFinishAllAndError")
@@ -1116,8 +1090,8 @@ void tst_Tasking::testTree_data()
// These tests check whether the proper subgroup's end handler is called
// when the group is stopped. Test it with different workflow policies.
// The sequential subgroup starts one short failing task followed by one long task.
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
parallel,
@@ -1125,16 +1099,14 @@ void tst_Tasking::testTree_data()
workflowPolicy(policy),
createFailingTask(1),
createSuccessTask(2, 1000ms),
groupDone(1),
groupError(1)
groupDone(1)
},
createFailingTask(3, 1ms),
groupDone(2),
groupError(2)
groupDone(2)
};
};
const Log shortErrorLog = {
const Log shortLog = {
{1, Handler::Setup},
{3, Handler::Setup},
{1, Handler::Error},
@@ -1143,7 +1115,7 @@ void tst_Tasking::testTree_data()
{2, Handler::GroupError}
};
const Log longErrorLog = {
const Log longLog = {
{1, Handler::Setup},
{3, Handler::Setup},
{1, Handler::Error},
@@ -1154,57 +1126,46 @@ void tst_Tasking::testTree_data()
{2, Handler::GroupError}
};
const Log doneLog = {
{1, Handler::Setup},
{3, Handler::Setup},
{1, Handler::Error},
{2, Handler::Setup},
{3, Handler::Error},
{2, Handler::Canceled},
{1, Handler::GroupSuccess},
{2, Handler::GroupError}
};
const Group root1 = createRoot(WorkflowPolicy::StopOnError);
QTest::newRow("StopGroupAfterErrorWithStopOnError")
<< TestData{storage, root1, shortErrorLog, 3, OnDone::Failure};
<< TestData{storage, root1, shortLog, 3, OnDone::Failure};
const Group root2 = createRoot(WorkflowPolicy::ContinueOnError);
QTest::newRow("StopGroupAfterErrorWithContinueOnError")
<< TestData{storage, root2, longErrorLog, 3, OnDone::Failure};
<< TestData{storage, root2, longLog, 3, OnDone::Failure};
const Group root3 = createRoot(WorkflowPolicy::StopOnDone);
QTest::newRow("StopGroupAfterErrorWithStopOnDone")
<< TestData{storage, root3, longErrorLog, 3, OnDone::Failure};
<< TestData{storage, root3, longLog, 3, OnDone::Failure};
const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone);
QTest::newRow("StopGroupAfterErrorWithContinueOnDone")
<< TestData{storage, root4, longErrorLog, 3, OnDone::Failure};
<< TestData{storage, root4, longLog, 3, OnDone::Failure};
const Group root5 = createRoot(WorkflowPolicy::StopOnFinished);
QTest::newRow("StopGroupAfterErrorWithStopOnFinished")
<< TestData{storage, root5, shortErrorLog, 3, OnDone::Failure};
<< TestData{storage, root5, shortLog, 3, OnDone::Failure};
// TODO: Behavioral change!
const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone);
QTest::newRow("StopGroupAfterErrorWithFinishAllAndDone")
<< TestData{storage, root6, doneLog, 3, OnDone::Failure};
<< TestData{storage, root6, longLog, 3, OnDone::Failure};
const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError);
QTest::newRow("StopGroupAfterErrorWithFinishAllAndError")
<< TestData{storage, root7, longErrorLog, 3, OnDone::Failure};
<< TestData{storage, root7, longLog, 3, OnDone::Failure};
}
{
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone,
groupError](WorkflowPolicy policy) {
const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone](
WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
createSuccessTask(1),
createFailingTask(2),
createSuccessTask(3),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -1266,7 +1227,7 @@ void tst_Tasking::testTree_data()
}
{
const auto createRoot = [storage, createTask, groupDone, groupError](
const auto createRoot = [storage, createTask, groupDone](
bool firstSuccess, bool secondSuccess) {
return Group {
parallel,
@@ -1274,8 +1235,7 @@ void tst_Tasking::testTree_data()
Storage(storage),
createTask(1, firstSuccess, 1000ms),
createTask(2, secondSuccess, 1ms),
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -1306,8 +1266,7 @@ void tst_Tasking::testTree_data()
}
{
const auto createRoot = [storage, createSuccessTask, groupDone, groupError](
SetupResult setupResult) {
const auto createRoot = [storage, createSuccessTask, groupDone](SetupResult setupResult) {
return Group {
Storage(storage),
Group {
@@ -1319,8 +1278,7 @@ void tst_Tasking::testTree_data()
createSuccessTask(3),
createSuccessTask(4)
},
groupDone(0),
groupError(0)
groupDone(0)
};
};
@@ -1809,7 +1767,7 @@ void tst_Tasking::testTree_data()
createSyncWithReturn(3, false),
createSuccessTask(4),
createSync(5),
groupError(0)
groupDone(0)
};
const Log log {
{1, Handler::Sync},

View File

@@ -511,7 +511,7 @@ void tst_Async::mapReduce_data()
AsyncTask<int>(std::bind(setupHandler, _1, 3), handleAsync, CallDoneIf::Success),
AsyncTask<int>(std::bind(setupHandler, _1, 4), handleAsync, CallDoneIf::Success),
AsyncTask<int>(std::bind(setupHandler, _1, 5), handleAsync, CallDoneIf::Success),
onGroupDone(doneHandler)
onGroupDone(doneHandler, CallDoneIf::Success)
};
};

View File

@@ -25,7 +25,7 @@ static QWidget *hr()
return frame;
}
QWidget *taskGroup(QWidget *groupWidget, const QList<QWidget *> &widgets)
static QWidget *taskGroup(QWidget *groupWidget, const QList<QWidget *> &widgets)
{
QWidget *widget = new QWidget;
QBoxLayout *layout = new QHBoxLayout(widget);
@@ -42,6 +42,11 @@ QWidget *taskGroup(QWidget *groupWidget, const QList<QWidget *> &widgets)
return widget;
}
static State resultToState(DoneWith result)
{
return result == DoneWith::Success ? State::Done : State::Error;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
@@ -172,8 +177,7 @@ int main(int argc, char *argv[])
const Group root {
widget->isSuccess() ? stopOnError : finishAllAndError,
TimeoutTask(setupTask),
onGroupDone([widget] { widget->setState(State::Done); }),
onGroupError([widget] { widget->setState(State::Error); })
onGroupDone([widget](DoneWith result) { widget->setState(resultToState(result)); })
};
return root;
};
@@ -183,15 +187,13 @@ int main(int argc, char *argv[])
rootGroup->executeMode(),
rootGroup->workflowPolicy(),
onGroupSetup([rootGroup] { rootGroup->setState(State::Running); }),
onGroupDone([rootGroup] { rootGroup->setState(State::Done); }),
onGroupError([rootGroup] { rootGroup->setState(State::Error); }),
onGroupDone([rootGroup](DoneWith result) { rootGroup->setState(resultToState(result)); }),
Group {
groupTask_1->executeMode(),
groupTask_1->workflowPolicy(),
onGroupSetup([groupTask_1] { groupTask_1->setState(State::Running); }),
onGroupDone([groupTask_1] { groupTask_1->setState(State::Done); }),
onGroupError([groupTask_1] { groupTask_1->setState(State::Error); }),
onGroupDone([groupTask_1](DoneWith result) { groupTask_1->setState(resultToState(result)); }),
createTask(task_1_1),
createTask(task_1_2),
@@ -203,8 +205,7 @@ int main(int argc, char *argv[])
groupTask_4->executeMode(),
groupTask_4->workflowPolicy(),
onGroupSetup([groupTask_4] { groupTask_4->setState(State::Running); }),
onGroupDone([groupTask_4] { groupTask_4->setState(State::Done); }),
onGroupError([groupTask_4] { groupTask_4->setState(State::Error); }),
onGroupDone([groupTask_4](DoneWith result) { groupTask_4->setState(resultToState(result)); }),
createTask(task_4_1),
createTask(task_4_2),
@@ -212,8 +213,7 @@ int main(int argc, char *argv[])
groupTask_4_3->executeMode(),
groupTask_4_3->workflowPolicy(),
onGroupSetup([groupTask_4_3] { groupTask_4_3->setState(State::Running); }),
onGroupDone([groupTask_4_3] { groupTask_4_3->setState(State::Done); }),
onGroupError([groupTask_4_3] { groupTask_4_3->setState(State::Error); }),
onGroupDone([groupTask_4_3](DoneWith result) { groupTask_4_3->setState(resultToState(result)); }),
createTask(task_4_3_1),
createTask(task_4_3_2),

View File

@@ -20,8 +20,9 @@ QT_END_NAMESPACE
enum class State {
Initial,
Running,
Done,
Error
Done, // TODO: Rename to Success
Error,
// TODO: Add Canceled state
};
enum class ExecuteMode {

View File

@@ -68,7 +68,7 @@ void Images::process()
finishAllAndDone,
parallel,
onGroupSetup(onRootSetup),
onGroupDone(onRootDone)
onGroupDone(onRootDone, CallDoneIf::Success)
};
int i = 0;