Initial commit

This commit is contained in:
Tom Willemse 2013-12-15 17:02:05 +01:00
commit ea8763fd0d
5 changed files with 148 additions and 0 deletions

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
pycommand==0.1.0

13
scripts/topple Executable file
View file

@ -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())

2
topple/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__/
*.pyc

1
topple/__init__.py Normal file
View file

@ -0,0 +1 @@

131
topple/topple.py Normal file
View file

@ -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()