From ea8763fd0d0910afad37eb77a965ffbd0a2cf3b7 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sun, 15 Dec 2013 17:02:05 +0100 Subject: Initial commit --- requirements.txt | 1 + scripts/topple | 13 ++++++ topple/.gitignore | 2 + topple/__init__.py | 1 + topple/topple.py | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+) create mode 100644 requirements.txt create mode 100755 scripts/topple create mode 100644 topple/.gitignore create mode 100644 topple/__init__.py create mode 100644 topple/topple.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ae0ed47 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pycommand==0.1.0 diff --git a/scripts/topple b/scripts/topple new file mode 100755 index 0000000..f09e9ae --- /dev/null +++ b/scripts/topple @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import sys + +import topple.topple + +if __name__ == '__main__': + cmd = topple.topple.Topple(sys.argv[1:]) + if cmd.error: + print('error: {0}'.format(cmd.error)) + sys.exit(1) + else: + sys.exit(cmd.run()) diff --git a/topple/.gitignore b/topple/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/topple/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/topple/__init__.py b/topple/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/topple/__init__.py @@ -0,0 +1 @@ + diff --git a/topple/topple.py b/topple/topple.py new file mode 100644 index 0000000..5a52e45 --- /dev/null +++ b/topple/topple.py @@ -0,0 +1,131 @@ +from __future__ import print_function + +import _ast +import ast +import os +import os.path +import sys + +import pycommand + + +def get_setting_specs(module): + sys.path.insert(0, os.getcwd()) + return __import__(module) + + +def write_settings(specs, out, values=None): + values = values or {} + + print('# {file} file generated by topple' + .format(file=specs.OUTPUT_FILE), file=out) + + for key, spec in specs.SETTINGS: + value = values.get(key, spec['initial']) + + if (spec['predicate'](value)): + print(key, repr(value), sep=' = ', file=out) + else: + raise RuntimeError('Invalid type for %s: %s' % (key, repr(value))) + + +class PreviewMixin(object): + optionList = ( + ('preview', ('p', None, 'Print generated file to stdout')), + ) + + def __new__(cls, *args, **kwargs): + cls.optionList = (cls.optionList or tuple()) + PreviewMixin.optionList + instance = super(PreviewMixin, cls).__new__(cls, *args, **kwargs) + return instance + + def write(self, output, specs, values=None): + preview = self.flags['preview'] + + if not preview: + with open(output, 'w') as f: + write_settings(specs, f, values) + else: + write_settings(specs, sys.stdout, values) + + +class Generate(pycommand.CommandBase, PreviewMixin): + usagestr = 'usage: topple generate [--preview|-p]' + + def run(self): + sys.path.insert(0, os.getcwd()) + + specs = get_setting_specs(self.parentFlags['module'] or 'toppler') + self.write(specs.OUTPUT_FILE, specs) + + +class Update(pycommand.CommandBase, PreviewMixin): + usagestr = 'usage: topple update [--preview|-p]' + + def _get_value(self, node): + if isinstance(node, _ast.Name): + return eval(node.id) + elif isinstance(node, _ast.Str): + return node.s + elif isinstance(node, _ast.Num): + return node.n + else: + return node + + def _get_values(self, filename): + res = {} + + with open(filename, 'r') as f: + tree = ast.parse('\n'.join(f.readlines()), filename) + for node in ast.iter_child_nodes(tree): + if isinstance(node, _ast.Assign): + res[node.targets[0].id] = self._get_value(node.value) + else: + print(node, node._fields) + + return res + + def run(self): + sys.path.insert(0, os.getcwd()) + filename = 'settings_local.py' + res = self._get_values(filename) + specs = get_setting_specs(self.parentFlags['module'] or 'toppler') + self.write(specs.OUTPUT_FILE, specs, res) + + +class Topple(pycommand.CommandBase): + usagestr = 'usage: topple [--module=modulename|-m modulename] generate' + description = ( + 'Commands:\n' + ' generate Generate a new settings file.\n' + ' update Update an existing settings file.\n' + ) + optionList = (('module', ('m', '', + 'Use specified python module.')),) + + def run(self): + module = self.flags['module'] or 'toppler' + + if not os.path.exists(module + '.py'): + print('No {module}.py module found!'.format(module=module)) + return 1 + if not self.args: + print(self.usage) + return 2 + + if self.args[0] == 'generate': + cmd = Generate(argv=self.args[1:]) + elif self.args[0] == 'update': + cmd = Update(argv=self.args[1:]) + else: + print('Undefined command: {cmd}'.format(cmd=self.args[0])) + return 1 + + cmd.registerParentFlag('module', self.flags['module']) + + if cmd.error: + print('Error during {cmd}: {err}'.format(cmd=self.args[0], + err=cmd.error)) + return 1 + else: + return cmd.run() -- cgit v1.2.3-54-g00ecf