diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 02a3aba804d..46c5f217a4c 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -207,13 +207,12 @@ public: : m_type(Type::Storage) , m_storageList{storage} {} - GroupItem(const Loop &loop) : GroupItem(GroupData{{}, {}, {}, loop}) {} - // TODO: Add tests. GroupItem(const QList &children) : m_type(Type::List) { addChildren(children); } GroupItem(std::initializer_list children) : m_type(Type::List) { addChildren(children); } protected: + GroupItem(const Loop &loop) : GroupItem(GroupData{{}, {}, {}, loop}) {} // Internal, provided by CustomTask using InterfaceCreateHandler = std::function; // Called prior to task start, just after createHandler @@ -274,6 +273,7 @@ protected: private: friend class ContainerNode; + friend class For; friend class TaskNode; friend class TaskTreePrivate; friend class ParallelLimitFunctor; @@ -433,11 +433,42 @@ TASKING_EXPORT extern const GroupItem nullItem; TASKING_EXPORT extern const ExecutableItem successItem; TASKING_EXPORT extern const ExecutableItem errorItem; -class TASKING_EXPORT Forever final : public Group +class TASKING_EXPORT For : public Group { public: - Forever(const QList &children) : Group({LoopForever(), children}) {} - Forever(std::initializer_list children) : Group({LoopForever(), children}) {} + template + For(const Loop &loop, const Args &...args) + : Group(withLoop(loop, args...)) { } + +protected: + For(const Loop &loop, const QList &children) : Group({loop, children}) {} + For(const Loop &loop, std::initializer_list children) : Group({loop, children}) {} + +private: + template + QList withLoop(const Loop &loop, const Args &...args) { + QList children{GroupItem(loop)}; + appendChildren(std::make_tuple(args...), &children); + return children; + } + + template + void appendChildren(const Tuple &tuple, QList *children) { + constexpr auto TupleSize = std::tuple_size_v; + if constexpr (TupleSize > 0) { + // static_assert(workflowPolicyCount() <= 1, "Too many workflow policies in one group."); + children->append(std::get(tuple)); + if constexpr (N + 1 < TupleSize) + appendChildren(tuple, children); + } + } +}; + +class TASKING_EXPORT Forever final : public For +{ +public: + Forever(const QList &children) : For(LoopForever(), children) {} + Forever(std::initializer_list children) : For(LoopForever(), children) {} }; // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 2e24eae73a8..ffce38534f8 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -830,9 +830,9 @@ AndroidDeviceManagerInstance::AndroidDeviceManagerInstance(QObject *parent) // otherwise, Android Studio would give an error during parsing also. So this fix // aim to keep support for Qt Creator and Android Studio. - m_avdListRecipe = Group { - storage, + m_avdListRecipe = For { iterator, + storage, ProcessTask(onProcessSetup, onProcessDone) }; } diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index 5570e540966..bb492a0884b 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -179,20 +179,19 @@ void AndroidQmlPreviewWorker::startPidWatcher() const TimeoutTask timeout([](std::chrono::milliseconds &timeout) { timeout = 2s; }); - const Group root { - Group { + const Group recipe { + For { pidIterator, ProcessTask(onPidSetup, onPidDone, CallDoneIf::Success), timeout }.withTimeout(20s), - Group { + For { alivePidIterator, ProcessTask(onPidSetup, onAlivePidDone), timeout } }; - - m_pidRunner.start(root); + m_pidRunner.start(recipe); } void AndroidQmlPreviewWorker::startLogcat() diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 47b1f4b1155..be9bd06e763 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -294,14 +294,14 @@ static GroupItem installationRecipe(const Storage &dialogStorage, return Group { onGroupSetup(onSetup), - Group { - finishAllAndSuccess, + For { uninstallIterator, + finishAllAndSuccess, ProcessTask(onUninstallSetup, onDone) }, - Group { - finishAllAndSuccess, + For { installIterator, + finishAllAndSuccess, ProcessTask(onInstallSetup, onDone) } }; diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 817768e176b..db32e10f235 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -417,14 +417,14 @@ void TestCodeParser::scanForTests(const QSet &filePaths, if (!results.isEmpty()) emit testParseResultsReady(results); }; - const Group root { + const For recipe { + LoopRepeat(filteredFiles.size()), parallelLimit(limit), storage, onGroupSetup([storage, filteredFiles] { *storage = filteredFiles.cbegin(); }), - LoopRepeat(filteredFiles.size()), AsyncTask(onSetup, onDone, CallDoneIf::Success) }; - m_taskTreeRunner.start(root); + m_taskTreeRunner.start(recipe); } void TestCodeParser::onTaskStarted(Id type) diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 6c8f19c1bb1..49bbbd4e920 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -459,15 +459,15 @@ void TestRunner::runTestsHelper() } }; - const Group root { - finishAllAndSuccess, + const For recipe { iterator, + finishAllAndSuccess, Group { storage, ProcessTask(onSetup, onDone) } }; - m_taskTreeRunner.start(root); + m_taskTreeRunner.start(recipe); } static void processOutput(TestOutputReader *outputreader, const QString &msg, OutputFormat format) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index e7bb3d176ed..9cb0f172fc4 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -691,7 +691,7 @@ static Group authorizationRecipe() *serverUrlStorage = unauthorizedDashboardStorage->url; }), }, - Group { + For { LoopUntil(onCredentialLoopCondition), CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone), Group { diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 08858a0498e..9a190b2499b 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -224,10 +224,10 @@ GroupItem clangToolTask(const AnalyzeUnits &units, error}); }; - return Group { + return For { + iterator, parallelLimit(qMax(1, input.runSettings.parallelJobs())), finishAllAndSuccess, - iterator, Group { storage, onGroupSetup(onSetup), diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 6a32b294a3d..44e3e0181b9 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -383,9 +383,9 @@ void LocatorMatcher::start() parallel, collectorStorage, AsyncTask(onCollectorSetup, onCollectorDone), - Group { - parallelLimit(d->m_parallelLimit), + For { iterator, + parallelLimit(d->m_parallelLimit), TaskTreeTask(onTaskTreeSetup) } }; diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 3606a5ebc84..3bc20607840 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -142,16 +142,16 @@ DiffFilesController::DiffFilesController(IDocument *document) setDiffFiles(finalList); }; - const Group root { + const For recipe { + iterator, parallelIdealThreadCountLimit, finishAllAndSuccess, storage, - iterator, onGroupSetup(onSetup), AsyncTask(onDiffSetup, onDiffDone, CallDoneIf::Success), onGroupDone(onDone) }; - setReloadRecipe(root); + setReloadRecipe(recipe); } class DiffCurrentFileController : public DiffFilesController diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index b1ad8140fe8..10cf2dcecdc 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -506,10 +506,10 @@ ShowController::ShowController(IDocument *document, const QString &id) updateDescription(*data); }; - const Group recipe { + const For recipe { + iterator, parallel, continueOnSuccess, - iterator, ProcessTask(onFollowSetup, onFollowDone, CallDoneIf::Success), onGroupDone(onDone, CallDoneIf::Error) }; diff --git a/src/plugins/lua/bindings/install.cpp b/src/plugins/lua/bindings/install.cpp index 076cf63b9fa..a5e77d1e521 100644 --- a/src/plugins/lua/bindings/install.cpp +++ b/src/plugins/lua/bindings/install.cpp @@ -196,10 +196,10 @@ static Group installRecipe( return DoneResult::Success; }; - return Group{ + return For { + installOptionsIt, storage, parallelIdealThreadCountLimit, - installOptionsIt, Group{ onGroupSetup([emitResult, storage, installOptionsIt] { const QString fileName = installOptionsIt->url.fileName(); diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index 4411184c923..42fab5d0bad 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -237,12 +237,12 @@ static QList scanForFilesHelper( } }; - const Group group{ - Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit, + const For recipe { iterator, + Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit, Utils::AsyncTask(onSetup, onDone) }; - TaskTree::runBlocking(group); + TaskTree::runBlocking(recipe); } return fileNodes; } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 3fd4f0db738..036376c67af 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1679,21 +1679,21 @@ private: } }; - const Group group{ - Group{ - parallelIdealThreadCountLimit, + const Group recipe { + For { iteratorParentDirs, + parallelIdealThreadCountLimit, AsyncTask>(onCreateDirSetup, onCreateDirDone), }, - Group{ - parallelLimit(2), + For { iterator, + parallelLimit(2), counterStorage, AsyncTask>(onCopySetup, onCopyDone), }, }; - m_taskTree.start(group, {}, [this](DoneWith result) { + m_taskTree.start(recipe, {}, [this](DoneWith result) { ProcessResultData resultData; if (result != DoneWith::Success) { resultData.m_exitCode = -1; diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index f2900a22158..897094490d0 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -278,15 +278,14 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const emit q->errorMessage(message); }; - const Group root { + return For { + iterator, continueOnError, onGroupSetup([this] { emit q->progressMessage(Tr::tr("Checking if required commands are available...")); }), - iterator, ProcessTask(onSetup, onDone) }; - return root; } } // namespace Internal diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 316bfac7736..cfe47dd2f13 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2735,12 +2735,12 @@ void tst_Tasking::testTree_data() { const QList successItems { storage, - LoopRepeat(2), createSuccessTask(1), createSuccessTask(2) }; - const Group rootSequentialSuccess { + const For rootSequentialSuccess { + LoopRepeat(2), sequential, successItems }; @@ -2755,7 +2755,8 @@ void tst_Tasking::testTree_data() {2, Handler::Success} }; - const Group rootParallelSuccess { + const For rootParallelSuccess { + LoopRepeat(2), parallel, successItems }; @@ -2770,7 +2771,8 @@ void tst_Tasking::testTree_data() {2, Handler::Success} }; - const Group rootParallelLimitSuccess { + const For rootParallelLimitSuccess { + LoopRepeat(2), parallelLimit(2), successItems }; @@ -2787,12 +2789,12 @@ void tst_Tasking::testTree_data() const QList errorItems { storage, - LoopRepeat(2), createSuccessTask(1), createFailingTask(2) }; - const Group rootSequentialError { + const For rootSequentialError { + LoopRepeat(2), sequential, errorItems }; @@ -2803,7 +2805,8 @@ void tst_Tasking::testTree_data() {2, Handler::Error} }; - const Group rootParallelError { + const For rootParallelError { + LoopRepeat(2), parallel, errorItems }; @@ -2818,7 +2821,8 @@ void tst_Tasking::testTree_data() {2, Handler::Canceled} }; - const Group rootParallelLimitError { + const For rootParallelLimitError { + LoopRepeat(2), parallelLimit(2), errorItems }; @@ -2873,12 +2877,12 @@ void tst_Tasking::testTree_data() const QList items { storage, - loop, TestTask(onSetupContinue(1), onDone(1)), TestTask(onSetupStop(2), onDone(2)) }; - const Group rootSequential { + const For rootSequential { + loop, sequential, items }; @@ -2896,7 +2900,8 @@ void tst_Tasking::testTree_data() {22, Handler::Setup} }; - const Group rootParallel { + const For rootParallel { + loop, parallel, items }; @@ -2914,7 +2919,8 @@ void tst_Tasking::testTree_data() {21, Handler::Success} }; - const Group rootParallelLimit { + const For rootParallelLimit { + loop, parallelLimit(2), items }; @@ -2942,9 +2948,9 @@ void tst_Tasking::testTree_data() { // Check if task tree finishes with the right progress value when LoopUntil(false). - const Group root { - storage, + const For root { LoopUntil([](int) { return false; }), + storage, createSuccessTask(1) }; QTest::newRow("ProgressWithLoopUntilFalse") @@ -2953,10 +2959,10 @@ void tst_Tasking::testTree_data() { // Check if task tree finishes with the right progress value when nested LoopUntil(false). - const Group root { - storage, + const For root { LoopUntil([](int index) { return index < 2; }), - Group { + storage, + For { LoopUntil([](int) { return false; }), createSuccessTask(1) } @@ -2978,9 +2984,9 @@ void tst_Tasking::testTree_data() { // Check if task tree finishes with the right progress value when nested LoopUntil(false). - const Group root { - storage, + const For root { LoopUntil([](int index) { return index < 2; }), + storage, Group { onGroupSetup([] { return SetupResult::StopWithSuccess; }), createSuccessTask(1) @@ -3157,10 +3163,10 @@ void tst_Tasking::testTree_data() return DoneResult::Error; }; - const Group root { + const For root { + iterator, storage, parallel, - iterator, TestTask(onSetup, onDone) }; diff --git a/tests/manual/tasking/assetdownloader/assetdownloader.cpp b/tests/manual/tasking/assetdownloader/assetdownloader.cpp index 90fa21837cb..b5daf6d4318 100644 --- a/tests/manual/tasking/assetdownloader/assetdownloader.cpp +++ b/tests/manual/tasking/assetdownloader/assetdownloader.cpp @@ -509,9 +509,9 @@ void AssetDownloader::start() onGroupSetup(onSkipIfAllAssetsPresent), NetworkQueryTask(onZipDownloadSetup, onZipDownloadDone), ConcurrentCallTask(onUnzipSetup, onUnzipDone), - Group { - parallelIdealThreadCountLimit, + For { downloadIterator, + parallelIdealThreadCountLimit, onGroupSetup(onAssetsDownloadGroupSetup), Group { assetStorage, @@ -519,9 +519,9 @@ void AssetDownloader::start() ConcurrentCallTask(onAssetWriteSetup, onAssetWriteDone) } }, - Group { - parallelIdealThreadCountLimit, + For { copyIterator, + parallelIdealThreadCountLimit, onGroupSetup(onAssetsCopyGroupSetup), ConcurrentCallTask(onAssetCopySetup, onAssetCopyDone) } diff --git a/tests/manual/tasking/dataexchange/recipe.cpp b/tests/manual/tasking/dataexchange/recipe.cpp index 78682b19e66..c326d48d3e2 100644 --- a/tests/manual/tasking/dataexchange/recipe.cpp +++ b/tests/manual/tasking/dataexchange/recipe.cpp @@ -74,7 +74,7 @@ Group recipe(const Storage &externalStorage) internalStorage, NetworkQueryTask(onDownloadSetup, onDownloadDone), ConcurrentCallTask(onReadSetup, onReadDone), - Group { + For { repeater, parallelIdealThreadCountLimit, ConcurrentCallTask(onScaleSetup, onScaleDone) diff --git a/tests/manual/tasking/imagescaling/imagescaling.cpp b/tests/manual/tasking/imagescaling/imagescaling.cpp index 186042435ec..ca9840269d9 100644 --- a/tests/manual/tasking/imagescaling/imagescaling.cpp +++ b/tests/manual/tasking/imagescaling/imagescaling.cpp @@ -93,10 +93,10 @@ void Images::process() labels[it]->setText(tr("Image\nData\nError.")); }; - const QList tasks { + const For recipe { + iterator, finishAllAndSuccess, parallel, - iterator, onGroupSetup(onRootSetup), Group { storage, @@ -105,8 +105,7 @@ void Images::process() }, onGroupDone(onRootDone, CallDoneIf::Success) }; - - taskTreeRunner.start(tasks); + taskTreeRunner.start(recipe); } void Images::initLayout(qsizetype count)