aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2013-12-15 17:02:05 +0100
committerGravatar Tom Willemse2013-12-15 17:02:50 +0100
commitea8763fd0d0910afad37eb77a965ffbd0a2cf3b7 (patch)
treee3bdc0f43a81b72bb98f52f08036de1ba9475d89
downloadtopple-ea8763fd0d0910afad37eb77a965ffbd0a2cf3b7.tar.gz
topple-ea8763fd0d0910afad37eb77a965ffbd0a2cf3b7.zip
Initial commit
-rw-r--r--requirements.txt1
-rwxr-xr-xscripts/topple13
-rw-r--r--topple/.gitignore2
-rw-r--r--topple/__init__.py1
-rw-r--r--topple/topple.py131
5 files changed, 148 insertions, 0 deletions
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', '<modulename>',
+ '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()