Initial commit
This commit is contained in:
commit
ea8763fd0d
5 changed files with 148 additions and 0 deletions
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pycommand==0.1.0
|
13
scripts/topple
Executable file
13
scripts/topple
Executable 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
2
topple/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
1
topple/__init__.py
Normal file
1
topple/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
131
topple/topple.py
Normal file
131
topple/topple.py
Normal 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()
|
Loading…
Reference in a new issue