aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIvan Komissarov <abbapoh@gmail.com>2020-09-26 18:49:26 +0200
committerIvan Komissarov <ABBAPOH@gmail.com>2021-09-20 08:48:39 +0000
commit19090f5ff1681503096e8797159e773600692903 (patch)
treeb34f68e51ef22486fc64d7409d856fd9c486b54d /src
parentb70bd9531f73382fe7ec1e1c7179d1d7aba92e58 (diff)
Implement qbsModuleProviders property
It is now possible to specify which providers should be run by providing the list of provider names. The desired providers can be selected on the Project and Product levels. Task-number: QBS-1604 Change-Id: Ib0782df00e3086104345f4b740fc1696d715344c Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp4
-rw-r--r--src/lib/corelib/language/evaluator.cpp9
-rw-r--r--src/lib/corelib/language/evaluator.h3
-rw-r--r--src/lib/corelib/language/moduleloader.cpp2
-rw-r--r--src/lib/corelib/language/moduleproviderloader.cpp148
-rw-r--r--src/lib/corelib/language/moduleproviderloader.h14
-rw-r--r--src/lib/corelib/tools/stringconstants.h1
7 files changed, 130 insertions, 51 deletions
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 13783d3b9..7266333f5 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -433,6 +433,8 @@ void BuiltinDeclarations::addProductItem()
item << PropertyDeclaration(StringConstants::multiplexConfigurationIdProperty(),
PropertyDeclaration::String, QString(),
PropertyDeclaration::ReadOnlyFlag);
+ item << PropertyDeclaration(StringConstants::qbsModuleProviders(),
+ PropertyDeclaration::StringList);
insert(item);
}
@@ -473,6 +475,8 @@ void BuiltinDeclarations::addProjectItem()
item << PropertyDeclaration(StringConstants::qbsSearchPathsProperty(),
PropertyDeclaration::StringList,
QString(), PropertyDeclaration::PropertyNotAvailableInConfig);
+ item << PropertyDeclaration(StringConstants::qbsModuleProviders(),
+ PropertyDeclaration::StringList);
insert(item);
}
diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp
index 5ea506d6a..b6fa06c8c 100644
--- a/src/lib/corelib/language/evaluator.cpp
+++ b/src/lib/corelib/language/evaluator.cpp
@@ -135,10 +135,19 @@ static QStringList toStringList(const QScriptValue &scriptValue)
QStringList Evaluator::stringListValue(const Item *item, const QString &name, bool *propertyWasSet)
{
+ const auto result = optionalStringListValue(item, name, propertyWasSet);
+ return result ? *result : QStringList();
+}
+
+std::optional<QStringList> Evaluator::optionalStringListValue(
+ const Item *item, const QString &name, bool *propertyWasSet)
+{
QScriptValue v = property(item, name);
handleEvaluationError(item, name, v);
if (propertyWasSet)
*propertyWasSet = isNonDefaultValue(item, name);
+ if (v.isUndefined())
+ return std::nullopt;
return toStringList(v);
}
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index f8535d0d7..1e21391dc 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -49,6 +49,7 @@
#include <QtScript/qscriptvalue.h>
#include <functional>
+#include <optional>
namespace qbs {
namespace Internal {
@@ -78,6 +79,8 @@ public:
const QString &defaultValue = QString(), bool *propertyWasSet = nullptr);
QStringList stringListValue(const Item *item, const QString &name,
bool *propertyWasSet = nullptr);
+ std::optional<QStringList> optionalStringListValue(const Item *item, const QString &name,
+ bool *propertyWasSet = nullptr);
void convertToPropertyType(const PropertyDeclaration& decl, const CodeLocation &loc,
QScriptValue &v);
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 5c2c376f5..7f61df6b2 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -3114,7 +3114,7 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
if (existingPaths.isEmpty()) { // no suitable names found, try to use providers
AccumulatingTimer providersTimer(
m_parameters.logElapsedTime() ? &m_elapsedTimeModuleProviders : nullptr);
- const auto result = m_moduleProviderLoader->executeModuleProvider(
+ auto result = m_moduleProviderLoader->executeModuleProvider(
*productContext,
dependsItemLocation,
moduleName,
diff --git a/src/lib/corelib/language/moduleproviderloader.cpp b/src/lib/corelib/language/moduleproviderloader.cpp
index 48eaba0c9..f036e36ab 100644
--- a/src/lib/corelib/language/moduleproviderloader.cpp
+++ b/src/lib/corelib/language/moduleproviderloader.cpp
@@ -72,58 +72,87 @@ ModuleProviderLoader::ModuleProviderResult ModuleProviderLoader::executeModulePr
const QualifiedId &moduleName,
FallbackMode fallbackMode)
{
- ModuleProviderResult result;
- for (QualifiedId providerName = moduleName; !providerName.empty();
- providerName.pop_back()) {
- qCDebug(lcModuleLoader) << "Module" << moduleName.toString()
- << "not found, checking for module providers";
- result = findModuleProvider(providerName, productContext,
- ModuleProviderLookup::Regular, dependsItemLocation);
- if (result.providerFound)
- break;
+ ModuleProviderLoader::ModuleProviderResult result;
+ std::vector<Provider> providersToRun;
+ qCDebug(lcModuleLoader) << "Module" << moduleName.toString()
+ << "not found, checking for module providers";
+ const auto providerNames = getModuleProviders(productContext.item);
+ if (providerNames) {
+ for (const auto &providerName : *providerNames)
+ providersToRun.push_back({providerName, ModuleProviderLookup::Named});
+ } else {
+ for (QualifiedId providerName = moduleName; !providerName.empty();
+ providerName.pop_back()) {
+ providersToRun.push_back({providerName, ModuleProviderLookup::Scoped});
+ }
}
- if (fallbackMode == FallbackMode::Enabled && !result.providerFound) {
- qCDebug(lcModuleLoader) << "Specific module provider not found for"
+ result = findModuleProvider(providersToRun, productContext, dependsItemLocation);
+
+ if (fallbackMode == FallbackMode::Enabled
+ && !result.providerFound
+ && !providerNames) {
+ qCDebug(lcModuleLoader) << "Specific module provider not found for"
<< moduleName.toString() << ", setting up fallback.";
- result = findModuleProvider(moduleName, productContext,
- ModuleProviderLookup::Fallback, dependsItemLocation);
+ result = findModuleProvider(
+ {{moduleName, ModuleProviderLookup::Fallback}},
+ productContext,
+ dependsItemLocation);
}
+
return result;
}
ModuleProviderLoader::ModuleProviderResult ModuleProviderLoader::findModuleProvider(
- const QualifiedId &name,
+ const std::vector<Provider> &providers,
ProductContext &product,
- ModuleProviderLookup lookupType,
const CodeLocation &dependsItemLocation)
{
- const QVariantMap config = moduleProviderConfig(product).value(name.toString()).toMap();
- ModuleProviderInfo &info =
- m_storedModuleProviderInfo.providers[{name.toString(), config, int(lookupType)}];
- if (info.name.isEmpty()) { // not found in cache
- info.name = name;
- info.config = config;
- info.providerFile = findModuleProviderFile(name, lookupType);
- if (info.providerFile.isEmpty())
- return {};
- info.searchPaths = getProviderSearchPaths(
- name, info.providerFile, product, config, dependsItemLocation);
- info.transientOutput = m_parameters.dryRun();
- } else {
- if (info.providerFile.isEmpty())
- return {};
- qCDebug(lcModuleLoader) << "Re-using provider" << name << "from cache";
- }
- if (info.searchPaths.empty()) {
- qCDebug(lcModuleLoader) << "Module provider did run, but did not set up "
- "any modules.";
- return {true, false};
+ if (providers.empty())
+ return {};
+ QStringList allSearchPaths;
+ ModuleProviderResult result;
+ for (const auto &[name, lookupType] : providers) {
+ const QVariantMap config = moduleProviderConfig(product).value(name.toString()).toMap();
+ ModuleProviderInfo &info =
+ m_storedModuleProviderInfo.providers[{name.toString(), config, int(lookupType)}];
+ const bool fromCache = !info.name.isEmpty();
+ if (!fromCache) {
+ info.name = name;
+ info.config = config;
+ info.providerFile = findModuleProviderFile(name, lookupType);
+ if (!info.providerFile.isEmpty()) {
+ qCDebug(lcModuleLoader) << "Running provider" << name << "at" << info.providerFile;
+ info.searchPaths = getProviderSearchPaths(
+ name, info.providerFile, product, config, dependsItemLocation);
+ info.transientOutput = m_parameters.dryRun();
+ }
+ }
+ if (info.providerFile.isEmpty()) {
+ if (lookupType == ModuleProviderLookup::Named)
+ throw ErrorInfo(Tr::tr("Unknown provider '%1'").arg(name.toString()));
+ continue;
+ }
+ if (fromCache)
+ qCDebug(lcModuleLoader) << "Re-using provider" << name << "from cache";
+
+ result.providerFound = true;
+ if (info.searchPaths.empty()) {
+ qCDebug(lcModuleLoader)
+ << "Module provider did run, but did not set up any modules.";
+ continue;
+ }
+ qCDebug(lcModuleLoader) << "Module provider added" << info.searchPaths.size()
+ << "new search path(s)";
+
+ allSearchPaths << info.searchPaths;
}
- qCDebug(lcModuleLoader) << "Module provider added" << info.searchPaths.size()
- << "new search path(s)";
+ if (allSearchPaths.isEmpty())
+ return result;
- m_reader->pushExtraSearchPaths(info.searchPaths);
- return {true, true};
+ m_reader->pushExtraSearchPaths(allSearchPaths);
+ result.providerAddedSearchPaths = true;
+
+ return result;
}
QVariantMap ModuleProviderLoader::moduleProviderConfig(
@@ -179,27 +208,52 @@ QVariantMap ModuleProviderLoader::moduleProviderConfig(
return *(product.theModuleProviderConfig = std::move(providerConfig));
}
+std::optional<std::vector<QualifiedId>> ModuleProviderLoader::getModuleProviders(Item *item)
+{
+ while (item) {
+ const auto providers =
+ m_evaluator->optionalStringListValue(item, StringConstants::qbsModuleProviders());
+ if (providers) {
+ std::vector<QualifiedId> result;
+ result.reserve(providers->size());
+ for (const auto &provider : *providers)
+ result.push_back(QualifiedId::fromString(provider));
+ return result;
+ }
+ item = item->parent();
+ }
+ return std::nullopt;
+}
+
QString ModuleProviderLoader::findModuleProviderFile(
const QualifiedId &name, ModuleProviderLookup lookupType)
{
for (const QString &path : m_reader->allSearchPaths()) {
QString fullPath = FileInfo::resolvePath(path, QStringLiteral("module-providers"));
switch (lookupType) {
- case ModuleProviderLookup::Regular:
+ case ModuleProviderLookup::Named: {
+ const auto result =
+ FileInfo::resolvePath(fullPath, name.toString() + QStringLiteral(".qbs"));
+ if (FileInfo::exists(result)) {
+ fullPath = result;
+ break;
+ }
+ [[fallthrough]];
+ }
+ case ModuleProviderLookup::Scoped:
for (const QString &component : name)
fullPath = FileInfo::resolvePath(fullPath, component);
+ fullPath = FileInfo::resolvePath(fullPath, QStringLiteral("provider.qbs"));
break;
case ModuleProviderLookup::Fallback:
- fullPath = FileInfo::resolvePath(fullPath, QStringLiteral("__fallback"));
+ fullPath = FileInfo::resolvePath(fullPath, QStringLiteral("__fallback/provider.qbs"));
break;
}
- const QString providerFile = FileInfo::resolvePath(fullPath,
- QStringLiteral("provider.qbs"));
- if (!FileInfo::exists(providerFile)) {
- qCDebug(lcModuleLoader) << "No module provider found at" << providerFile;
+ if (!FileInfo::exists(fullPath)) {
+ qCDebug(lcModuleLoader) << "No module provider found at" << fullPath;
continue;
}
- return providerFile;
+ return fullPath;
}
return {};
}
diff --git a/src/lib/corelib/language/moduleproviderloader.h b/src/lib/corelib/language/moduleproviderloader.h
index c720d4202..4b3115cfb 100644
--- a/src/lib/corelib/language/moduleproviderloader.h
+++ b/src/lib/corelib/language/moduleproviderloader.h
@@ -57,7 +57,14 @@ public:
using FallbackMode = ModuleLoader::FallbackMode;
explicit ModuleProviderLoader(ItemReader *itemReader, Evaluator *evaluator);
- enum class ModuleProviderLookup { Regular, Fallback };
+ enum class ModuleProviderLookup { Scoped, Named, Fallback };
+
+ struct Provider
+ {
+ QualifiedId name;
+ ModuleProviderLookup lookup;
+ };
+
struct ModuleProviderResult
{
ModuleProviderResult() = default;
@@ -88,14 +95,15 @@ public:
const QualifiedId &moduleName,
FallbackMode fallbackMode);
ModuleProviderResult findModuleProvider(
- const QualifiedId &name,
+ const std::vector<Provider> &providers,
ProductContext &product,
- ModuleProviderLookup lookupType,
const CodeLocation &dependsItemLocation);
QVariantMap moduleProviderConfig(ProductContext &product);
const Set<QString> &tempQbsFiles() const { return m_tempQbsFiles; }
+ std::optional<std::vector<QualifiedId>> getModuleProviders(Item *item);
+
private:
QString findModuleProviderFile(const QualifiedId &name, ModuleProviderLookup lookupType);
QStringList getProviderSearchPaths(
diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h
index f2bc78446..f40bfa4a7 100644
--- a/src/lib/corelib/tools/stringconstants.h
+++ b/src/lib/corelib/tools/stringconstants.h
@@ -143,6 +143,7 @@ public:
static const QString &profilesProperty() { return profiles(); }
QBS_STRING_CONSTANT(productTypesProperty, "productTypes")
QBS_STRING_CONSTANT(productsKey, "products")
+ QBS_STRING_CONSTANT(qbsModuleProviders, "qbsModuleProviders")
QBS_STRING_CONSTANT(qbsSearchPathsProperty, "qbsSearchPaths")
QBS_STRING_CONSTANT(referencesProperty, "references")
QBS_STRING_CONSTANT(recursiveProperty, "recursive")