summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@digia.com>2013-03-30 12:31:05 +0100
committerJoerg Bornemann <joerg.bornemann@digia.com>2013-04-03 15:18:32 +0200
commit9f71bd40503001cb593ec113d16f9212263d4723 (patch)
tree34bd763e314a02f8c07cb717c537853e76b41f50
parenta44efdd72349a5d2fcb1bb77cf729a84e712f74e (diff)
downloadqbs-9f71bd40503001cb593ec113d16f9212263d4723.tar.gz
introduce product.dependencies property
It is now possible to access the dependencies of a product or module. Entry point for the tree of dependencies is product.dependencies which returns a list of objects that represent products/modules the product depends on. Blackbox test added. Change-Id: I0c2728da479e8cc45ca3994d7e4a9e7a41802aa1 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
-rw-r--r--src/lib/buildgraph/buildgraph.cpp123
-rw-r--r--tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs37
-rw-r--r--tests/auto/blackbox/testdata/dependenciesProperty/product2.cpp1
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp47
-rw-r--r--tests/auto/blackbox/tst_blackbox.h1
5 files changed, 200 insertions, 9 deletions
diff --git a/src/lib/buildgraph/buildgraph.cpp b/src/lib/buildgraph/buildgraph.cpp
index 3ec381e0e..81e01cc51 100644
--- a/src/lib/buildgraph/buildgraph.cpp
+++ b/src/lib/buildgraph/buildgraph.cpp
@@ -44,6 +44,119 @@
namespace qbs {
namespace Internal {
+static void setupProductScriptValue(ScriptEngine *engine, QScriptValue &productScriptValue,
+ const ResolvedProductConstPtr &product,
+ ScriptPropertyObserver *observer);
+
+class DependenciesFunction
+{
+public:
+ DependenciesFunction(ScriptEngine *engine)
+ : m_engine(engine)
+ {
+ }
+
+ void init(QScriptValue &productScriptValue, const ResolvedProductConstPtr &product)
+ {
+ QScriptValue depfunc = m_engine->newFunction(&js_productDependencies);
+ setProduct(depfunc, product.data());
+ QScriptValue descriptor = m_engine->newObject();
+ descriptor.setProperty(QLatin1String("get"), depfunc);
+ descriptor.setProperty(QLatin1String("set"), m_engine->evaluate("(function(){})"));
+ descriptor.setProperty(QLatin1String("enumerable"), true);
+ m_engine->defineProperty(productScriptValue, QLatin1String("dependencies"), descriptor);
+ }
+
+private:
+ static QScriptValue js_productDependencies(QScriptContext *context, QScriptEngine *engine)
+ {
+ QScriptValue callee = context->callee();
+ const ResolvedProduct * const product = getProduct(callee);
+ QScriptValue result = engine->newArray();
+ quint32 idx = 0;
+ foreach (const ResolvedProductPtr &dependency, product->dependencies) {
+ QScriptValue obj = engine->newObject();
+ setupProductScriptValue(static_cast<ScriptEngine *>(engine), obj, dependency, 0);
+ result.setProperty(idx++, obj);
+ }
+ foreach (const ResolvedModuleConstPtr &dependency, product->modules) {
+ QScriptValue obj = engine->newObject();
+ setupModuleScriptValue(static_cast<ScriptEngine *>(engine), obj,
+ product->properties->value(), dependency->name);
+ result.setProperty(idx++, obj);
+ }
+ return result;
+ }
+
+ static QScriptValue js_moduleDependencies(QScriptContext *context, QScriptEngine *engine)
+ {
+ QScriptValue callee = context->callee();
+ const QVariantMap modulesMap = callee.data().toVariant().toMap();
+ QScriptValue result = engine->newArray();
+ quint32 idx = 0;
+ for (QVariantMap::const_iterator it = modulesMap.begin(); it != modulesMap.end(); ++it) {
+ QScriptValue obj = engine->newObject();
+ obj.setProperty(QLatin1String("name"), it.key());
+ setupModuleScriptValue(static_cast<ScriptEngine *>(engine), obj, it.value().toMap(),
+ it.key());
+ result.setProperty(idx++, obj);
+ }
+ return result;
+ }
+
+ static void setupModuleScriptValue(ScriptEngine *engine, QScriptValue &moduleScriptValue,
+ const QVariantMap &propertyMap,
+ const QString &moduleName)
+ {
+ const QVariantMap propMap
+ = propertyMap.value(QLatin1String("modules")).toMap().value(moduleName).toMap();
+ for (QVariantMap::ConstIterator it = propMap.constBegin(); it != propMap.constEnd(); ++it) {
+ const QVariant &value = it.value();
+ if (value.isValid() && !value.canConvert<QVariantMap>())
+ moduleScriptValue.setProperty(it.key(), engine->toScriptValue(value));
+ }
+ QScriptValue depfunc = engine->newFunction(&js_moduleDependencies);
+ depfunc.setData(engine->toScriptValue(propMap.value(QLatin1String("modules"))));
+ QScriptValue descriptor = engine->newObject();
+ descriptor.setProperty(QLatin1String("get"), depfunc);
+ descriptor.setProperty(QLatin1String("set"), engine->evaluate("(function(){})"));
+ descriptor.setProperty(QLatin1String("enumerable"), true);
+ engine->defineProperty(moduleScriptValue, QLatin1String("dependencies"), descriptor);
+ moduleScriptValue.setProperty(QLatin1String("dependencies"), depfunc);
+ moduleScriptValue.setProperty(QLatin1String("type"), QLatin1String("module"));
+ }
+
+ static void setProduct(QScriptValue scriptValue, const ResolvedProduct *product)
+ {
+ QVariant v;
+ v.setValue<quintptr>(reinterpret_cast<quintptr>(product));
+ scriptValue.setData(scriptValue.engine()->newVariant(v));
+ }
+
+ static const ResolvedProduct *getProduct(const QScriptValue &scriptValue)
+ {
+ const quintptr ptr = scriptValue.data().toVariant().value<quintptr>();
+ return reinterpret_cast<const ResolvedProduct *>(ptr);
+ }
+
+ ScriptEngine *m_engine;
+};
+
+static void setupProductScriptValue(ScriptEngine *engine, QScriptValue &productScriptValue,
+ const ResolvedProductConstPtr &product,
+ ScriptPropertyObserver *observer)
+{
+ ModuleProperties::init(productScriptValue, product);
+ DependenciesFunction(engine).init(productScriptValue, product);
+ const QVariantMap &propMap = product->properties->value();
+ for (QVariantMap::ConstIterator it = propMap.constBegin(); it != propMap.constEnd(); ++it) {
+ const QVariant &value = it.value();
+ if (value.isValid() && !value.canConvert<QVariantMap>())
+ engine->setObservedProperty(productScriptValue, it.key(),
+ engine->toScriptValue(value), observer);
+ }
+}
+
void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductConstPtr &product,
const RuleConstPtr &rule, QScriptValue targetObject,
ScriptPropertyObserver *observer)
@@ -81,15 +194,7 @@ void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductCons
engine->setProperty("_qbs_procenv", v);
}
productScriptValue = engine->newObject();
- ModuleProperties::init(productScriptValue, product);
- const QVariantMap &propMap = product->properties->value();
- for (QVariantMap::ConstIterator it = propMap.constBegin(); it != propMap.constEnd(); ++it) {
- const QVariant &value = it.value();
- if (value.isValid() && !value.canConvert<QVariantMap>())
- engine->setObservedProperty(productScriptValue, it.key(),
- engine->toScriptValue(value), observer);
- }
-
+ setupProductScriptValue(engine, productScriptValue, product, observer);
targetObject.setProperty("product", productScriptValue);
} else {
productScriptValue = targetObject.property("product");
diff --git a/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs
new file mode 100644
index 000000000..96058f107
--- /dev/null
+++ b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs
@@ -0,0 +1,37 @@
+import qbs 1.0
+import qbs.fileinfo as FileInfo
+
+Project {
+ Product {
+ type: "deps"
+ name: "product1"
+ Depends { name: "product2" }
+ Transformer {
+ Artifact {
+ fileTags: ["deps"]
+ fileName: product.name + '.deps'
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = 'generate ' + FileInfo.fileName(output.fileName);
+ cmd.highlight = 'codegen';
+ cmd.content = JSON.stringify(product.dependencies);
+ cmd.sourceCode = function() {
+ file = new TextFile(output.fileName, TextFile.WriteOnly);
+ file.truncate();
+ file.write(content);
+ file.close();
+ }
+ return cmd;
+ }
+ }
+ }
+ Product {
+ type: "application"
+ name: "product2"
+ property string narf: "zort"
+ Depends { name: "cpp" }
+ cpp.defines: ["SMURF"]
+ files: ["product2.cpp"]
+ }
+}
diff --git a/tests/auto/blackbox/testdata/dependenciesProperty/product2.cpp b/tests/auto/blackbox/testdata/dependenciesProperty/product2.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata/dependenciesProperty/product2.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 937421f3e..2540cdfd6 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -35,6 +35,8 @@
#include <QLocale>
#include <QTemporaryFile>
+#include <QScriptEngine>
+#include <QScriptValue>
#if QT_VERSION >= 0x050000
#define SKIP_TEST(message) QSKIP(message)
@@ -245,6 +247,51 @@ void TestBlackbox::build_project_dry_run()
QVERIFY2(buildDirContents.isEmpty(), qPrintable(buildDirContents.join(" ")));
}
+void TestBlackbox::dependenciesProperty()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/dependenciesProperty"));
+ QCOMPARE(runQbs(), 0);
+ QFile depsFile(buildDir + QLatin1String("/product1.deps"));
+ QVERIFY(depsFile.open(QFile::ReadOnly));
+ QString deps = QString::fromLatin1(depsFile.readAll());
+ QVERIFY(!deps.isEmpty());
+ QScriptEngine scriptEngine;
+ QScriptValue scriptValue = scriptEngine.evaluate(deps);
+ QScriptValue product2;
+ QScriptValue qbs;
+ int c = scriptValue.property(QLatin1String("length")).toInt32();
+ QCOMPARE(c, 2);
+ for (int i = 0; i < c; ++i) {
+ QScriptValue dep = scriptValue.property(i);
+ QString name = dep.property(QLatin1String("name")).toVariant().toString();
+ if (name == QLatin1String("product2"))
+ product2 = dep;
+ else if (name == QLatin1String("qbs"))
+ qbs = dep;
+ }
+ QVERIFY(qbs.isObject());
+ QVERIFY(product2.isObject());
+ QCOMPARE(product2.property(QLatin1String("type")).toString(), QLatin1String("application"));
+ QCOMPARE(product2.property(QLatin1String("narf")).toString(), QLatin1String("zort"));
+ QScriptValue product2_deps = product2.property(QLatin1String("dependencies"));
+ QVERIFY(product2_deps.isObject());
+ c = product2_deps.property(QLatin1String("length")).toInt32();
+ QCOMPARE(c, 2);
+ QScriptValue product2_qbs;
+ QScriptValue product2_cpp;
+ for (int i = 0; i < c; ++i) {
+ QScriptValue dep = product2_deps.property(i);
+ QString name = dep.property(QLatin1String("name")).toVariant().toString();
+ if (name == QLatin1String("cpp"))
+ product2_cpp = dep;
+ else if (name == QLatin1String("qbs"))
+ product2_qbs = dep;
+ }
+ QVERIFY(product2_qbs.isObject());
+ QVERIFY(product2_cpp.isObject());
+ QCOMPARE(product2_cpp.property("defines").toString(), QLatin1String("SMURF"));
+}
+
void TestBlackbox::resolve_project_data()
{
return build_project_data();
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index d1d32e05e..c67aad5ab 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -65,6 +65,7 @@ private slots:
void build_project();
void build_project_dry_run_data();
void build_project_dry_run();
+ void dependenciesProperty();
void resolve_project_data();
void resolve_project();
void resolve_project_dry_run_data();