aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/jsextensions
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@digia.com>2014-01-09 17:50:40 +0100
committerJoerg Bornemann <joerg.bornemann@digia.com>2014-01-10 18:11:22 +0100
commit81af9acaa295a574c1cb5e6714725197dac7f530 (patch)
treecc8c94467f49a7d267e5249f624874feecc7eed4 /src/lib/corelib/jsextensions
parent2fe25eb3f20ffb4e58cb559f2bcb9950c963290a (diff)
Move Qt profile setup into a dedicated library.
Otherwise all changes to the implementation will have to be duplicated in IDEs. Change-Id: I61e6d4fa1ee9b724eb5d9de9f233dc915a6c8bc3 Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/lib/corelib/jsextensions')
-rw-r--r--src/lib/corelib/jsextensions/domxml.cpp370
-rw-r--r--src/lib/corelib/jsextensions/domxml.h118
-rw-r--r--src/lib/corelib/jsextensions/file.cpp134
-rw-r--r--src/lib/corelib/jsextensions/file.h44
-rw-r--r--src/lib/corelib/jsextensions/jsextensions.cpp65
-rw-r--r--src/lib/corelib/jsextensions/jsextensions.h59
-rw-r--r--src/lib/corelib/jsextensions/jsextensions.pri17
-rw-r--r--src/lib/corelib/jsextensions/moduleproperties.cpp154
-rw-r--r--src/lib/corelib/jsextensions/moduleproperties.h62
-rw-r--r--src/lib/corelib/jsextensions/process.cpp223
-rw-r--r--src/lib/corelib/jsextensions/process.h91
-rw-r--r--src/lib/corelib/jsextensions/textfile.cpp185
-rw-r--r--src/lib/corelib/jsextensions/textfile.h74
13 files changed, 1596 insertions, 0 deletions
diff --git a/src/lib/corelib/jsextensions/domxml.cpp b/src/lib/corelib/jsextensions/domxml.cpp
new file mode 100644
index 000000000..a66f2b21b
--- /dev/null
+++ b/src/lib/corelib/jsextensions/domxml.cpp
@@ -0,0 +1,370 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+** 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 "domxml.h"
+
+#include <QFile>
+#include <QScriptEngine>
+
+
+namespace qbs {
+namespace Internal {
+
+void initializeJsExtensionXml(QScriptValue extensionObject)
+{
+ QScriptEngine *engine = extensionObject.engine();
+ QScriptValue obj = engine->newQMetaObject(&XmlDomDocument::staticMetaObject, engine->newFunction(&XmlDomDocument::ctor));
+ extensionObject.setProperty("XmlDomDocument", obj);
+ obj = engine->newQMetaObject(&XmlDomNode::staticMetaObject, engine->newFunction(&XmlDomNode::ctor));
+ extensionObject.setProperty("XmlDomElement", obj);
+}
+
+QScriptValue XmlDomDocument::ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ XmlDomDocument *xml = 0;
+ switch (context->argumentCount()) {
+ case 0:
+ xml = new XmlDomDocument(context);
+ break;
+ case 1:
+ xml = new XmlDomDocument(context, context->argument(0).toString());
+ break;
+ default:
+ return context->throwError("DomXml(QString file = QLatin1String(\"\"))");
+ }
+ QScriptValue obj = engine->newQObject(xml, QScriptEngine::ScriptOwnership);
+ return obj;
+}
+
+QScriptValue XmlDomDocument::documentElement()
+{
+ return engine()->newQObject(new XmlDomNode(m_domDocument.documentElement()), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomDocument::createElement(const QString &tagName)
+{
+ return engine()->newQObject(new XmlDomNode(m_domDocument.createElement(tagName)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomDocument::createCDATASection(const QString &value)
+{
+ return engine()->newQObject(new XmlDomNode(m_domDocument.createCDATASection(value)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomDocument::createTextNode(const QString &value)
+{
+ return engine()->newQObject(new XmlDomNode(m_domDocument.createTextNode(value)), QScriptEngine::ScriptOwnership);
+}
+
+bool XmlDomDocument::setContent(const QString &content)
+{
+ return m_domDocument.setContent(content);
+}
+
+QString XmlDomDocument::toString(int indent)
+{
+ return m_domDocument.toString(indent);
+}
+
+void XmlDomDocument::save(const QString &filePath, int indent)
+{
+ QFile f(filePath);
+ if (!f.open(QIODevice::WriteOnly)) {
+ context()->throwError(QString::fromLatin1("unable to open '%1'")
+ .arg(filePath));
+ return;
+ }
+
+ QByteArray buff(m_domDocument.toByteArray(indent));
+ if (buff.size() != f.write(buff))
+ {
+ context()->throwError(f.errorString());
+ f.close();
+ return;
+ }
+
+ f.close();
+ if (f.error() != QFile::NoError)
+ context()->throwError(f.errorString());
+}
+
+void XmlDomDocument::load(const QString &filePath)
+{
+ QFile f(filePath);
+ if (!f.open(QIODevice::ReadOnly)) {
+ context()->throwError(QString::fromLatin1("unable to open '%1'")
+ .arg(filePath));
+ return;
+ }
+
+ QString errorMsg;
+ if (!m_domDocument.setContent(&f, &errorMsg)) {
+ context()->throwError(errorMsg);
+ return;
+ }
+}
+
+XmlDomDocument::XmlDomDocument(QScriptContext *context, const QString &name):m_domDocument(name)
+{
+ Q_UNUSED(context)
+ m_domNode = m_domDocument;
+}
+
+QScriptValue XmlDomNode::ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(context)
+ return engine->newQObject(new XmlDomNode(), QScriptEngine::ScriptOwnership);
+}
+
+bool XmlDomNode::isElement() const
+{
+ return m_domNode.isElement();
+}
+
+bool XmlDomNode::isCDATASection() const
+{
+ return m_domNode.isCDATASection();
+}
+
+bool XmlDomNode::isText() const
+{
+ return m_domNode.isText();
+}
+
+QString XmlDomNode::attribute(const QString &name, const QString &defValue)
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return defValue;
+ }
+ return el.attribute(name, defValue);
+}
+
+void XmlDomNode::setAttribute(const QString &name, const QString &value)
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return;
+ }
+ el.setAttribute(name, value);
+}
+
+bool XmlDomNode::hasAttribute(const QString &name) const
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return false;
+ }
+ return el.hasAttribute(name);
+}
+
+QString XmlDomNode::tagName() const
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return QString();
+ }
+ return el.tagName();
+}
+
+void XmlDomNode::setTagName(const QString &name)
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return;
+ }
+ el.setTagName(name);
+}
+
+QString XmlDomNode::text() const
+{
+ QDomElement el = m_domNode.toElement();
+ if (el.isNull()) {
+ context()->throwError(QString::fromLatin1("Node '%1' is not an element node").arg(m_domNode.nodeName()));
+ return QString();
+ }
+ return el.text();
+}
+
+QString XmlDomNode::data() const
+{
+ if (m_domNode.isText())
+ return m_domNode.toText().data();
+ if (m_domNode.isCDATASection())
+ return m_domNode.toCDATASection().data();
+ if (m_domNode.isCharacterData())
+ return m_domNode.toCharacterData().data();
+ context()->throwError(QString::fromLatin1("Node '%1' is not a character data node").arg(m_domNode.nodeName()));
+ return QString();
+}
+
+void XmlDomNode::setData(const QString &v) const
+{
+ if (m_domNode.isText())
+ return m_domNode.toText().setData(v);
+ if (m_domNode.isCDATASection())
+ return m_domNode.toCDATASection().setData(v);
+ if (m_domNode.isCharacterData())
+ return m_domNode.toCharacterData().setData(v);
+ context()->throwError(QString::fromLatin1("Node '%1' is not a character data node").arg(m_domNode.nodeName()));
+ return;
+}
+
+void XmlDomNode::clear()
+{
+ m_domNode.clear();
+}
+
+bool XmlDomNode::hasAttributes() const
+{
+ return m_domNode.hasAttributes();
+}
+
+bool XmlDomNode::hasChildNodes() const
+{
+ return m_domNode.hasChildNodes();
+}
+
+QScriptValue XmlDomNode::parentNode() const
+{
+ return engine()->newQObject(new XmlDomNode(m_domNode.parentNode()), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::firstChild(const QString &tagName)
+{
+ if (tagName.isEmpty())
+ return engine()->newQObject(new XmlDomNode(m_domNode.firstChild()), QScriptEngine::ScriptOwnership);
+ return engine()->newQObject(new XmlDomNode(m_domNode.firstChildElement(tagName)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::lastChild(const QString &tagName) const
+{
+ if (tagName.isEmpty())
+ return engine()->newQObject(new XmlDomNode(m_domNode.lastChild()), QScriptEngine::ScriptOwnership);
+ return engine()->newQObject(new XmlDomNode(m_domNode.lastChildElement(tagName)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::previousSibling(const QString &tagName) const
+{
+ if (tagName.isEmpty())
+ return engine()->newQObject(new XmlDomNode(m_domNode.previousSibling()), QScriptEngine::ScriptOwnership);
+ return engine()->newQObject(new XmlDomNode(m_domNode.previousSiblingElement(tagName)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::nextSibling(const QString &tagName) const
+{
+ if (tagName.isEmpty())
+ return engine()->newQObject(new XmlDomNode(m_domNode.nextSibling()), QScriptEngine::ScriptOwnership);
+ return engine()->newQObject(new XmlDomNode(m_domNode.nextSiblingElement(tagName)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::appendChild(QScriptValue newChild)
+{
+ XmlDomNode *newNode = qobject_cast<XmlDomNode*>(newChild.toQObject());
+ if (!newNode) {
+ context()->throwError(QString::fromLatin1("First argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+ return engine()->newQObject(new XmlDomNode(m_domNode.appendChild(newNode->m_domNode)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::insertBefore(const QScriptValue &newChild, const QScriptValue &refChild)
+{
+ XmlDomNode *newNode = qobject_cast<XmlDomNode*>(newChild.toQObject());
+ if (!newNode) {
+ context()->throwError(QString::fromLatin1("First argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ XmlDomNode *refNode = qobject_cast<XmlDomNode*>(refChild.toQObject());
+ if (!refNode) {
+ context()->throwError(QString::fromLatin1("Second argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ return engine()->newQObject(new XmlDomNode(m_domNode.insertBefore(newNode->m_domNode, refNode->m_domNode)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::insertAfter(const QScriptValue &newChild, const QScriptValue &refChild)
+{
+ XmlDomNode *newNode = qobject_cast<XmlDomNode*>(newChild.toQObject());
+ if (!newNode) {
+ context()->throwError(QString::fromLatin1("First argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ XmlDomNode *refNode = qobject_cast<XmlDomNode*>(refChild.toQObject());
+ if (!refNode) {
+ context()->throwError(QString::fromLatin1("Second argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ return engine()->newQObject(new XmlDomNode(m_domNode.insertAfter(newNode->m_domNode, refNode->m_domNode)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::replaceChild(const QScriptValue &newChild, const QScriptValue &oldChild)
+{
+ XmlDomNode *newNode = qobject_cast<XmlDomNode*>(newChild.toQObject());
+ if (!newNode) {
+ context()->throwError(QString::fromLatin1("First argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ XmlDomNode *oldNode = qobject_cast<XmlDomNode*>(oldChild.toQObject());
+ if (!oldNode) {
+ context()->throwError(QString::fromLatin1("Second argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ return engine()->newQObject(new XmlDomNode(m_domNode.replaceChild(newNode->m_domNode, oldNode->m_domNode)), QScriptEngine::ScriptOwnership);
+}
+
+QScriptValue XmlDomNode::removeChild(const QScriptValue &oldChild)
+{
+ XmlDomNode *oldNode = qobject_cast<XmlDomNode*>(oldChild.toQObject());
+ if (!oldNode) {
+ context()->throwError(QString::fromLatin1("First argument is not a XmlDomNode object"));
+ return QScriptValue();
+ }
+
+ return engine()->newQObject(new XmlDomNode(m_domNode.removeChild(oldNode->m_domNode)), QScriptEngine::ScriptOwnership);
+}
+
+XmlDomNode::XmlDomNode(const QDomNode &other)
+{
+ m_domNode = other;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/domxml.h b/src/lib/corelib/jsextensions/domxml.h
new file mode 100644
index 000000000..7df603328
--- /dev/null
+++ b/src/lib/corelib/jsextensions/domxml.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+** 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.
+**
+****************************************************************************/
+
+#ifndef DOMXML_H
+#define DOMXML_H
+
+#include <QDomDocument>
+#include <QDomNode>
+#include <QObject>
+#include <QScriptValue>
+#include <QScriptable>
+#include <QVariant>
+
+namespace qbs {
+namespace Internal {
+
+class XmlDomDocument;
+
+void initializeJsExtensionXml(QScriptValue extensionObject);
+
+class XmlDomNode: public QObject, public QScriptable
+{
+ Q_OBJECT
+public:
+ static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine);
+
+ Q_INVOKABLE bool isElement() const;
+ Q_INVOKABLE bool isCDATASection() const;
+ Q_INVOKABLE bool isText() const;
+
+ Q_INVOKABLE QString attribute(const QString & name, const QString & defValue = QString());
+ Q_INVOKABLE void setAttribute(const QString & name, const QString & value);
+ Q_INVOKABLE bool hasAttribute(const QString & name) const;
+ Q_INVOKABLE QString tagName() const;
+ Q_INVOKABLE void setTagName(const QString & name);
+
+ Q_INVOKABLE QString text() const;
+
+ Q_INVOKABLE QString data() const;
+ Q_INVOKABLE void setData(const QString &v) const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE bool hasAttributes() const;
+ Q_INVOKABLE bool hasChildNodes() const;
+ Q_INVOKABLE QScriptValue parentNode() const;
+ Q_INVOKABLE QScriptValue firstChild(const QString & tagName = QString());
+ Q_INVOKABLE QScriptValue lastChild(const QString & tagName = QString()) const;
+ Q_INVOKABLE QScriptValue previousSibling(const QString & tagName = QString()) const;
+ Q_INVOKABLE QScriptValue nextSibling(const QString & tagName = QString()) const;
+
+ Q_INVOKABLE QScriptValue appendChild(QScriptValue newChild);
+ Q_INVOKABLE QScriptValue insertBefore(const QScriptValue& newChild, const QScriptValue& refChild);
+ Q_INVOKABLE QScriptValue insertAfter(const QScriptValue& newChild, const QScriptValue& refChild);
+ Q_INVOKABLE QScriptValue replaceChild(const QScriptValue& newChild, const QScriptValue& oldChild);
+ Q_INVOKABLE QScriptValue removeChild(const QScriptValue& oldChild);
+
+protected:
+ friend class XmlDomDocument;
+ XmlDomNode(const QDomNode &other = QDomNode());
+ QDomNode m_domNode;
+};
+
+class XmlDomDocument: public XmlDomNode
+{
+ Q_OBJECT
+public:
+ static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine);
+ Q_INVOKABLE QScriptValue documentElement();
+ Q_INVOKABLE QScriptValue createElement(const QString & tagName);
+ Q_INVOKABLE QScriptValue createCDATASection(const QString & value);
+ Q_INVOKABLE QScriptValue createTextNode(const QString & value);
+
+ Q_INVOKABLE bool setContent(const QString & content);
+ Q_INVOKABLE QString toString(int indent = 1);
+
+ Q_INVOKABLE void save(const QString & filePath, int indent = 1);
+ Q_INVOKABLE void load(const QString & filePath);
+
+protected:
+ XmlDomDocument(QScriptContext *context, const QString &name = QString());
+
+private:
+ QDomDocument m_domDocument;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+Q_DECLARE_METATYPE(qbs::Internal::XmlDomDocument *)
+Q_DECLARE_METATYPE(qbs::Internal::XmlDomNode *)
+
+#endif // DOMXML_H
diff --git a/src/lib/corelib/jsextensions/file.cpp b/src/lib/corelib/jsextensions/file.cpp
new file mode 100644
index 000000000..1e6f2947c
--- /dev/null
+++ b/src/lib/corelib/jsextensions/file.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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 "file.h"
+
+#include <language/scriptengine.h>
+#include <logging/translator.h>
+#include <tools/fileinfo.h>
+
+#include <QFileInfo>
+#include <QScriptEngine>
+
+namespace qbs {
+namespace Internal {
+
+class File
+{
+ friend void initializeJsExtensionFile(QScriptValue extensionObject);
+
+private:
+ static QScriptValue js_ctor(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_copy(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_exists(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_lastModified(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_remove(QScriptContext *context, QScriptEngine *engine);
+};
+
+
+void initializeJsExtensionFile(QScriptValue extensionObject)
+{
+ QScriptEngine *engine = extensionObject.engine();
+ QScriptValue fileObj = engine->newFunction(File::js_ctor);
+ fileObj.setProperty("copy", engine->newFunction(File::js_copy));
+ fileObj.setProperty("exists", engine->newFunction(File::js_exists));
+ fileObj.setProperty("lastModified", engine->newFunction(File::js_lastModified));
+ fileObj.setProperty("remove", engine->newFunction(File::js_remove));
+ extensionObject.setProperty("File", fileObj);
+}
+
+QScriptValue File::js_ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ // Add instance variables here etc., if needed.
+ Q_UNUSED(context);
+ Q_UNUSED(engine);
+ return true;
+}
+
+QScriptValue File::js_copy(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (Q_UNLIKELY(context->argumentCount() < 2)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ Tr::tr("copy expects 2 arguments"));
+ }
+
+ const QString sourceFile = context->argument(0).toString();
+ const QString targetFile = context->argument(1).toString();
+ QString errorMessage;
+ if (Q_UNLIKELY(!copyFileRecursion(sourceFile, targetFile, false, &errorMessage)))
+ return context->throwError(errorMessage);
+ return true;
+}
+
+QScriptValue File::js_exists(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (Q_UNLIKELY(context->argumentCount() < 1)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ Tr::tr("exist expects 1 argument"));
+ }
+ const QString filePath = context->argument(0).toString();
+ const bool exists = FileInfo::exists(filePath);
+ ScriptEngine * const se = static_cast<ScriptEngine *>(engine);
+ se->addFileExistsResult(filePath, exists);
+ return exists;
+}
+
+QScriptValue File::js_remove(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (Q_UNLIKELY(context->argumentCount() < 1)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ Tr::tr("remove expects 1 argument"));
+ }
+ QString fileName = context->argument(0).toString();
+
+ QString errorMessage;
+ if (Q_UNLIKELY(!removeFileRecursion(QFileInfo(fileName), &errorMessage)))
+ return context->throwError(errorMessage);
+ return true;
+}
+
+QScriptValue File::js_lastModified(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ if (Q_UNLIKELY(context->argumentCount() < 1)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ Tr::tr("File.lastModified() expects an argument"));
+ }
+ const QString filePath = context->argument(0).toString();
+ const FileTime timestamp = FileInfo(filePath).lastModified();
+ ScriptEngine * const se = static_cast<ScriptEngine *>(engine);
+ se->addFileLastModifiedResult(filePath, timestamp);
+ return static_cast<qsreal>(timestamp.m_fileTime);
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/file.h b/src/lib/corelib/jsextensions/file.h
new file mode 100644
index 000000000..874c40c71
--- /dev/null
+++ b/src/lib/corelib/jsextensions/file.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#ifndef QBS_FILE_H
+#define QBS_FILE_H
+
+#include <QScriptContext>
+#include <QScriptValue>
+
+namespace qbs {
+namespace Internal {
+
+void initializeJsExtensionFile(QScriptValue extensionObject);
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // QBS_FILE_H
diff --git a/src/lib/corelib/jsextensions/jsextensions.cpp b/src/lib/corelib/jsextensions/jsextensions.cpp
new file mode 100644
index 000000000..b6b5e099b
--- /dev/null
+++ b/src/lib/corelib/jsextensions/jsextensions.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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 "jsextensions.h"
+
+#include "domxml.h"
+#include "file.h"
+#include "process.h"
+#include "textfile.h"
+
+namespace qbs {
+namespace Internal {
+
+void JsExtensions::setupExtensions(const QStringList &names, QScriptValue scope)
+{
+ foreach (const QString &name, names)
+ initializers().value(name)(scope);
+}
+
+bool JsExtensions::hasExtension(const QString &name)
+{
+ return initializers().contains(name);
+}
+
+JsExtensions::InitializerMap JsExtensions::initializers()
+{
+ if (m_initializers.isEmpty()) {
+ m_initializers.insert(QLatin1String("File"), &initializeJsExtensionFile);
+ m_initializers.insert(QLatin1String("Process"), &initializeJsExtensionProcess);
+ m_initializers.insert(QLatin1String("Xml"), &initializeJsExtensionXml);
+ m_initializers.insert(QLatin1String("TextFile"), &initializeJsExtensionTextFile);
+ }
+ return m_initializers;
+}
+
+JsExtensions::InitializerMap JsExtensions::m_initializers;
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/jsextensions.h b/src/lib/corelib/jsextensions/jsextensions.h
new file mode 100644
index 000000000..e268ec215
--- /dev/null
+++ b/src/lib/corelib/jsextensions/jsextensions.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#ifndef QBS_JSEXTENSIONS_H
+#define QBS_JSEXTENSIONS_H
+
+#include <QHash>
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+class QScriptValue;
+QT_END_NAMESPACE
+
+namespace qbs {
+namespace Internal {
+
+class JsExtensions
+{
+public:
+ static void setupExtensions(const QStringList &names, QScriptValue scope);
+ static bool hasExtension(const QString &name);
+
+private:
+ typedef QHash<QString, void (*)(QScriptValue)> InitializerMap;
+ static InitializerMap initializers();
+
+ static InitializerMap m_initializers;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard.
diff --git a/src/lib/corelib/jsextensions/jsextensions.pri b/src/lib/corelib/jsextensions/jsextensions.pri
new file mode 100644
index 000000000..21c97ef64
--- /dev/null
+++ b/src/lib/corelib/jsextensions/jsextensions.pri
@@ -0,0 +1,17 @@
+QT += xml
+
+HEADERS += \
+ $$PWD/file.h \
+ $$PWD/textfile.h \
+ $$PWD/process.h \
+ $$PWD/moduleproperties.h \
+ $$PWD/domxml.h \
+ $$PWD/jsextensions.h
+
+SOURCES += \
+ $$PWD/file.cpp \
+ $$PWD/textfile.cpp \
+ $$PWD/process.cpp \
+ $$PWD/moduleproperties.cpp \
+ $$PWD/domxml.cpp \
+ $$PWD/jsextensions.cpp
diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp
new file mode 100644
index 000000000..83d92e776
--- /dev/null
+++ b/src/lib/corelib/jsextensions/moduleproperties.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 "moduleproperties.h"
+
+#include <buildgraph/artifact.h>
+#include <language/language.h>
+#include <language/scriptengine.h>
+#include <logging/translator.h>
+#include <tools/error.h>
+#include <tools/propertyfinder.h>
+
+#include <QScriptEngine>
+
+namespace qbs {
+namespace Internal {
+
+static QString ptrKey() { return QLatin1String("__internalPtr"); }
+static QString typeKey() { return QLatin1String("__type"); }
+static QString productType() { return QLatin1String("product"); }
+static QString artifactType() { return QLatin1String("artifact"); }
+
+void ModuleProperties::init(QScriptValue productObject,
+ const ResolvedProductConstPtr &product)
+{
+ init(productObject, product.data(), productType());
+}
+
+void ModuleProperties::init(QScriptValue artifactObject, const Artifact *artifact)
+{
+ init(artifactObject, artifact, artifactType());
+}
+
+void ModuleProperties::init(QScriptValue objectWithProperties, const void *ptr,
+ const QString &type)
+{
+ QScriptEngine * const engine = objectWithProperties.engine();
+ objectWithProperties.setProperty("moduleProperties",
+ engine->newFunction(ModuleProperties::js_moduleProperties, 2));
+ objectWithProperties.setProperty("moduleProperty",
+ engine->newFunction(ModuleProperties::js_moduleProperty, 2));
+ objectWithProperties.setProperty(ptrKey(), engine->toScriptValue(quintptr(ptr)));
+ objectWithProperties.setProperty(typeKey(), type);
+}
+
+QScriptValue ModuleProperties::js_moduleProperties(QScriptContext *context, QScriptEngine *engine)
+{
+ try {
+ return moduleProperties(context, engine, false);
+ } catch (const ErrorInfo &e) {
+ return context->throwError(e.toString());
+ }
+}
+
+QScriptValue ModuleProperties::js_moduleProperty(QScriptContext *context, QScriptEngine *engine)
+{
+ try {
+ return moduleProperties(context, engine, true);
+ } catch (const ErrorInfo &e) {
+ return context->throwError(e.toString());
+ }
+}
+
+QScriptValue ModuleProperties::moduleProperties(QScriptContext *context, QScriptEngine *engine,
+ bool oneValue)
+{
+ if (Q_UNLIKELY(context->argumentCount() < 2)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ Tr::tr("Function moduleProperties() expects 2 arguments"));
+ }
+
+ const QScriptValue objectWithProperties = context->thisObject();
+ const QScriptValue typeScriptValue = objectWithProperties.property(typeKey());
+ if (Q_UNLIKELY(!typeScriptValue.isString())) {
+ return context->throwError(QScriptContext::TypeError,
+ QLatin1String("Internal error: __type not set up"));
+ }
+ const QScriptValue ptrScriptValue = objectWithProperties.property(ptrKey());
+ if (Q_UNLIKELY(!ptrScriptValue.isNumber())) {
+ return context->throwError(QScriptContext::TypeError,
+ QLatin1String("Internal error: __internalPtr not set up"));
+ }
+
+ const void *ptr = reinterpret_cast<const void *>(qscriptvalue_cast<quintptr>(ptrScriptValue));
+ PropertyMapConstPtr properties;
+ const Artifact *artifact = 0;
+ if (typeScriptValue.toString() == productType()) {
+ properties = static_cast<const ResolvedProduct *>(ptr)->properties;
+ } else if (typeScriptValue.toString() == artifactType()) {
+ artifact = static_cast<const Artifact *>(ptr);
+ properties = artifact->properties;
+ } else {
+ return context->throwError(QScriptContext::TypeError,
+ QLatin1String("Internal error: invalid type"));
+ }
+
+ ScriptEngine * const qbsEngine = static_cast<ScriptEngine *>(engine);
+ const QString moduleName = internalModuleName(context->argument(0).toString());
+ const QString propertyName = context->argument(1).toString();
+
+ QVariant value = qbsEngine->retrieveFromPropertyCache(moduleName, propertyName, properties);
+ if (!value.isValid()) {
+ if (oneValue)
+ value = PropertyFinder().propertyValue(properties->value(), moduleName, propertyName);
+ else
+ value = PropertyFinder().propertyValues(properties->value(), moduleName, propertyName);
+ const Property p(moduleName, propertyName, value);
+ if (artifact)
+ qbsEngine->addPropertyRequestedFromArtifact(artifact, p);
+ else
+ qbsEngine->addPropertyRequestedInScript(p);
+
+ // Cache the variant value. We must not cache the QScriptValue here, because it's a
+ // reference and the user might change the actual object.
+ qbsEngine->addToPropertyCache(moduleName, propertyName, properties, value);
+ }
+ return engine->toScriptValue(value);
+}
+
+QString ModuleProperties::internalModuleName(const QString &name)
+{
+ QString result = name;
+ result.replace(QLatin1Char('.'), QLatin1Char('/'));
+ return result;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/moduleproperties.h b/src/lib/corelib/jsextensions/moduleproperties.h
new file mode 100644
index 000000000..81f27f6ec
--- /dev/null
+++ b/src/lib/corelib/jsextensions/moduleproperties.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#ifndef QBS_MODULEPROPERTIES_H
+#define QBS_MODULEPROPERTIES_H
+
+#include <buildgraph/forward_decls.h>
+#include <language/forward_decls.h>
+
+#include <QScriptContext>
+#include <QScriptValue>
+
+namespace qbs {
+namespace Internal {
+
+class ModuleProperties
+{
+public:
+ static void init(QScriptValue productObject, const ResolvedProductConstPtr &product);
+ static void init(QScriptValue artifactObject, const Artifact *artifact);
+
+private:
+ static void init(QScriptValue objectWithProperties, const void *ptr, const QString &type);
+
+ static QScriptValue js_moduleProperties(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_moduleProperty(QScriptContext *context, QScriptEngine *engine);
+
+ static QScriptValue moduleProperties(QScriptContext *context, QScriptEngine *engine,
+ bool oneValue);
+ static QString internalModuleName(const QString &name);
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // QBS_MODULEPROPERTIES_H
diff --git a/src/lib/corelib/jsextensions/process.cpp b/src/lib/corelib/jsextensions/process.cpp
new file mode 100644
index 000000000..3cf74ab31
--- /dev/null
+++ b/src/lib/corelib/jsextensions/process.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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 "process.h"
+
+#include <logging/translator.h>
+#include <tools/hostosinfo.h>
+
+#include <QProcess>
+#include <QScriptEngine>
+#include <QScriptValue>
+#include <QTextCodec>
+#include <QTextStream>
+
+namespace qbs {
+namespace Internal {
+
+void initializeJsExtensionProcess(QScriptValue extensionObject)
+{
+ QScriptEngine *engine = extensionObject.engine();
+ QScriptValue obj = engine->newQMetaObject(&Process::staticMetaObject, engine->newFunction(&Process::ctor));
+ extensionObject.setProperty("Process", obj);
+}
+
+QScriptValue Process::ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ Process *t;
+ switch (context->argumentCount()) {
+ case 0:
+ t = new Process(context);
+ break;
+ default:
+ return context->throwError("Process()");
+ }
+
+ QScriptValue obj = engine->newQObject(t, QScriptEngine::ScriptOwnership);
+
+ // Get environment
+ QVariant v = engine->property("_qbs_procenv");
+ if (!v.isNull())
+ t->m_environment
+ = QProcessEnvironment(*reinterpret_cast<QProcessEnvironment*>(v.value<void*>()));
+
+ return obj;
+}
+
+Process::~Process()
+{
+ delete m_textStream;
+ delete m_qProcess;
+}
+
+Process::Process(QScriptContext *context)
+{
+ Q_UNUSED(context);
+ Q_ASSERT(thisObject().engine() == engine());
+
+ m_qProcess = new QProcess;
+ m_textStream = new QTextStream(m_qProcess);
+}
+
+QString Process::getEnv(const QString &name)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ return m_environment.value(name);
+}
+
+void Process::setEnv(const QString &name, const QString &value)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ m_environment.insert(name, value);
+}
+
+QString Process::workingDirectory()
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ return m_workingDirectory;
+}
+
+void Process::setWorkingDirectory(const QString &dir)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ m_workingDirectory = dir;
+}
+
+bool Process::start(const QString &program, const QStringList &arguments)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+
+ if (!m_workingDirectory.isEmpty())
+ m_qProcess->setWorkingDirectory(m_workingDirectory);
+
+ m_qProcess->setProcessEnvironment(m_environment);
+ m_qProcess->start(program, arguments);
+ return m_qProcess->waitForStarted();
+}
+
+int Process::exec(const QString &program, const QStringList &arguments, bool throwOnError)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+
+ if (!start(program, arguments)) {
+ if (throwOnError) {
+ context()->throwError(Tr::tr("Error running '%1': %2")
+ .arg(program, m_qProcess->errorString()));
+ }
+ return -1;
+ }
+ m_qProcess->closeWriteChannel();
+ m_qProcess->waitForFinished(-1);
+ if (throwOnError) {
+ if (m_qProcess->error() != QProcess::UnknownError) {
+ context()->throwError(Tr::tr("Error running '%1': %2")
+ .arg(program, m_qProcess->errorString()));
+ } else if (m_qProcess->exitCode() != 0) {
+ QString errorMessage = Tr::tr("Process '%1' finished with exit code %2.")
+ .arg(program).arg(m_qProcess->exitCode());
+ const QString stdErr = readStdErr();
+ if (!stdErr.isEmpty())
+ errorMessage.append(Tr::tr(" The standard error output was:\n")).append(stdErr);
+ context()->throwError(errorMessage);
+ }
+ }
+ if (m_qProcess->error() != QProcess::UnknownError)
+ return -1;
+ return m_qProcess->exitCode();
+}
+
+void Process::close()
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ delete m_qProcess;
+ m_qProcess = 0;
+ delete m_textStream;
+ m_textStream = 0;
+}
+
+bool Process::waitForFinished(int msecs)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+
+ if (m_qProcess->state() == QProcess::NotRunning)
+ return true;
+ return m_qProcess->waitForFinished(msecs);
+}
+
+void Process::terminate()
+{
+ m_qProcess->terminate();
+}
+
+void Process::kill()
+{
+ m_qProcess->kill();
+}
+
+void Process::setCodec(const QString &codec)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ m_textStream->setCodec(qPrintable(codec));
+}
+
+QString Process::readLine()
+{
+ return m_textStream->readLine();
+}
+
+QString Process::readStdOut()
+{
+ return m_textStream->readAll();
+}
+
+QString Process::readStdErr()
+{
+ return m_textStream->codec()->toUnicode(m_qProcess->readAllStandardError());
+}
+
+int Process::exitCode() const
+{
+ return m_qProcess->exitCode();
+}
+
+void Process::write(const QString &str)
+{
+ (*m_textStream) << str;
+}
+
+void Process::writeLine(const QString &str)
+{
+ (*m_textStream) << str;
+ if (HostOsInfo::isWindowsHost())
+ (*m_textStream) << '\r';
+ (*m_textStream) << '\n';
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/process.h b/src/lib/corelib/jsextensions/process.h
new file mode 100644
index 000000000..1dea021a3
--- /dev/null
+++ b/src/lib/corelib/jsextensions/process.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#ifndef QBS_PROCESS_H
+#define QBS_PROCESS_H
+
+#include <QObject>
+#include <QProcessEnvironment>
+#include <QScriptable>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+class QProcess;
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace qbs {
+namespace Internal {
+void initializeJsExtensionProcess(QScriptValue extensionObject);
+
+class Process : public QObject, public QScriptable
+{
+ Q_OBJECT
+public:
+ static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine);
+ Process(QScriptContext *context);
+ ~Process();
+
+ Q_INVOKABLE QString getEnv(const QString &name);
+ Q_INVOKABLE void setEnv(const QString &name, const QString &value);
+ Q_INVOKABLE void setCodec(const QString &codec);
+
+ Q_INVOKABLE QString workingDirectory();
+ Q_INVOKABLE void setWorkingDirectory(const QString &dir);
+
+ Q_INVOKABLE bool start(const QString &program, const QStringList &arguments);
+ Q_INVOKABLE int exec(const QString &program, const QStringList &arguments,
+ bool throwOnError = false);
+ Q_INVOKABLE void close();
+ Q_INVOKABLE bool waitForFinished(int msecs = 30000);
+ Q_INVOKABLE void terminate();
+ Q_INVOKABLE void kill();
+
+ Q_INVOKABLE QString readLine();
+ Q_INVOKABLE QString readStdOut();
+ Q_INVOKABLE QString readStdErr();
+
+ Q_INVOKABLE void write(const QString &str);
+ Q_INVOKABLE void writeLine(const QString &str);
+
+ Q_INVOKABLE int exitCode() const;
+
+private:
+ QProcess *m_qProcess;
+ QProcessEnvironment m_environment;
+ QString m_workingDirectory;
+ QTextStream *m_textStream;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+Q_DECLARE_METATYPE(qbs::Internal::Process *)
+
+#endif // QBS_PROCESS_H
diff --git a/src/lib/corelib/jsextensions/textfile.cpp b/src/lib/corelib/jsextensions/textfile.cpp
new file mode 100644
index 000000000..7129ee955
--- /dev/null
+++ b/src/lib/corelib/jsextensions/textfile.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** 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 "textfile.h"
+
+#include <tools/hostosinfo.h>
+
+#include <QFile>
+#include <QScriptEngine>
+#include <QScriptValue>
+#include <QTextStream>
+
+namespace qbs {
+namespace Internal {
+
+void initializeJsExtensionTextFile(QScriptValue extensionObject)
+{
+ QScriptEngine *engine = extensionObject.engine();
+ QScriptValue obj = engine->newQMetaObject(&TextFile::staticMetaObject, engine->newFunction(&TextFile::ctor));
+ extensionObject.setProperty("TextFile", obj);
+}
+
+QScriptValue TextFile::ctor(QScriptContext *context, QScriptEngine *engine)
+{
+ TextFile *t;
+ switch (context->argumentCount()) {
+ case 1:
+ t = new TextFile(context,
+ context->argument(0).toString());
+ break;
+ case 2:
+ t = new TextFile(context,
+ context->argument(0).toString(),
+ static_cast<OpenMode>(context->argument(1).toInt32())
+ );
+ break;
+ case 3:
+ t = new TextFile(context,
+ context->argument(0).toString(),
+ static_cast<OpenMode>(context->argument(1).toInt32()),
+ context->argument(2).toString()
+ );
+ break;
+ default:
+ return context->throwError("TextFile(QString file, OpenMode mode = ReadOnly, QString codec = QLatin1String(\"UTF8\"))");
+ }
+
+ QScriptValue obj = engine->newQObject(t, QScriptEngine::ScriptOwnership);
+// obj.setProperty("d", engine->newQObject(new FileImplementation(t),
+// QScriptEngine::QScriptEngine::QtOwnership));
+ return obj;
+}
+
+TextFile::~TextFile()
+{
+ delete qstream;
+ delete qfile;
+}
+
+TextFile::TextFile(QScriptContext *context, const QString &file, OpenMode mode, const QString &codec)
+{
+ Q_UNUSED(codec)
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = this;
+
+ t->qfile = new QFile(file);
+ QIODevice::OpenMode m = QIODevice::ReadOnly;
+ if (mode == ReadWrite)
+ m = QIODevice::ReadWrite;
+ else if (mode == ReadOnly)
+ m = QIODevice::ReadOnly;
+ else if (mode == WriteOnly)
+ m = QIODevice::WriteOnly;
+ if (Q_UNLIKELY(!t->qfile->open(m))) {
+ delete t->qfile;
+ t->qfile = 0;
+ context->throwError(QString::fromLatin1("unable to open '%1'")
+ .arg(file)
+ );
+ }
+
+ t->qstream = new QTextStream(t->qfile);
+}
+
+void TextFile::close()
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (t->qfile)
+ t->qfile->close();
+ delete t->qfile;
+ t->qfile = 0;
+ delete t->qstream;
+ t->qstream = 0;
+}
+
+void TextFile::setCodec(const QString &codec)
+{
+ Q_ASSERT(thisObject().engine() == engine());
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ t->qstream->setCodec(qPrintable(codec));
+}
+
+QString TextFile::readLine()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qfile)
+ return QString();
+ return t->qstream->readLine();
+}
+
+QString TextFile::readAll()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qfile)
+ return QString();
+ return t->qstream->readAll();
+}
+
+bool TextFile::atEof() const
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return true;
+ return t->qstream->atEnd();
+}
+
+void TextFile::truncate()
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ t->qfile->resize(0);
+ t->qstream->reset();
+}
+
+void TextFile::write(const QString &str)
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ (*t->qstream) << str;
+}
+
+void TextFile::writeLine(const QString &str)
+{
+ TextFile *t = qscriptvalue_cast<TextFile*>(thisObject());
+ if (!t->qstream)
+ return;
+ (*t->qstream) << str;
+ if (HostOsInfo::isWindowsHost())
+ (*t->qstream) << '\r';
+ (*t->qstream) << '\n';
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/textfile.h b/src/lib/corelib/jsextensions/textfile.h
new file mode 100644
index 000000000..ff8aaf43b
--- /dev/null
+++ b/src/lib/corelib/jsextensions/textfile.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#ifndef QBS_TEXTFILE_H
+#define QBS_TEXTFILE_H
+
+#include <QObject>
+#include <QScriptable>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace qbs {
+namespace Internal {
+
+void initializeJsExtensionTextFile(QScriptValue extensionObject);
+
+class TextFile : public QObject, public QScriptable
+{
+ Q_OBJECT
+ Q_ENUMS(OpenMode)
+public:
+ enum OpenMode { ReadOnly, WriteOnly, ReadWrite };
+ static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine);
+ TextFile(QScriptContext *context, const QString &file, OpenMode mode = ReadOnly, const QString &codec = QLatin1String("UTF8"));
+ ~TextFile();
+ Q_INVOKABLE void close();
+ Q_INVOKABLE void setCodec(const QString &codec);
+ Q_INVOKABLE QString readLine();
+ Q_INVOKABLE QString readAll();
+ Q_INVOKABLE bool atEof() const;
+ Q_INVOKABLE void truncate();
+ Q_INVOKABLE void write(const QString &str);
+ Q_INVOKABLE void writeLine(const QString &str);
+private:
+ QFile *qfile;
+ QTextStream *qstream;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+Q_DECLARE_METATYPE(qbs::Internal::TextFile *)
+
+#endif // QBS_TEXTFILE_H