diff --git a/applications/generate/README.md b/applications/generate/README.md index 605ec7be..528f4739 100644 --- a/applications/generate/README.md +++ b/applications/generate/README.md @@ -10,14 +10,16 @@ Philadelphia Code Generator requires Python 3.5 or newer. Philadelphia Code Generator supports the following input sources: - [FIX Repository][] +- [QuickFIX][] [FIX Repository]: https://www.fixtrading.org/standards/fix-repository/ + [QuickFIX]: http://www.quickfixengine.org/ ## Development Run Philadelphia Code Generator with Python: ``` -python -m philadelphia.generate +python -m philadelphia.generate [] ``` ## Installation @@ -29,7 +31,7 @@ python setup.py install Run Philadelphia Code Generator: ``` -philadelphia-generate +philadelphia-generate [] ``` ## License diff --git a/applications/generate/etc/example.ini b/applications/generate/etc/example.ini new file mode 100644 index 00000000..7758081b --- /dev/null +++ b/applications/generate/etc/example.ini @@ -0,0 +1,4 @@ +[dialect] +name=Example +class-name-prefix=Example +package-name=com.example.fix diff --git a/applications/generate/philadelphia/generate.py b/applications/generate/philadelphia/generate.py index d13f7972..17faf554 100644 --- a/applications/generate/philadelphia/generate.py +++ b/applications/generate/philadelphia/generate.py @@ -1,11 +1,13 @@ +import os.path import sys from . import model +from . import quickfix from . import repository USAGE = '''\ -Usage: philadelphia-generate +Usage: philadelphia-generate [] Commands: enumerations Generate enumerations @@ -14,24 +16,39 @@ ''' -def enumerations(path): - dialect = repository.read_dialect(path) - fields = repository.read_fields(path) +def enumerations(config, path): + module = read_module(path) + dialect = read_dialect(config, module, path) + fields = module.read_fields(path) print(model.format_enumerations(fields, dialect)) -def msg_types(path): - dialect = repository.read_dialect(path) - messages = repository.read_messages(path) +def msg_types(config, path): + module = read_module(path) + dialect = read_dialect(config, module, path) + messages = module.read_messages(path) print(model.format_msg_types(messages, dialect)) -def tags(path): - dialect = repository.read_dialect(path) - fields = repository.read_fields(path) +def tags(config, path): + module = read_module(path) + dialect = read_dialect(config, module, path) + fields = module.read_fields(path) print(model.format_tags(fields, dialect)) +def read_dialect(config, module, path): + if config: + return model.read_dialect(config) + if hasattr(module, 'read_dialect'): + return module.read_dialect(path) + sys.exit('error: Missing configuration file') + + +def read_module(path): + return repository if os.path.isdir(path) else quickfix + + COMMANDS = { 'enumerations': enumerations, 'msg-types': msg_types, @@ -40,14 +57,21 @@ def tags(path): def main(): - if len(sys.argv) != 3: + if len(sys.argv) != 3 and len(sys.argv) != 4: sys.exit(USAGE) command = COMMANDS.get(sys.argv[1]) if not command: sys.exit('error: {}: Unknown command'.format(sys.argv[1])) - command(sys.argv[2]) + if len(sys.argv) == 4: + config = sys.argv[2] + path = sys.argv[3] + else: + config = None + path = sys.argv[2] + + command(config, path) if __name__ == '__main__': diff --git a/applications/generate/philadelphia/model.py b/applications/generate/philadelphia/model.py index 6fba6c71..d67f01ce 100644 --- a/applications/generate/philadelphia/model.py +++ b/applications/generate/philadelphia/model.py @@ -1,4 +1,5 @@ import collections +import configparser from . import java @@ -15,6 +16,15 @@ Message = collections.namedtuple('Message', ['name', 'msg_type']) +def read_dialect(filename): + config = configparser.ConfigParser() + config.read(filename) + package_name = config['dialect']['package-name'] + class_name_prefix = config['dialect']['class-name-prefix'] + name = config['dialect']['name'] + return Dialect(package_name, class_name_prefix, name) + + def format_enumerations(fields, dialect): name = '{}Enumerations'.format(dialect.class_name_prefix) javadoc = 'Enumerations for {}.'.format(dialect.name) diff --git a/applications/generate/philadelphia/quickfix.py b/applications/generate/philadelphia/quickfix.py new file mode 100644 index 00000000..33a0671d --- /dev/null +++ b/applications/generate/philadelphia/quickfix.py @@ -0,0 +1,46 @@ +import xml.etree.ElementTree + +from . import model + + +def read_messages(filename): + def message(elem): + name = elem.get('name') + msgtype = elem.get('msgtype') + return model.Message(name=name, msg_type=msgtype) + root = xml.etree.ElementTree.parse(filename).find('messages') + return [message(elem) for elem in root.findall('message')] + + +def read_fields(filename): + def value(elem): + enum = elem.get('enum') + description = elem.get('description') + return model.Value(name=description, value=enum) + def field(root): + number = root.get('number') + name = root.get('name') + type_ = _type(root) + if name == 'MsgType' or not type_: + values = [] + else: + values = [value(elem) for elem in root.findall('value')] + return model.Field(tag=number, name=name, type_=type_, values=values) + root = xml.etree.ElementTree.parse(filename).find('fields') + return sorted([field(elem) for elem in root.findall('field')], + key=lambda field: int(field.tag)) + + +_TYPES = { + 'CHAR': 'char', + 'INT': 'int', + 'MULTIPLECHARVALUE': 'char', + 'MULTIPLESTRINGVALUE': 'String', + 'NUMINGROUP': 'int', + 'STRING': 'String', +} + + +def _type(elem): + type_ = elem.get('type') + return _TYPES.get(type_) diff --git a/scripts/archive.txt b/scripts/archive.txt index ac2030da..0f197905 100644 --- a/scripts/archive.txt +++ b/scripts/archive.txt @@ -5,10 +5,12 @@ applications/client/README.md applications/client/etc/example.conf applications/client/philadelphia-client.jar applications/generate/README.md +applications/generate/etc/example.ini applications/generate/philadelphia/__init__.py applications/generate/philadelphia/generate.py applications/generate/philadelphia/java.py applications/generate/philadelphia/model.py +applications/generate/philadelphia/quickfix.py applications/generate/philadelphia/repository.py applications/generate/setup.py examples/acceptor/README.md