summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL.md7
-rw-r--r--README.md10
-rw-r--r--USAGE.md96
-rwxr-xr-xcli.py35
-rwxr-xr-xgenerator/csv/csv.py2
-rw-r--r--generator/csv/templates/packages.csv6
-rw-r--r--generator/qfacegen/qfacegen.py26
-rw-r--r--generator/qfacegen/templates/document.qface39
-rw-r--r--generator/qtcpp/log.yaml18
-rw-r--r--generator/qtcpp/qtcpp.py12
-rw-r--r--input_csv.yml2
-rw-r--r--requirements.txt1
-rw-r--r--templates/packages.csv11
-rw-r--r--tuner_cpp.yml2
14 files changed, 232 insertions, 35 deletions
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..7f57b31
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,7 @@
+# Installation
+
+ pip3 install -r requirements.txt
+
+# Parser Generation (Optional)
+
+For updating the grammar you also need antlr4 (see http://www.antlr.org).
diff --git a/README.md b/README.md
index 75a55a4..3a249c9 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,7 @@
# QML Interface Builder
-Infrastructure to build a QML/Qt CPP interface based on an interface definition language and templates
+Infrastructure to build a QML/Qt CPP interface based on an interface definition language and templates.
-# Dependencies
+This tool set is not build for highest performance. Rather flexinility in the IDL design and generator creation was the goal. It uses great libraries to minimize the amount of code to be written by the user.
-- Python3
-- ANTLR4
-- Jinja Templates
-
-# Running
+Please see the INSTALL and USAGE guides for more information.
diff --git a/USAGE.md b/USAGE.md
new file mode 100644
index 0000000..91c700e
--- /dev/null
+++ b/USAGE.md
@@ -0,0 +1,96 @@
+# Usage
+
+There is a central client to interface the commands for generation, called cli.
+
+To use an existing generator just provide the path to the generator script.
+
+ ./cli.py generator --generator generator/csv --input input --output output
+
+You can also create a YAML configuration file (e.g csv.yaml):
+
+ generator: generator/csv
+ input: input
+ output: output
+
+And then call the client with:
+
+ ./cli.py generate --runner csv.yaml
+
+To enable auto-live reloading just use the monitor target:
+
+
+ ./cli.py generator_monitor --runner csv.yaml
+
+This will observe the generator folder and the input folder for changes and re-run the generator.
+
+# Grammar
+
+The IDL grammar is described in the grammar file (see qface/parser/idl/T.g4)
+
+ package <identifier> <version>;
+
+ [import <identifier> <version>];
+
+ service <identifier> {
+ (readonly) <type> <attribute>;
+ <type> <operation>([type name]);
+ event <type> <operation>([type name]);
+ list<type> <attribute>;
+ model<type> <attribute>;
+ }
+
+ enum <identifier> {
+ <name> = <value>
+ }
+
+ flag <identifier> {
+ <name> = <value>
+ }
+
+ struct <identifier> {
+ <type> <name>;
+ }
+
+
+# Domain Model
+
+The IDL is converted into an in memory domain model (see qface/idl/domain.py).
+
+ System
+ Package
+ Import
+ Service
+ Attribute
+ Operation
+ Enum
+ Struct
+
+The domain model is the base for the code generation.
+
+# Code Generation
+
+The code generation is driven by a small script which iterates over the domain model and writes files using a template language (see http://jinja.pocoo.org) and espcially the template designer documentation (http://jinja.pocoo.org/docs/dev/templates/).
+
+ from qface.generator import FileSystem, Generator
+
+ def generate(input, output):
+ system = FileSystem.parse_dir(input)
+ generator = Generator(searchpath='templates')
+ ctx = {'output': output, 'system': system}
+ generator.write('{{output}}/packages.csv', 'packages.csv', ctx)
+
+This script reads the input directory returns a system object form the domain model. This is used as the root object for the code generation inside the template language.
+
+ {% for package in system.packages %}
+ {%- for service in package.services -%}
+ SERVICE, {{package}}.{{service}}
+ {% endfor -%}
+ {%- for struct in package.structs -%}
+ STRUCT , {{package}}.{{struct}}
+ {% endfor -%}
+ {%- for enum in package.enums -%}
+ ENUM , {{package}}.{{enum}}
+ {% endfor -%}
+ {% endfor %}
+
+The tempate iterates over the domain objects and generates text which is written into a file. The file name is also adjustable using the same template language.
diff --git a/cli.py b/cli.py
index 441a50e..a31f574 100755
--- a/cli.py
+++ b/cli.py
@@ -69,9 +69,10 @@ def test_monitor(ctx):
class RunScriptChangeHandler(FileSystemEventHandler):
- def __init__(self, script):
+ def __init__(self, script, cwd=None):
super(RunTestChangeHandler).__init__()
self.script = script
+ self.cwd = cwd
def on_modified(self, event):
if event.src_path.endswith('.cache'):
@@ -79,18 +80,28 @@ class RunScriptChangeHandler(FileSystemEventHandler):
if event.is_directory:
return
print(event)
- sh('python3 {0}'.format(self.script))
+ sh('python3 {0}'.format(self.script), cwd=self.cwd)
@cli.command()
-@click.option('--script')
-def generator_monitor(script):
- print('run script: ' + script)
- event_handler = RunScriptChangeHandler(script)
+@click.option('--runner', type=click.File('r'))
+@click.option('--generator', type=click.Path(exists=True))
+@click.option('--input', type=click.Path(exists=True))
+@click.option('--output', type=click.Path(exists=True))
+def generator_monitor(runner, generator, input, output):
+ if runner:
+ config = yaml.load(runner)
+ generator = config['generator']
+ input = config['input']
+ output = config['output']
+ generator = Path(generator).absolute()
+ input = Path(input).absolute()
+ output = Path(output).absolute()
+ script = generator / '{0}.py --input {1} --output {2}'.format(generator.name, input, output)
+ event_handler = RunScriptChangeHandler(script, cwd=generator.as_posix())
observer = Observer()
- observer.schedule(event_handler, './templates', recursive=True)
- observer.schedule(event_handler, './examples', recursive=True)
- observer.schedule(event_handler, str(Path(script).parent), recursive=False)
+ observer.schedule(event_handler, generator.as_posix(), recursive=True)
+ observer.schedule(event_handler, input.as_posix(), recursive=True)
observer.start()
try:
while True:
@@ -111,9 +122,13 @@ def generate(runner, generator, input, output):
generator = config['generator']
input = config['input']
output = config['output']
+ generator = Path(generator).absolute()
+ script = '{0}.py'.format(generator.name)
input = Path(input).absolute()
output = Path(output).absolute()
- sh('python3 ./generator/{0}/{0}.py --input {1} --output {2}'.format(generator, input, output))
+ sh('python3 {0} --input {1} --output {2}'
+ .format(script, input, output),
+ cwd=generator.as_posix())
if __name__ == '__main__':
cli()
diff --git a/generator/csv/csv.py b/generator/csv/csv.py
index d96f972..96ebac1 100755
--- a/generator/csv/csv.py
+++ b/generator/csv/csv.py
@@ -5,7 +5,7 @@ from qface.generator import FileSystem, Generator
def generate(input, output):
system = FileSystem.parse_dir(input)
- generator = Generator(searchpath='./templates')
+ generator = Generator(searchpath='templates')
ctx = {'output': output, 'system': system}
generator.write('{{output}}/packages.csv', 'packages.csv', ctx)
diff --git a/generator/csv/templates/packages.csv b/generator/csv/templates/packages.csv
index d316387..cf95646 100644
--- a/generator/csv/templates/packages.csv
+++ b/generator/csv/templates/packages.csv
@@ -1,11 +1,11 @@
{% for package in system.packages %}
{%- for service in package.services -%}
- {{package}}.{{service}}, SERVICE
+ SERVICE, {{package}}.{{service}}
{% endfor -%}
{%- for struct in package.structs -%}
- {{package}}.{{struct}}, STRUCT
+ STRUCT , {{package}}.{{struct}}
{% endfor -%}
{%- for enum in package.enums -%}
- {{package}}.{{enum}}, ENUM
+ ENUM , {{package}}.{{enum}}
{% endfor -%}
{% endfor %}
diff --git a/generator/qfacegen/qfacegen.py b/generator/qfacegen/qfacegen.py
new file mode 100644
index 0000000..6806dad
--- /dev/null
+++ b/generator/qfacegen/qfacegen.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+import click
+import logging
+from qface.generator import FileSystem, Generator
+
+logging.basicConfig(filename='qfacegen.log', filemode='w', level=logging.DEBUG)
+
+def generate(input, output):
+ system = FileSystem.parse_dir(input)
+ generator = Generator(searchpath='./templates')
+ ctx = {'output': output}
+ for counter in range(200):
+ for package in system.packages:
+ ctx.update({'package': package, 'counter': counter})
+ generator.write('{{output}}/x{{package}}{{counter}}.qface', 'document.qface', ctx)
+
+
+@click.command()
+@click.option('--input', type=click.Path(exists=True))
+@click.option('--output', type=click.Path(exists=True))
+def runner(input, output):
+ generate(input, output)
+
+
+if __name__ == '__main__':
+ runner()
diff --git a/generator/qfacegen/templates/document.qface b/generator/qfacegen/templates/document.qface
new file mode 100644
index 0000000..f383274
--- /dev/null
+++ b/generator/qfacegen/templates/document.qface
@@ -0,0 +1,39 @@
+package {{package}}{{counter}};
+
+{%for service in package.services %}
+service {{service}} {
+ {% for attribute in service.attributes %}
+ {%+ if attribute.is_readonly %}readonly {% endif %}
+ {%if attribute.type.is_list or attribute.type.is_model -%}
+ {{attribute.type}}<{{attribute.type.nested}}> {{attribute}};
+ {% else %}{{attribute.type}} {{attribute}};
+ {% endif %}
+ {% endfor %}
+ {% for operation in service.operations %}
+ {{operation.type}} {{operation}}();
+ {% endfor %}
+}
+
+
+{% for enum in package.enums%}
+{% set comma = joiner(",") %}
+enum {{enum}} {
+ {%- for member in enum.members -%}
+ {{ comma() }}
+ {{member.name}} = {{member.value}}
+ {%- endfor %}
+}
+{%- endfor %}
+
+
+{% for struct in package.structs %}
+struct {{struct}} {
+ {% for member in struct.members %}
+ {{member.type}} {{member}};
+ {% endfor %}
+}
+{% endfor %}
+
+
+{%endfor%}
+
diff --git a/generator/qtcpp/log.yaml b/generator/qtcpp/log.yaml
new file mode 100644
index 0000000..7846e96
--- /dev/null
+++ b/generator/qtcpp/log.yaml
@@ -0,0 +1,18 @@
+version: 1
+formatters:
+ simple:
+ format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+handlers:
+ console:
+ class: logging.StreamHandler
+ level: DEBUG
+ formatter: simple
+ stream: ext://sys.stdout
+loggers:
+ qface.generator:
+ level: DEBUG
+ handlers: [console]
+ propagate: no
+root:
+ level: DEBUG
+ handlers: [console]
diff --git a/generator/qtcpp/qtcpp.py b/generator/qtcpp/qtcpp.py
index cbe8796..f999313 100644
--- a/generator/qtcpp/qtcpp.py
+++ b/generator/qtcpp/qtcpp.py
@@ -1,9 +1,18 @@
#!/usr/bin/env python3
import click
+import logging
+import logging.config
+import yaml
from qface.generator import FileSystem, Generator
-system = FileSystem.parse_dir('./in')
+def setupLogging():
+ fp = open('log.yaml', 'r')
+ data = yaml.load(fp)
+ logging.config.dictConfig(data)
+setupLogging()
+
+logger = logging.getLogger(__name__)
def paramterType(symbol):
moduleName = symbol.package.nameParts[-1].capitalize()
@@ -48,6 +57,7 @@ def generate(input, output):
generator.register_filter('parameterType', paramterType)
ctx = {'output': output}
for package in system.packages:
+ logger.debug('process %s' % package)
moduleName = package.nameParts[-1].capitalize()
ctx.update({'package': package, 'module': moduleName})
packageOutput = generator.apply('{{output}}/{{package|lower}}', ctx)
diff --git a/input_csv.yml b/input_csv.yml
index 5b8eae2..e890047 100644
--- a/input_csv.yml
+++ b/input_csv.yml
@@ -1,3 +1,3 @@
-generator: csv
+generator: generator/csv
input: input
output: output
diff --git a/requirements.txt b/requirements.txt
index 224d0e1..d41297e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,5 +3,6 @@ jinja2
click
path.py
watchdog
+pyyaml
pytest
ipdb
diff --git a/templates/packages.csv b/templates/packages.csv
deleted file mode 100644
index d316387..0000000
--- a/templates/packages.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-{% for package in system.packages %}
- {%- for service in package.services -%}
- {{package}}.{{service}}, SERVICE
- {% endfor -%}
- {%- for struct in package.structs -%}
- {{package}}.{{struct}}, STRUCT
- {% endfor -%}
- {%- for enum in package.enums -%}
- {{package}}.{{enum}}, ENUM
- {% endfor -%}
-{% endfor %}
diff --git a/tuner_cpp.yml b/tuner_cpp.yml
index 5f902d8..82ebaad 100644
--- a/tuner_cpp.yml
+++ b/tuner_cpp.yml
@@ -1,3 +1,3 @@
-generator: qtcpp
+generator: generator/qtcpp
input: input
output: output