diff options
author | Marcelo Lira <marcelo.lira@openbossa.org> | 2011-01-24 21:17:27 -0300 |
---|---|---|
committer | Marcelo Lira <marcelo.lira@openbossa.org> | 2011-01-25 08:32:20 -0300 |
commit | 5f6d08e17f214d7d3a41a1cbdfb2d975e02a33cd (patch) | |
tree | 4287dc5ba6eafe5db035ea661ef3133a67aa196c | |
parent | 13480bf7867bed1cfa64613fddb0d6e53aa36b9e (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.1 | 12 | ||||
-rw-r--r-- | doc/projectfile.rst | 40 | ||||
-rw-r--r-- | main.cpp | 101 | ||||
-rw-r--r-- | tests/test_generator/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/test_generator/dummygenerator.cpp | 22 | ||||
-rw-r--r-- | tests/test_generator/dummygenerator.h | 2 | ||||
-rw-r--r-- | tests/test_generator/dummygentest-project.txt.in | 20 | ||||
-rw-r--r-- | tests/test_generator/dummygentest.cpp | 102 | ||||
-rw-r--r-- | tests/test_generator/dummygentest.h | 9 | ||||
-rw-r--r-- | tests/test_generator/test_global.h | 1 | ||||
-rw-r--r-- | tests/test_generator/test_typesystem.xml | 3 |
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 @@ -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> |