summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuergen Bocklage-Ryannel <juergen@ryannel.org>2018-12-24 13:28:16 +0100
committerJuergen Bocklage-Ryannel <juergen@ryannel.org>2018-12-24 13:28:16 +0100
commitf354532d7cc9e3663b005f5413baf03833c60398 (patch)
treee2bcb28bb3d8f3d3efc86bb1c064380cd5579e60
parent22840dd0a67644afd20c1b9c4dfffa2c23cb4c6d (diff)
downloadqtivi-qface-f354532d7cc9e3663b005f5413baf03833c60398.tar.gz
- introduce qface script mode
- add ability to load dynamic filters for qface script mode - extract generic filters - fixed some issues with cpp macros
-rw-r--r--docs/index.rst1
-rw-r--r--docs/script.rst40
-rw-r--r--qface/__about__.py4
-rw-r--r--qface/app.py42
-rw-r--r--qface/filters.py68
-rw-r--r--qface/generator.py7
-rw-r--r--qface/helper/generic.py52
-rw-r--r--qface/helper/qtcpp.py6
-rw-r--r--qface/templates/qface/qtcpp.j212
-rw-r--r--qface/utils.py13
10 files changed, 173 insertions, 72 deletions
diff --git a/docs/index.rst b/docs/index.rst
index 0212095..12a05b7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,6 +18,7 @@ Several code generators for common use cases have already been implemented. Thes
json
domain
extending
+ script
api
diff --git a/docs/script.rst b/docs/script.rst
new file mode 100644
index 0000000..fb3def2
--- /dev/null
+++ b/docs/script.rst
@@ -0,0 +1,40 @@
+***********
+Script Mode
+***********
+
+In the script mode, qface is used as the qface exectuable. In this mode the code generator consits of a rule document and template files and optionally a filter module.
+
+Whereas normally the generator writer create an own python package in this module only some documents are needed and the qface script is used.
+
+Setup
+=====
+
+To get started create a `qface-rules.yml` document and a templates folder::
+
+ qface-rules.yml
+ templates/
+
+
+In the rules file you provide the code generation rules accoring to the rule generator documentation. The templates folder will contain the required templates.
+
+Filters
+=======
+
+To provide extra filder you need to create a `filters.py` document with the declaration of your filters::
+
+ def echo(s):
+ print(s)
+ return "World"
+
+ filters['echo'] = echo
+
+The filters module will be loaded by qface and all entries to the filters dictionary are added to the global lists of Jinja filters.
+
+Running
+=======
+
+To run now the generator you can simply call::
+
+ qface --rules qface-rules.yml --target out counter.qface
+
+This will take your rules and generate the files inside the out folder based on the `counter.qface` interface file.
diff --git a/qface/__about__.py b/qface/__about__.py
index e63ff15..0ed253d 100644
--- a/qface/__about__.py
+++ b/qface/__about__.py
@@ -9,7 +9,7 @@ except NameError:
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
__url__ = "https://pelagicore.github.io/qface/"
-__version__ = "1.9.1"
+__version__ = "2.0.0"
__author__ = "JRyannel"
-__author_email__ = "qface-generator@googlegroups.com"
+__author_email__ = ""
__copyright__ = "2019 Pelagicore"
diff --git a/qface/app.py b/qface/app.py
index 800744a..38a26d6 100644
--- a/qface/app.py
+++ b/qface/app.py
@@ -7,39 +7,61 @@ import logging
from path import Path
from qface.generator import FileSystem, RuleGenerator
from qface.watch import monitor
+from qface.utils import load_filters
here = Path(__file__).dirname()
logging.basicConfig()
-def run(spec, src, dst):
+def run(spec, src, dst, features, force):
spec = Path(spec)
project = Path(dst).name
system = FileSystem.parse(src)
- context = {
+ extra_filters_path = spec.dirname() / 'filters.py'
+ extra_filters = load_filters(extra_filters_path)
+
+ ctx = {
'dst': dst,
'system': system,
'project': project,
}
- generator = RuleGenerator(search_path=spec.dirname() / 'templates', destination=dst, context=context)
+ generator = RuleGenerator(
+ search_path=spec.dirname() / 'templates',
+ destination=dst,
+ context=ctx,
+ features=features,
+ force=force
+ )
+ generator.filters = extra_filters
generator.process_rules(spec, system)
@click.command()
-@click.option('--spec', type=click.Path(exists=True, file_okay=True))
-@click.option('--dst', type=click.Path(exists=False, file_okay=False))
+@click.option('--rules', type=click.Path(exists=True, file_okay=True))
+@click.option('--target', type=click.Path(exists=False, file_okay=False))
@click.option('--reload/--no-reload', default=False, help="Auto reload script on changes")
-@click.argument('src', nargs=-1, type=click.Path(exists=True))
-def main(spec, dst, reload, src):
- spec = Path(spec)
+@click.option('--scaffold/--no-scaffold', default=False, help="Add extrac scaffolding code")
+@click.option('--watch', type=click.Path(exists=False, file_okay=False))
+@click.option('--feature', multiple=True)
+@click.option('--force/--no-force', default=False, help="forces overwriting of files")
+@click.argument('source', nargs=-1, type=click.Path(exists=True))
+def main(rules, target, reload, source, watch, scaffold, feature, force):
+ rules = Path(rules)
if reload:
argv = sys.argv.copy()
argv.remove('--reload')
- monitor(args=argv, watch=src + (spec.dirname(),))
+ watch_list = list(source)
+ watch_list.append(rules.dirname())
+ if watch:
+ watch_list.append(watch)
+ monitor(args=argv, watch=watch_list)
else:
- run(spec, src, dst)
+ features = set(feature)
+ if scaffold:
+ features.add('scaffold')
+ run(rules, source, target, features=features, force=force)
if __name__ == '__main__':
diff --git a/qface/filters.py b/qface/filters.py
index 5969a64..236c7b3 100644
--- a/qface/filters.py
+++ b/qface/filters.py
@@ -1,58 +1,28 @@
-import json
-import hashlib
+from .helper import generic
from .helper import qtqml
from .helper import qtcpp
from .helper import doc
+import importlib.util
-def jsonify(symbol):
- """ returns json format for symbol """
- try:
- # all symbols have a toJson method, try it
- return json.dumps(symbol.toJson(), indent=' ')
- except AttributeError:
- pass
- return json.dumps(symbol, indent=' ')
+def get_filters():
+ filters = {}
+ filters.update(generic.get_filters())
+ filters.update(qtqml.Filters.get_filters())
+ filters.update(qtcpp.Filters.get_filters())
+ filters.update(doc.get_filters())
+ return filters
-def upper_first(s):
- """ uppercase first letter """
- s = str(s)
- return s[0].upper() + s[1:]
+def load_filters(path):
+ if not path.exists():
+ print('filter module does not exist')
+ return {}
+ extra_filters = {}
+ spec = importlib.util.spec_from_file_location('filters', path.abspath())
+ filters_module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(filters_module)
+ filters_module.get_filters(extra_filters)
+ return extra_filters
-def lower_first(s):
- s = str(s)
- return s[0].lower() + s[1:]
-
-
-def hash(symbol, hash_type='sha1'):
- """ create a hash code from symbol """
- code = hashlib.new(hash_type)
- code.update(str(symbol).encode('utf-8'))
- return code.hexdigest()
-
-
-def path(symbol):
- """ replaces '.' with '/' """
- return str(symbol).replace('.', '/')
-
-
-def identifier(s):
- return str(s).lower().replace('.', '_')
-
-
-filters = {
- 'jsonify': jsonify,
- 'upper_first': upper_first,
- 'lower_first': lower_first,
- 'upperfirst': upper_first,
- 'lowerfirst': lower_first,
- 'hash': hash,
- 'path': path,
- 'identifier': identifier,
-}
-
-filters.update(qtqml.Filters.get_filters())
-filters.update(qtcpp.Filters.get_filters())
-filters.update(doc.get_filters())
diff --git a/qface/generator.py b/qface/generator.py
index eb3172d..b4f93df 100644
--- a/qface/generator.py
+++ b/qface/generator.py
@@ -21,7 +21,7 @@ from .idl.parser.TListener import TListener
from .idl.profile import EProfile
from .idl.domain import System
from .idl.listener import DomainListener
-from .filters import filters
+from .filters import get_filters
from jinja2.debug import make_traceback as _make_traceback
@@ -94,7 +94,7 @@ class Generator(object):
lstrip_blocks=True,
)
self.env.exception_handler = template_error_handler
- self.env.filters.update(filters)
+ self.env.filters.update(get_filters())
self._destination = Path()
self._path = Path()
self._source = ''
@@ -170,6 +170,9 @@ class Generator(object):
"""Using a template file name it renders a template
into a file given a context
"""
+ if not file_path or not template:
+ click.secho('source or target missing for document')
+ return
if not context:
context = self.context
error = False
diff --git a/qface/helper/generic.py b/qface/helper/generic.py
new file mode 100644
index 0000000..713952d
--- /dev/null
+++ b/qface/helper/generic.py
@@ -0,0 +1,52 @@
+import json
+import hashlib
+
+
+def jsonify(symbol):
+ """ returns json format for symbol """
+ try:
+ # all symbols have a toJson method, try it
+ return json.dumps(symbol.toJson(), indent=' ')
+ except AttributeError:
+ pass
+ return json.dumps(symbol, indent=' ')
+
+
+def upper_first(s):
+ """ uppercase first letter """
+ s = str(s)
+ return s[0].upper() + s[1:]
+
+
+def lower_first(s):
+ s = str(s)
+ return s[0].lower() + s[1:]
+
+
+def hash(symbol, hash_type='sha1'):
+ """ create a hash code from symbol """
+ code = hashlib.new(hash_type)
+ code.update(str(symbol).encode('utf-8'))
+ return code.hexdigest()
+
+
+def path(symbol):
+ """ replaces '.' with '/' """
+ return str(symbol).replace('.', '/')
+
+
+def identifier(s):
+ return str(s).lower().replace('.', '_')
+
+
+def get_filters():
+ return {
+ 'jsonify': jsonify,
+ 'upper_first': upper_first,
+ 'lower_first': lower_first,
+ 'upperfirst': upper_first,
+ 'lowerfirst': lower_first,
+ 'hash': hash,
+ 'path': path,
+ 'identifier': identifier,
+ }
diff --git a/qface/helper/qtcpp.py b/qface/helper/qtcpp.py
index aeae6f0..c9e6835 100644
--- a/qface/helper/qtcpp.py
+++ b/qface/helper/qtcpp.py
@@ -36,7 +36,7 @@ class Filters(object):
return 'QVariant()'
elif t.is_void:
return ''
- elif t.is_enum:
+ elif t.is_enumeration:
value = next(iter(t.reference.members))
return '{0}::{0}Enum::{1}'.format(symbol.type, value)
elif symbol.kind == 'enum':
@@ -58,7 +58,7 @@ class Filters(object):
@staticmethod
def parameterType(symbol):
prefix = Filters.classPrefix
- if symbol.type.is_enum:
+ if symbol.type.is_enumeration:
return '{0}::{0}Enum {1}'.format(symbol.type, symbol)
if symbol.type.is_void or symbol.type.is_primitive:
if symbol.type.is_string:
@@ -88,7 +88,7 @@ class Filters(object):
def returnType(symbol):
prefix = Filters.classPrefix
t = symbol.type
- if t.is_enum:
+ if t.is_enumeration:
return '{0}::{0}Enum'.format(symbol.type)
if symbol.type.is_void or symbol.type.is_primitive:
if t.is_string:
diff --git a/qface/templates/qface/qtcpp.j2 b/qface/templates/qface/qtcpp.j2
index 729bfc9..b2e3bff 100644
--- a/qface/templates/qface/qtcpp.j2
+++ b/qface/templates/qface/qtcpp.j2
@@ -14,15 +14,15 @@
{%- endmacro %}
{% macro property_decl(property, notifiable=True) -%}
-Q_PROPERTY({{property|qt.returnType}} {{property}} READ {{property}} {% if not property.readonly %}WRITE set{{property|upperfirst}}{% endif %}{% if not property.const and notifiable %} NOTIFY {{property}}Changed{% endif %})
+Q_PROPERTY({{property|qt.returnType}} {{property}} READ {{property}} {% if not property.readonly %}WRITE push{{property|upperfirst}}{% endif %}{% if not property.const and notifiable %} NOTIFY {{property}}Changed{% endif %})
{%- endmacro %}
-{% macro property_setter_decl(property, ending=";") -%}
-void set{{property|upperfirst}}({{ property|qt.parameterType }}){{ending}}
+{% macro property_setter_decl(property, ending=";", prefix='virtual') -%}
+{{prefix}} void push{{property|upperfirst}}({{ property|qt.parameterType }}){{ending}}
{%- endmacro %}
-{% macro property_getter_decl(property, ending=";") -%}
-{{property|qt.returnType}} {{property}}() const{{ending}}
+{% macro property_getter_decl(property, ending=";", prefix='virtual') -%}
+{{prefix}} {{property|qt.returnType}} {{property}}() const{{ending}}
{%- endmacro %}
{% macro signal_decl(symbol, postfix="") -%}
@@ -41,7 +41,7 @@ void {{symbol}}{{postfix}}();
{{doc.description|join("\n ")}}
{% endwith %}
*/
-void {{class}}::set{{property|upperfirst}}({{ property|qt.parameterType }})
+void {{class}}::push{{property|upperfirst}}({{ property|qt.parameterType }})
{
{% if notifiable %}
if (m_{{property}} != {{property}}) {
diff --git a/qface/utils.py b/qface/utils.py
index f816b58..889d862 100644
--- a/qface/utils.py
+++ b/qface/utils.py
@@ -9,3 +9,16 @@ def module_info(text):
'title': module.name,
'brief': " ".join(doc.parse_doc(module.comment).brief)
}
+
+
+def load_filters(path):
+ if not path.exists():
+ print('filter module does not exist')
+ return {}
+
+ ctx = {
+ 'filters': {}
+ }
+ exec(path.text(), ctx)
+ return ctx['filters']
+