aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/buildgraph/depscanner.cpp
diff options
context:
space:
mode:
authorMaxim Zaitsev <maxim.m.zaitsev@gmail.com>2014-03-04 02:46:31 +0400
committerJoerg Bornemann <joerg.bornemann@digia.com>2014-03-12 15:27:44 +0100
commit9c8997413fb7d744e1d1b62b5c926cb089eb0d52 (patch)
tree566370cd102144ed4cb3c0000cf2998cf3dd974c /src/lib/corelib/buildgraph/depscanner.cpp
parent91d4e47fc8eb506b3a906d75a838a28b2c3a38e4 (diff)
Add new qml item Scanner
This item allows to write custom dependency scanners in modules. Change-Id: I6cb49969973ee29896d1909e7a16bf5da50f8aef Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/lib/corelib/buildgraph/depscanner.cpp')
-rw-r--r--src/lib/corelib/buildgraph/depscanner.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/lib/corelib/buildgraph/depscanner.cpp b/src/lib/corelib/buildgraph/depscanner.cpp
new file mode 100644
index 000000000..e273e19d2
--- /dev/null
+++ b/src/lib/corelib/buildgraph/depscanner.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Build Suite.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "depscanner.h"
+#include "artifact.h"
+#include "projectbuilddata.h"
+#include "buildgraph.h"
+
+#include <tools/error.h>
+#include <logging/translator.h>
+#include <language/language.h>
+#include <language/scriptengine.h>
+#include <jsextensions/moduleproperties.h>
+#include <plugins/scanner/scanner.h>
+
+#include <QVariantMap>
+#include <QSet>
+#include <QScriptContext>
+
+namespace qbs {
+namespace Internal {
+
+static void collectCppIncludePaths(const QVariantMap &modules, QSet<QString> *collectedPaths)
+{
+ QMapIterator<QString, QVariant> iterator(modules);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.key() == QLatin1String("cpp")) {
+ QVariant includePathsVariant =
+ iterator.value().toMap().value(QLatin1String("includePaths"));
+ if (includePathsVariant.isValid())
+ collectedPaths->unite(QSet<QString>::fromList(includePathsVariant.toStringList()));
+ } else {
+ collectCppIncludePaths(iterator.value().toMap().value(QLatin1String("modules")).toMap(),
+ collectedPaths);
+ }
+ }
+}
+
+PluginDependencyScanner::PluginDependencyScanner(ScannerPlugin *plugin)
+ : m_plugin(plugin)
+{
+ m_fileTag += FileTag(plugin->fileTag);
+}
+
+QStringList PluginDependencyScanner::collectSearchPaths(Artifact *artifact)
+{
+ if (m_plugin->flags & ScannerUsesCppIncludePaths) {
+ QVariantMap modules = artifact->properties->value().value(QLatin1String("modules")).toMap();
+ QSet<QString> collectedPaths;
+ collectCppIncludePaths(modules, &collectedPaths);
+ return QStringList(collectedPaths.toList());
+ } else {
+ return QStringList();
+ }
+}
+
+QStringList PluginDependencyScanner::collectDependencies(Artifact *artifact)
+{
+ QSet<QString> result;
+ QString baseDirOfInFilePath = artifact->dirPath();
+ const QString &filepath = artifact->filePath();
+ void *scannerHandle = m_plugin->open(filepath.utf16(), ScanForDependenciesFlag);
+ if (!scannerHandle)
+ return QStringList();
+ forever {
+ int flags = 0;
+ int length = 0;
+ const char *szOutFilePath = m_plugin->next(scannerHandle, &length, &flags);
+ if (szOutFilePath == 0)
+ break;
+ QString outFilePath = QString::fromLocal8Bit(szOutFilePath, length);
+ if (outFilePath.isEmpty())
+ continue;
+ if (flags & SC_LOCAL_INCLUDE_FLAG) {
+ QString localFilePath = FileInfo::resolvePath(baseDirOfInFilePath, outFilePath);
+ if (FileInfo::exists(localFilePath))
+ outFilePath = localFilePath;
+ }
+ result += outFilePath;
+ }
+ m_plugin->close(scannerHandle);
+ return QStringList(result.toList());
+}
+
+const FileTags &PluginDependencyScanner::fileTags()
+{
+ return m_fileTag;
+}
+
+bool PluginDependencyScanner::recursive()
+{
+ return m_plugin->flags & ScannerRecursiveDependencies;
+}
+
+void *PluginDependencyScanner::key()
+{
+ return m_plugin;
+}
+
+UserDependencyScanner::UserDependencyScanner(const ResolvedScannerConstPtr &scanner,
+ const Logger &logger, ScriptEngine *engine)
+ : m_scanner(scanner),
+ m_logger(logger),
+ m_engine(engine),
+ m_observer(engine),
+ m_project(0),
+ m_product(0)
+{
+ m_global = engine->newObject();
+ setupScriptEngineForFile(m_engine, m_scanner->scanScript->fileContext, m_global);
+}
+
+QStringList UserDependencyScanner::collectSearchPaths(Artifact *artifact)
+{
+ return evaluate(artifact, m_scanner->searchPathsScript);
+}
+
+QStringList UserDependencyScanner::collectDependencies(Artifact *artifact)
+{
+ return evaluate(artifact, m_scanner->scanScript);
+}
+
+const FileTags &UserDependencyScanner::fileTags()
+{
+ return m_scanner->inputs;
+}
+
+bool UserDependencyScanner::recursive()
+{
+ return m_scanner->recursive;
+}
+
+void *UserDependencyScanner::key()
+{
+ return const_cast<ResolvedScanner*>(m_scanner.data());
+}
+
+QStringList UserDependencyScanner::evaluate(Artifact *artifact, const ScriptFunctionPtr &script)
+{
+ if ((artifact->product.data() != m_product) || (artifact->product->project.data() != m_project)) {
+ m_product = artifact->product.data();
+ m_project = artifact->product->project.data();
+ setupScriptEngineForProduct(m_engine, artifact->product,
+ m_scanner->module, m_global, &m_observer);
+ }
+
+ QScriptValue artifactConfig = m_engine->newObject();
+ ModuleProperties::init(artifactConfig, artifact);
+ artifactConfig.setProperty(QLatin1String("fileName"), artifact->filePath(), 0);
+ const QStringList fileTags = artifact->fileTags.toStringList();
+ artifactConfig.setProperty(QLatin1String("fileTags"), m_engine->toScriptValue(fileTags));
+ if (!m_scanner->module->name.isEmpty())
+ artifactConfig.setProperty(QLatin1String("moduleName"), m_scanner->module->name);
+ QScriptValueList args;
+ args.reserve(3);
+ args.append(m_global.property(QString::fromLatin1("project")));
+ args.append(m_global.property(QString::fromLatin1("product")));
+ args.append(artifactConfig);
+
+ QScriptContext *ctx = m_engine->currentContext();
+ ctx->pushScope(m_global);
+ QScriptValue &function = script->scriptFunction;
+ if (!function.isValid() || function.engine() != m_engine) {
+ function = m_engine->evaluate(script->sourceCode);
+ if (Q_UNLIKELY(!function.isFunction()))
+ throw ErrorInfo(Tr::tr("Invalid scan script."), script->location);
+ }
+ QScriptValue result = function.call(QScriptValue(), args);
+ ctx->popScope();
+ m_engine->clearRequestedProperties();
+ if (Q_UNLIKELY(m_engine->hasErrorOrException(result))) {
+ QString msg = Tr::tr("evaluating scan script: ") + m_engine->uncaughtException().toString();
+ m_engine->clearExceptions();
+ throw ErrorInfo(msg, script->location);
+ }
+ QStringList list;
+ if (result.isArray()) {
+ const int count = result.property(QLatin1String("length")).toInt32();
+ list.reserve(count);
+ for (qint32 i = 0; i < count; ++i) {
+ QScriptValue item = result.property(i);
+ if (item.isValid() && !item.isUndefined())
+ list.append(item.toString());
+ }
+ }
+ return list;
+}
+
+} // namespace Internal
+} // namespace qbs