aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Lira <marcelo.lira@openbossa.org>2011-01-24 21:17:27 -0300
committerMarcelo Lira <marcelo.lira@openbossa.org>2011-01-25 08:32:20 -0300
commit5f6d08e17f214d7d3a41a1cbdfb2d975e02a33cd (patch)
tree4287dc5ba6eafe5db035ea661ef3133a67aa196c
parent13480bf7867bed1cfa64613fddb0d6e53aa36b9e (diff)
Modified GeneratorRunner to support a simpler format of project file.
The project file are now just a text file containing key/value pairs. The documentation was updated accordingly, including the man page.
-rw-r--r--data/generatorrunner.112
-rw-r--r--doc/projectfile.rst40
-rw-r--r--main.cpp101
-rw-r--r--tests/test_generator/CMakeLists.txt6
-rw-r--r--tests/test_generator/dummygenerator.cpp22
-rw-r--r--tests/test_generator/dummygenerator.h2
-rw-r--r--tests/test_generator/dummygentest-project.txt.in20
-rw-r--r--tests/test_generator/dummygentest.cpp102
-rw-r--r--tests/test_generator/dummygentest.h9
-rw-r--r--tests/test_generator/test_global.h1
-rw-r--r--tests/test_generator/test_typesystem.xml3
11 files changed, 190 insertions, 128 deletions
diff --git a/data/generatorrunner.1 b/data/generatorrunner.1
index 60749d951..072d373a1 100644
--- a/data/generatorrunner.1
+++ b/data/generatorrunner.1
@@ -9,17 +9,17 @@ generatorrunner - plugin-based binding source code generator
is a utility that uses the information taken from APIExtractor
related to the provided C++ headers and typesystem files and execute
generators using this information. Generators are plugins and you need
-to specify one using the \-\-generatorSet parameter. At the moment there
+to specify one using the \-\-generatorSet parameter. At the moment there
are two generators available:
.B qtdoc
-\- Generates Sphinx-based documentation for C++ libraries documented using
-.B qdoc3
-documentation syntax, using the XML files created by the documentation tool
+\- Generates Sphinx-based documentation for C++ libraries documented using
+.B qdoc3
+documentation syntax, using the XML files created by the documentation tool
.B (qdoc3).
Can be called supplying
.B \-\-generatorSet=qtdoc
-to
+to
.B generatorrunner
or by calling the convenience executable
.B docgenerator.
@@ -40,6 +40,8 @@ Only generates the documentation.
.TP
.BI \-\-help \fR,\fP \-h \fR,\fP -?
Prints the usage message.
+.IP \-\-project-file=<file>
+Text file containing a description of the binding project. Replaces and overrides command line arguments.
.IP \-\-include\-paths=\fI<path>[:path:..]\fR
The directories where the generator will search for the
headers. Works like gcc's \-I flag.
diff --git a/doc/projectfile.rst b/doc/projectfile.rst
index 6b91bc9dd..f0ea7b421 100644
--- a/doc/projectfile.rst
+++ b/doc/projectfile.rst
@@ -5,7 +5,7 @@ Binding Project File
********************
Instead of directing the Generator behaviour via command line, the binding developer
-can write a XML project file describing the same information, and avoid the hassle
+can write a text project file describing the same information, and avoid the hassle
of a long stream of command line arguments.
.. _project-file-structure:
@@ -15,24 +15,18 @@ The project file structure
Here follows a comprehensive example of a generator project file.
- .. code-block:: xml
-
- <?xml version="1.0"?>
- <generator-project>
- <generator-set generator="path/to/generator/CHOICE_GENERATOR" />
- <header-file location="DIR/global.h" />
- <typesystem-file location="DIR/typesystem_for_your_binding.xml" />
- <output-directory location="OUTPUTDIR" />
- <include-paths>
- <path location="path/to/library/being/wrapped/headers/1" />
- <path location="path/to/library/being/wrapped/headers/2" />
- </include-paths>
- <typesystem-paths>
- <path location="path/to/directory/containing/type/system/files/1" />
- <path location="path/to/directory/containing/type/system/files/2" />
- </typesystem-paths>
- <enable-parent-ctor-heuristic />
- </generator-project>
+ .. code-block:: ini
+
+ [generator-project]
+ generator-set = path/to/generator/CHOICE_GENERATOR
+ header-file = DIR/global.h" />
+ typesystem-file = DIR/typesystem_for_your_binding.xml
+ output-directory location="OUTPUTDIR" />
+ include-path = path/to/library/being/wrapped/headers/1
+ include-path = path/to/library/being/wrapped/headers/2
+ typesystem-path = path/to/directory/containing/type/system/files/1
+ typesystem-path = path/to/directory/containing/type/system/files/2
+ enable-parent-ctor-heuristic
Project file tags
@@ -52,9 +46,9 @@ For tags without options, just write as an empty tag without any attributes. Exa
becomes
- .. code-block:: xml
+ .. code-block:: ini
- <BOOLEAN-ARGUMENT />
+ BOOLEAN-ARGUMENT
and
@@ -64,8 +58,8 @@ and
becomes
- .. code-block:: xml
+ .. code-block:: ini
- <VALUE-ARGUMENT value="VALUE" />
+ VALUE-ARGUMENT = VALUE
diff --git a/main.cpp b/main.cpp
index 782f6b514..1e4e65fe8 100644
--- a/main.cpp
+++ b/main.cpp
@@ -50,17 +50,49 @@ static void printOptions(QTextStream& s, const QMap<QString, QString>& options)
typedef void (*getGeneratorsFunc)(QLinkedList<Generator*>*);
-static QString getPathString(const QDomElement& element)
+static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
{
- QStringList path;
- QDomNode n = element.firstChild();
- while (!n.isNull()) {
- QDomElement e = n.toElement(); // try to convert the node to an element.
- if (e.tagName() == "path")
- path << QDir::toNativeSeparators(e.attribute("location"));
- n = n.nextSibling();
+ QByteArray line = projectFile.readLine().trimmed();
+ if (line.isEmpty() || line != "[generator-project]")
+ return false;
+
+ QStringList includePaths;
+ QStringList typesystemPaths;
+
+ while (!projectFile.atEnd()) {
+ line = projectFile.readLine().trimmed();
+ if (line.isEmpty())
+ continue;
+
+ int split = line.indexOf("=");
+ QString key;
+ QString value;
+ if (split > 0) {
+ key = line.left(split - 1).trimmed();
+ value = line.mid(split + 1).trimmed();
+ } else {
+ key = line;
+ }
+
+ if (key == "include-path")
+ includePaths << QDir::toNativeSeparators(value);
+ else if (key == "typesystem-path")
+ typesystemPaths << QDir::toNativeSeparators(value);
+ else if (key == "header-file")
+ args["arg-1"] = value;
+ else if (key == "typesystem-file")
+ args["arg-2"] = value;
+ else
+ args[key] = value;
}
- return path.join(PATH_SPLITTER);
+
+ if (!includePaths.isEmpty())
+ args["include-paths"] = includePaths.join(PATH_SPLITTER);
+
+ if (!typesystemPaths.isEmpty())
+ args["typesystem-paths"] = typesystemPaths.join(PATH_SPLITTER);
+
+ return true;
}
static QMap<QString, QString> getInitializedArguments()
@@ -84,7 +116,9 @@ static QMap<QString, QString> getInitializedArguments()
return args;
if (!QFile::exists(projectFileName)) {
- std::cerr << qPrintable(appName) << ": Project file \"" << qPrintable(projectFileName) << "\" not found." << std::endl;
+ std::cerr << qPrintable(appName) << ": Project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" not found.";
+ std::cerr << std::endl;
return args;
}
@@ -92,40 +126,12 @@ static QMap<QString, QString> getInitializedArguments()
if (!projectFile.open(QIODevice::ReadOnly))
return args;
- QDomDocument doc("project-file");
- if (!doc.setContent(&projectFile)) {
- projectFile.close();
+ if (!processProjectFile(projectFile, args)) {
+ std::cerr << qPrintable(appName) << ": first line of project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" must be the string \"[generator-project]\"";
+ std::cerr << std::endl;
return args;
}
- projectFile.close();
-
- QDomElement docElem = doc.documentElement();
- QDomNode n = docElem.firstChild();
- while (!n.isNull()) {
- QDomElement e = n.toElement(); // try to convert the node to an element.
- if (!e.isNull()) {
- QString tag = e.tagName();
- if (tag == "generator-set")
- args[tag] = e.attribute("generator");
- else if (tag == "output-directory" || tag == "license-file")
- args[tag] = e.attribute("location");
- else if (tag == "api-version")
- args[tag] = e.attribute("version");
- else if (tag == "debug")
- args[tag] = e.attribute("level");
- else if (tag == "documentation-only" || tag == "no-suppress-warnings" || tag == "silent")
- args[tag] = QString();
- else if (tag == "include-paths" || tag == "typesystem-paths")
- args[tag] = getPathString(e);
- else if (tag == "header-file")
- args["arg-1"] = e.attribute("location");
- else if (tag == "typesystem-file")
- args["arg-2"] = e.attribute("location");
- else
- args[tag] = e.attribute("value");
- }
- n = n.nextSibling();
- }
return args;
}
@@ -133,7 +139,6 @@ static QMap<QString, QString> getInitializedArguments()
static QMap<QString, QString> getCommandLineArgs()
{
QMap<QString, QString> args = getInitializedArguments();
-
QStringList arguments = QCoreApplication::arguments();
arguments.removeFirst();
@@ -163,19 +168,19 @@ void printUsage(const GeneratorList& generators)
<< "generator [options] header-file typesystem-file\n\n"
"General options:\n";
QMap<QString, QString> generalOptions;
- generalOptions.insert("project-file=[file]", "XML file containing a description of the binding project. Replaces and overrides command line arguments");
+ generalOptions.insert("project-file=<file>", "text file containing a description of the binding project. Replaces and overrides command line arguments");
generalOptions.insert("debug-level=[sparse|medium|full]", "Set the debug level");
generalOptions.insert("silent", "Avoid printing any message");
generalOptions.insert("help", "Display this help and exit");
generalOptions.insert("no-suppress-warnings", "Show all warnings");
- generalOptions.insert("output-directory=[dir]", "The directory where the generated files will be written");
+ generalOptions.insert("output-directory=<path>", "The directory where the generated files will be written");
generalOptions.insert("include-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Include paths used by the C++ parser");
generalOptions.insert("typesystem-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Paths used when searching for typesystems");
generalOptions.insert("documentation-only", "Do not generates any code, just the documentation");
- generalOptions.insert("license-file=[license-file]", "File used for copyright headers of generated files");
+ generalOptions.insert("license-file=<license-file>", "File used for copyright headers of generated files");
generalOptions.insert("version", "Output version information and exit");
- generalOptions.insert("generator-set", "generator-set to be used. e.g. qtdoc");
- generalOptions.insert("api-version", "Specify the supported api version used to generate the bindings");
+ generalOptions.insert("generator-set=<\"generator module\">", "generator-set to be used. e.g. qtdoc");
+ generalOptions.insert("api-version=<\"version\">", "Specify the supported api version used to generate the bindings");
printOptions(s, generalOptions);
foreach (Generator* generator, generators) {
diff --git a/tests/test_generator/CMakeLists.txt b/tests/test_generator/CMakeLists.txt
index c8dd017e4..180bba273 100644
--- a/tests/test_generator/CMakeLists.txt
+++ b/tests/test_generator/CMakeLists.txt
@@ -40,6 +40,12 @@ macro(declare_test testname)
set_property(TEST ${testname} PROPERTY ENVIRONMENT "PATH=${ENV_PATH}" "QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}")
endmacro(declare_test testname)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_global.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_global.h" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_typesystem.xml"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_typesystem.xml" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dummygentest-project.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/dummygentest-project.txt" @ONLY)
declare_test(dummygentest)
add_dependencies(dummygenerator generatorrunner)
diff --git a/tests/test_generator/dummygenerator.cpp b/tests/test_generator/dummygenerator.cpp
index fc3912fe6..795d7afd3 100644
--- a/tests/test_generator/dummygenerator.cpp
+++ b/tests/test_generator/dummygenerator.cpp
@@ -40,3 +40,25 @@ DummyGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass
s << "// Generated code for class: " << qPrintable(metaClass->name()) << endl;
}
+bool
+DummyGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ if (args.contains("dump-arguments") && !args["dump-arguments"].isEmpty()) {
+ QFile logFile(args["dump-arguments"]);
+ logFile.open(QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream out(&logFile);
+ foreach (const QString& key, args.keys()) {
+ if (key == "arg-1")
+ out << "header-file";
+ else if (key == "arg-2")
+ out << "typesystem-file";
+ else
+ out << key;
+ if (!args[key].isEmpty())
+ out << " = " << args[key];
+ out << endl;
+ }
+ }
+ return true;
+}
+
diff --git a/tests/test_generator/dummygenerator.h b/tests/test_generator/dummygenerator.h
index 154dc2579..079c1d5b6 100644
--- a/tests/test_generator/dummygenerator.h
+++ b/tests/test_generator/dummygenerator.h
@@ -30,7 +30,7 @@ class GENRUNNER_API DummyGenerator : public Generator
public:
DummyGenerator() {}
~DummyGenerator() {}
- bool doSetup(const QMap<QString, QString>& args) { return true; }
+ bool doSetup(const QMap<QString, QString>& args);
const char* name() const { return "DummyGenerator"; }
protected:
diff --git a/tests/test_generator/dummygentest-project.txt.in b/tests/test_generator/dummygentest-project.txt.in
new file mode 100644
index 000000000..0a076d8bd
--- /dev/null
+++ b/tests/test_generator/dummygentest-project.txt.in
@@ -0,0 +1,20 @@
+[generator-project]
+
+generator-set = dummy
+header-file = @CMAKE_CURRENT_BINARY_DIR@/test_global.h
+typesystem-file = @CMAKE_CURRENT_BINARY_DIR@/test_typesystem.xml
+output-directory = /tmp/output
+
+dump-arguments = @CMAKE_CURRENT_BINARY_DIR@/dummygen-args.log
+
+include-path = /include/path/location1
+include-path = /include/path/location2
+
+typesystem-path = /typesystem/path/location1
+typesystem-path = /typesystem/path/location2
+
+api-version = 1.2.3
+debug = sparse
+
+no-suppress-warnings
+
diff --git a/tests/test_generator/dummygentest.cpp b/tests/test_generator/dummygentest.cpp
index 55fe3b45f..3261a3cac 100644
--- a/tests/test_generator/dummygentest.cpp
+++ b/tests/test_generator/dummygentest.cpp
@@ -28,35 +28,32 @@
#include <QtTest/QTest>
#include <QProcess>
-#define HEADER_CONTENTS "struct Dummy {};"
-#define TYPESYSTEM_CONTENTS "<typesystem package='dummy'><value-type name='Dummy'/></typesystem>"
#define GENERATED_CONTENTS "// Generated code for class: Dummy"
-#define GENERATED_FILE "dummy/dummy_generated.txt"
-void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule()
+void DummyGenTest::initTestCase()
{
- QTemporaryFile headerFile;
- headerFile.open();
- QCOMPARE(headerFile.write(HEADER_CONTENTS), qint64(sizeof(HEADER_CONTENTS)-1));
- headerFile.close();
-
- QTemporaryFile typesystemFile;
- typesystemFile.open();
- QCOMPARE(typesystemFile.write(TYPESYSTEM_CONTENTS), qint64(sizeof(TYPESYSTEM_CONTENTS)-1));
- typesystemFile.close();
-
- QString generatedFileName = QString("%1/" GENERATED_FILE).arg(QDir::tempPath());
- QFile::remove(generatedFileName);
+ int argc = 0;
+ char* argv[] = {NULL};
+ QCoreApplication app(argc, argv);
+ workDir = QCoreApplication::applicationDirPath();
+
+ headerFilePath = workDir + "/test_global.h";
+ typesystemFilePath = workDir + "/test_typesystem.xml";
+ projectFilePath = workDir + "/dummygentest-project.txt";
+ generatedFilePath = QString("%1/dummy/dummy_generated.txt").arg(QDir::tempPath());
+}
+void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule()
+{
QStringList args;
args.append("--generator-set=" DUMMYGENERATOR_BINARY_DIR "/dummy_generator" MODULE_EXTENSION);
args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
- args.append(headerFile.fileName());
- args.append(typesystemFile.fileName());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
int result = QProcess::execute("generatorrunner", args);
QCOMPARE(result, 0);
- QFile generatedFile(generatedFileName);
+ QFile generatedFile(generatedFilePath);
generatedFile.open(QIODevice::ReadOnly);
QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
generatedFile.close();
@@ -66,28 +63,15 @@ void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule()
void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule()
{
- QTemporaryFile headerFile;
- headerFile.open();
- QCOMPARE(headerFile.write(HEADER_CONTENTS), qint64(sizeof(HEADER_CONTENTS)-1));
- headerFile.close();
-
- QTemporaryFile typesystemFile;
- typesystemFile.open();
- QCOMPARE(typesystemFile.write(TYPESYSTEM_CONTENTS), qint64(sizeof(TYPESYSTEM_CONTENTS)-1));
- typesystemFile.close();
-
- QString generatedFileName = QString("%1/" GENERATED_FILE).arg(QDir::tempPath());
- QFile::remove(generatedFileName);
-
QStringList args;
args.append("--generator-set=dummy");
args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
- args.append(headerFile.fileName());
- args.append(typesystemFile.fileName());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
int result = QProcess::execute("generatorrunner", args);
QCOMPARE(result, 0);
- QFile generatedFile(generatedFileName);
+ QFile generatedFile(generatedFilePath);
generatedFile.open(QIODevice::ReadOnly);
QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
generatedFile.close();
@@ -97,27 +81,14 @@ void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule()
void DummyGenTest::testCallDummyGeneratorExecutable()
{
- QTemporaryFile headerFile;
- headerFile.open();
- QCOMPARE(headerFile.write(HEADER_CONTENTS), qint64(sizeof(HEADER_CONTENTS)-1));
- headerFile.close();
-
- QTemporaryFile typesystemFile;
- typesystemFile.open();
- QCOMPARE(typesystemFile.write(TYPESYSTEM_CONTENTS), qint64(sizeof(TYPESYSTEM_CONTENTS)-1));
- typesystemFile.close();
-
- QString generatedFileName = QString("%1/" GENERATED_FILE).arg(QDir::tempPath());
- QFile::remove(generatedFileName);
-
QStringList args;
args.append(QString("--output-directory=%1").arg(QDir::tempPath()));
- args.append(headerFile.fileName());
- args.append(typesystemFile.fileName());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
int result = QProcess::execute(DUMMYGENERATOR_BINARY, args);
QCOMPARE(result, 0);
- QFile generatedFile(generatedFileName);
+ QFile generatedFile(generatedFilePath);
generatedFile.open(QIODevice::ReadOnly);
QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
generatedFile.close();
@@ -125,6 +96,35 @@ void DummyGenTest::testCallDummyGeneratorExecutable()
QVERIFY(generatedFile.remove());
}
+void DummyGenTest::testProjectFileArgumentsReading()
+{
+ QStringList args(QString("--project-file=%1/dummygentest-project.txt").arg(workDir));
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile logFile(workDir + "/dummygen-args.log");
+ logFile.open(QIODevice::ReadOnly);
+ QStringList logContents;
+ while (!logFile.atEnd())
+ logContents << logFile.readLine().trimmed();
+ logContents.sort();
+ QCOMPARE(logContents[0], QString("api-version = 1.2.3"));
+ QCOMPARE(logContents[1], QString("debug = sparse"));
+ QVERIFY(logContents[2].startsWith("dump-arguments = "));
+ QVERIFY(logContents[2].endsWith("dummygen-args.log"));
+ QCOMPARE(logContents[3], QString("generator-set = dummy"));
+ QVERIFY(logContents[4].startsWith("header-file = "));
+ QVERIFY(logContents[4].endsWith("test_global.h"));
+ QCOMPARE(logContents[5], QString("include-paths = /include/path/location1:/include/path/location2"));
+ QCOMPARE(logContents[6], QString("no-suppress-warnings"));
+ QCOMPARE(logContents[7], QString("output-directory = /tmp/output"));
+ QVERIFY(logContents[8].startsWith("project-file = "));
+ QVERIFY(logContents[8].endsWith("dummygentest-project.txt"));
+ QVERIFY(logContents[9].startsWith("typesystem-file = "));
+ QVERIFY(logContents[9].endsWith("test_typesystem.xml"));
+ QCOMPARE(logContents[10], QString("typesystem-paths = /typesystem/path/location1:/typesystem/path/location2"));
+}
+
QTEST_APPLESS_MAIN(DummyGenTest)
#include "dummygentest.moc"
diff --git a/tests/test_generator/dummygentest.h b/tests/test_generator/dummygentest.h
index 0bfab2a0d..0f485ae81 100644
--- a/tests/test_generator/dummygentest.h
+++ b/tests/test_generator/dummygentest.h
@@ -32,10 +32,19 @@ class DummyGenTest : public QObject
{
Q_OBJECT
+private:
+ QString workDir;
+ QString headerFilePath;
+ QString typesystemFilePath;
+ QString generatedFilePath;
+ QString projectFilePath;
+
private slots:
+ void initTestCase();
void testCallGenRunnerWithFullPathToDummyGenModule();
void testCallGenRunnerWithNameOfDummyGenModule();
void testCallDummyGeneratorExecutable();
+ void testProjectFileArgumentsReading();
};
#endif
diff --git a/tests/test_generator/test_global.h b/tests/test_generator/test_global.h
new file mode 100644
index 000000000..6a95200cf
--- /dev/null
+++ b/tests/test_generator/test_global.h
@@ -0,0 +1 @@
+struct Dummy {};
diff --git a/tests/test_generator/test_typesystem.xml b/tests/test_generator/test_typesystem.xml
new file mode 100644
index 000000000..c19a4e95e
--- /dev/null
+++ b/tests/test_generator/test_typesystem.xml
@@ -0,0 +1,3 @@
+<typesystem package='dummy'>
+ <value-type name='Dummy'/>
+</typesystem>