diff options
-rw-r--r-- | src/lib/corelib/buildgraph/buildgraphloader.cpp | 1 | ||||
-rw-r--r-- | src/lib/corelib/language/evaluator.cpp | 2 | ||||
-rw-r--r-- | src/lib/corelib/language/language.cpp | 11 | ||||
-rw-r--r-- | src/lib/corelib/language/language.h | 13 | ||||
-rw-r--r-- | src/lib/corelib/language/loader.cpp | 1 | ||||
-rw-r--r-- | src/lib/corelib/language/loader.h | 3 | ||||
-rw-r--r-- | src/lib/corelib/language/moduleloader.cpp | 40 | ||||
-rw-r--r-- | src/lib/corelib/language/moduleloader.h | 8 | ||||
-rw-r--r-- | src/lib/corelib/language/scriptengine.cpp | 1 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs | 21 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/import-change-tracking/probe1.js | 3 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/import-change-tracking/probe2.js | 1 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackbox.cpp | 41 |
13 files changed, 122 insertions, 24 deletions
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp index df9a234da..d459a1a10 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.cpp +++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp @@ -336,6 +336,7 @@ void BuildGraphLoader::trackProjectChanges() ldr.setSearchPaths(m_parameters.searchPaths()); ldr.setProgressObserver(m_evalContext->observer()); ldr.setOldProjectProbes(restoredProject->probes); + ldr.setLastResolveTime(restoredProject->lastResolveTime); QHash<QString, QList<ProbeConstPtr>> restoredProbes; for (const auto &restoredProduct : qAsConst(allRestoredProducts)) restoredProbes.insert(restoredProduct->uniqueName(), restoredProduct->probes); diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp index 61bf4f96d..cd0513b5c 100644 --- a/src/lib/corelib/language/evaluator.cpp +++ b/src/lib/corelib/language/evaluator.cpp @@ -248,7 +248,7 @@ Evaluator::FileContextScopes Evaluator::fileContextScopes(const FileContextConst try { result.importScope = m_scriptEngine->newObject(); setupScriptEngineForFile(m_scriptEngine, file, result.importScope, - ObserveMode::Disabled); // TODO: Probes need to enable this + ObserveMode::Enabled); } catch (const ErrorInfo &e) { result.importScope = m_scriptEngine->currentContext()->throwError(e.toString()); } diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 9b71dbf00..854bfbb68 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -125,6 +125,15 @@ void FileTagger::store(PersistentPool &pool) const } +bool Probe::needsReconfigure(const FileTime &referenceTime) const +{ + const auto criterion = [referenceTime](const QString &filePath) { + FileInfo fi(filePath); + return !fi.exists() || fi.lastModified() > referenceTime; + }; + return std::any_of(m_importedFilesUsed.cbegin(), m_importedFilesUsed.cend(), criterion); +} + void Probe::load(PersistentPool &pool) { pool.load(m_globalId); @@ -133,6 +142,7 @@ void Probe::load(PersistentPool &pool) pool.load(m_configureScript); pool.load(m_properties); pool.load(m_initialProperties); + pool.load(m_importedFilesUsed); } void Probe::store(PersistentPool &pool) const @@ -143,6 +153,7 @@ void Probe::store(PersistentPool &pool) const pool.store(m_configureScript); pool.store(m_properties); pool.store(m_initialProperties); + pool.store(m_importedFilesUsed); } diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index e78e4a137..c551a9ff0 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -63,6 +63,7 @@ #include <memory> #include <mutex> +#include <vector> QT_BEGIN_NAMESPACE class QScriptEngine; @@ -110,10 +111,11 @@ public: bool condition, const QString &configureScript, const QVariantMap &properties, - const QVariantMap &initialProperties) + const QVariantMap &initialProperties, + const std::vector<QString> &importedFilesUsed) { return ProbeConstPtr(new Probe(globalId, location, condition, configureScript, properties, - initialProperties)); + initialProperties, importedFilesUsed)); } const QString &globalId() const { return m_globalId; } @@ -121,6 +123,8 @@ public: const QString &configureScript() const { return m_configureScript; } const QVariantMap &properties() const { return m_properties; } const QVariantMap &initialProperties() const { return m_initialProperties; } + const std::vector<QString> &importedFilesUsed() const { return m_importedFilesUsed; } + bool needsReconfigure(const FileTime &referenceTime) const; private: Probe() {} @@ -129,12 +133,14 @@ private: bool condition, const QString &configureScript, const QVariantMap &properties, - const QVariantMap &initialProperties) + const QVariantMap &initialProperties, + const std::vector<QString> &importedFilesUsed) : m_globalId(globalId) , m_location(location) , m_configureScript(configureScript) , m_properties(properties) , m_initialProperties(initialProperties) + , m_importedFilesUsed(importedFilesUsed) , m_condition(condition) {} @@ -146,6 +152,7 @@ private: QString m_configureScript; QVariantMap m_properties; QVariantMap m_initialProperties; + std::vector<QString> m_importedFilesUsed; bool m_condition; }; diff --git a/src/lib/corelib/language/loader.cpp b/src/lib/corelib/language/loader.cpp index 77af576d1..beddd6e49 100644 --- a/src/lib/corelib/language/loader.cpp +++ b/src/lib/corelib/language/loader.cpp @@ -158,6 +158,7 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &_parameters moduleLoader.setSearchPaths(m_searchPaths); moduleLoader.setOldProjectProbes(m_oldProjectProbes); moduleLoader.setOldProductProbes(m_oldProductProbes); + moduleLoader.setLastResolveTime(m_lastResolveTime); moduleLoader.setStoredProfiles(m_storedProfiles); const ModuleLoaderResult loadResult = moduleLoader.load(parameters); ProjectResolver resolver(&evaluator, loadResult, parameters, m_logger); diff --git a/src/lib/corelib/language/loader.h b/src/lib/corelib/language/loader.h index c07380639..45faf74c9 100644 --- a/src/lib/corelib/language/loader.h +++ b/src/lib/corelib/language/loader.h @@ -41,6 +41,7 @@ #include "forward_decls.h" #include <logging/logger.h> +#include <tools/filetime.h> #include <QtCore/qstringlist.h> @@ -61,6 +62,7 @@ public: void setSearchPaths(const QStringList &searchPaths); void setOldProjectProbes(const QList<ProbeConstPtr> &oldProbes); void setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>> &oldProbes); + void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; } void setStoredProfiles(const QVariantMap &profiles); TopLevelProjectPtr loadProject(const SetupProjectParameters ¶meters); @@ -74,6 +76,7 @@ private: QList<ProbeConstPtr> m_oldProjectProbes; QHash<QString, QList<ProbeConstPtr>> m_oldProductProbes; QVariantMap m_storedProfiles; + FileTime m_lastResolveTime; }; } // namespace Internal diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index ba3850f2f..b00b735a9 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -113,21 +113,6 @@ static QString probeGlobalId(Item *probe) return id + QLatin1Char('_') + probe->file()->filePath(); } -enum class CompareScript { No, Yes }; - -static bool probeEqualTo( - const ProbeConstPtr &probe, - bool condition, - const QVariantMap &initialProperties, - const QString &configureScript, - CompareScript compareScript) -{ - return probe->condition() == condition - && probe->initialProperties() == initialProperties - && (compareScript == CompareScript::No - || probe->configureScript() == configureScript); -} - class ModuleLoader::ProductSortByDependencies { public: @@ -1480,7 +1465,7 @@ ProbeConstPtr ModuleLoader::findOldProjectProbe( return ProbeConstPtr(); for (const ProbeConstPtr &oldProbe : m_oldProjectProbes.value(globalId)) { - if (probeEqualTo(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes)) + if (probeMatches(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes)) return oldProbe; } @@ -1497,7 +1482,7 @@ ProbeConstPtr ModuleLoader::findOldProductProbe( return ProbeConstPtr(); for (const ProbeConstPtr &oldProbe : m_oldProductProbes.value(productName)) { - if (probeEqualTo(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes)) + if (probeMatches(oldProbe, condition, initialProperties, sourceCode, CompareScript::Yes)) return oldProbe; } @@ -1511,12 +1496,23 @@ ProbeConstPtr ModuleLoader::findCurrentProbe( { const QList<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location); for (const ProbeConstPtr &probe : cachedProbes) { - if (probeEqualTo(probe, condition, initialProperties, QString(), CompareScript::No)) + if (probeMatches(probe, condition, initialProperties, QString(), CompareScript::No)) return probe; } return ProbeConstPtr(); } +bool ModuleLoader::probeMatches(const ProbeConstPtr &probe, bool condition, + const QVariantMap &initialProperties, const QString &configureScript, + CompareScript compareScript) const +{ + return probe->condition() == condition + && probe->initialProperties() == initialProperties + && (compareScript == CompareScript::No + || (probe->configureScript() == configureScript + && !probe->needsReconfigure(m_lastResolveTime))); +} + void ModuleLoader::printProfilingInfo() { if (!m_parameters.logElapsedTime()) @@ -2972,13 +2968,18 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It if (!resolvedProbe) resolvedProbe = findCurrentProbe(probe->location(), condition, initialProperties); ErrorInfo evalError; + std::vector<QString> importedFilesUsedInConfigure; if (!condition) { qCDebug(lcModuleLoader) << "Probe disabled; skipping"; } else if (!resolvedProbe) { + engine->clearRequestedProperties(); QScriptValue sv = engine->evaluate(configureScript->sourceCodeForEvaluation()); engine->releaseResourcesOfScriptObjects(); if (Q_UNLIKELY(engine->hasErrorOrException(sv))) evalError = engine->lastError(sv, configureScript->location()); + importedFilesUsedInConfigure = engine->importedFilesUsedInScript(); + } else { + importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed(); } QVariantMap properties; if (!evalError.hasError()) { @@ -3010,7 +3011,8 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It throw evalError; if (!resolvedProbe) { resolvedProbe = Probe::create(probeId, probe->location(), condition, - sourceCode, properties, initialProperties); + sourceCode, properties, initialProperties, + importedFilesUsedInConfigure); m_currentProbes[probe->location()] << resolvedProbe; } productContext->info.probes << resolvedProbe; diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h index d035e1a55..19afbca17 100644 --- a/src/lib/corelib/language/moduleloader.h +++ b/src/lib/corelib/language/moduleloader.h @@ -45,6 +45,7 @@ #include "item.h" #include "itempool.h" #include <logging/logger.h> +#include <tools/filetime.h> #include <tools/set.h> #include <tools/setupprojectparameters.h> #include <tools/version.h> @@ -125,6 +126,7 @@ public: void setSearchPaths(const QStringList &searchPaths); void setOldProjectProbes(const QList<ProbeConstPtr> &oldProbes); void setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>> &oldProbes); + void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; } void setStoredProfiles(const QVariantMap &profiles); Evaluator *evaluator() const { return m_evaluator; } @@ -322,6 +324,11 @@ private: ProbeConstPtr findCurrentProbe(const CodeLocation &location, bool condition, const QVariantMap &initialProperties) const; + enum class CompareScript { No, Yes }; + bool probeMatches(const ProbeConstPtr &probe, bool condition, + const QVariantMap &initialProperties, const QString &configureScript, + CompareScript compareScript) const; + void printProfilingInfo(); void handleProductError(const ErrorInfo &error, ProductContext *productContext); QualifiedIdSet gatherModulePropertiesSetInGroup(const Item *group); @@ -361,6 +368,7 @@ private: QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes; QHash<QString, QList<ProbeConstPtr>> m_oldProductProbes; + FileTime m_lastResolveTime; QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes; QVariantMap m_storedProfiles; QVariantMap m_localProfiles; diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index eac65018e..b1c6d1410 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -133,7 +133,6 @@ void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, QScriptValue & installImportFunctions(); m_currentDirPathStack.push(FileInfo::path(fileCtx->filePath())); m_extensionSearchPathsStack.push(fileCtx->searchPaths()); - m_importsObserver->clearImportIds(); m_observeMode = observeMode; for (const JsImport &jsImport : fileCtx->jsImports()) diff --git a/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs index f7e9bc5de..c229de889 100644 --- a/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs +++ b/tests/auto/blackbox/testdata/import-change-tracking/import-change-tracking-product.qbs @@ -2,12 +2,14 @@ import qbs import "irrelevant.js" as Irrelevant import "custom1prepare1.js" as Custom1Prepare import "custom2prepare" as Custom2Prepare +import "probe1.js" as ProbeFunc Product { name: "customProduct" type: ["custom1", "custom2"] property string irrelevant: Irrelevant.irrelevant() + property string dummy: probe1.result Group { files: "input1.txt" @@ -34,4 +36,23 @@ Product { return Custom2Prepare.prepare(); } } + + Probe { + id: probe1 + property string input: Irrelevant.irrelevant() + property string result + configure: { + found = true; + console.info("running probe1"); + return ProbeFunc.probe1Func(); + } + } + + Probe { + id: probe2 + configure: { + console.info("running probe2"); + found = true; + } + } } diff --git a/tests/auto/blackbox/testdata/import-change-tracking/probe1.js b/tests/auto/blackbox/testdata/import-change-tracking/probe1.js new file mode 100644 index 000000000..f9cb64dd0 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/probe1.js @@ -0,0 +1,3 @@ +var Probe2 = require("./probe2.js") + +function probe1Func() { return Probe2.probe2Func(); } diff --git a/tests/auto/blackbox/testdata/import-change-tracking/probe2.js b/tests/auto/blackbox/testdata/import-change-tracking/probe2.js new file mode 100644 index 000000000..563ba6b93 --- /dev/null +++ b/tests/auto/blackbox/testdata/import-change-tracking/probe2.js @@ -0,0 +1 @@ +function probe2Func() { return "probeData"; } diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 15440f838..8f5f73dc6 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -5539,6 +5539,8 @@ void TestBlackbox::importChangeTracking() QDir::setCurrent(testDataDir + "/import-change-tracking"); QCOMPARE(runQbs(QStringList({"-f", "import-change-tracking.qbs"})), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); @@ -5549,6 +5551,8 @@ void TestBlackbox::importChangeTracking() touch("irrelevant.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); @@ -5559,6 +5563,8 @@ void TestBlackbox::importChangeTracking() touch("custom1prepare1.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); @@ -5568,6 +5574,8 @@ void TestBlackbox::importChangeTracking() touch("custom1prepare2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); @@ -5577,6 +5585,8 @@ void TestBlackbox::importChangeTracking() touch("custom1command.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); @@ -5585,6 +5595,8 @@ void TestBlackbox::importChangeTracking() touch("custom2prepare/custom2prepare2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); @@ -5594,9 +5606,35 @@ void TestBlackbox::importChangeTracking() touch("imports/custom2command/custom2command1.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe1 "), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + // Change in directly imported file only used by one Probe + WAIT_FOR_NEW_TIMESTAMP(); + touch("probe1.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + + // Change in indirectly imported file only used by one Probe + WAIT_FOR_NEW_TIMESTAMP(); + touch("probe2.js"); + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running custom2 command"), m_qbsStdout.constData()); + // Change everything at once. WAIT_FOR_NEW_TIMESTAMP(); touch("irrelevant.js"); @@ -5605,8 +5643,11 @@ void TestBlackbox::importChangeTracking() touch("custom1command.js"); touch("custom2prepare/custom2prepare1.js"); touch("imports/custom2command/custom2command2.js"); + touch("probe2.js"); QCOMPARE(runQbs(), 0); QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("running probe1"), m_qbsStdout.constData()); + QVERIFY2(!m_qbsStdout.contains("running probe2"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom2 prepare script"), m_qbsStdout.constData()); QVERIFY2(m_qbsStdout.contains("running custom1 command"), m_qbsStdout.constData()); |