diff options
| author | Raphael Collet <rco@openerp.com> | 2016-09-02 15:58:39 +0200 |
|---|---|---|
| committer | Raphael Collet <rco@openerp.com> | 2016-09-02 17:28:12 +0200 |
| commit | 9e64f9f9514194d74e166b032add8511182f2677 (patch) | |
| tree | 5086710c04c6b923be18a6d1d97b3f0f3a2a9c4a /odoo/cli/scaffold.py | |
| parent | 11812b0b9e82b2b1b9041d8250ce01e7b4a5f7ee (diff) | |
[REF] openerp: move `openerp` to `odoo`
Diffstat (limited to 'odoo/cli/scaffold.py')
| -rw-r--r-- | odoo/cli/scaffold.py | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/odoo/cli/scaffold.py b/odoo/cli/scaffold.py new file mode 100644 index 00000000000..221f192347e --- /dev/null +++ b/odoo/cli/scaffold.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import argparse +import os +import re +import sys + +import jinja2 + +from . import Command + +from openerp.modules.module import (get_module_root, MANIFEST, load_information_from_description_file as load_manifest) + + +class Scaffold(Command): + """ Generates an Odoo module skeleton. """ + + def run(self, cmdargs): + # TODO: bash completion file + parser = argparse.ArgumentParser( + prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1], + description=self.__doc__, + epilog=self.epilog(), + ) + parser.add_argument( + '-t', '--template', type=template, default=template('default'), + help="Use a custom module template, can be a template name or the" + " path to a module template (default: %(default)s)") + parser.add_argument('name', help="Name of the module to create") + parser.add_argument( + 'dest', default='.', nargs='?', + help="Directory to create the module in (default: %(default)s)") + + if not cmdargs: + sys.exit(parser.print_help()) + args = parser.parse_args(args=cmdargs) + + args.template.render_to( + snake(args.name), + directory(args.dest, create=True), + {'name': args.name}) + + def epilog(self): + return "Built-in templates available are: %s" % ', '.join( + d for d in os.listdir(builtins()) + if d != 'base' + ) + +builtins = lambda *args: os.path.join( + os.path.abspath(os.path.dirname(__file__)), + 'templates', + *args) + +def snake(s): + """ snake cases ``s`` + + :param str s: + :return: str + """ + # insert a space before each uppercase character preceded by a + # non-uppercase letter + s = re.sub(r'(?<=[^A-Z])\B([A-Z])', r' \1', s) + # lowercase everything, split on whitespace and join + return '_'.join(s.lower().split()) +def pascal(s): + return ''.join( + ss.capitalize() + for ss in re.sub('[_\s]+', ' ', s).split() + ) + +def directory(p, create=False): + expanded = os.path.abspath( + os.path.expanduser( + os.path.expandvars(p))) + if create and not os.path.exists(expanded): + os.makedirs(expanded) + if not os.path.isdir(expanded): + die("%s is not a directory" % p) + return expanded + +env = jinja2.Environment() +env.filters['snake'] = snake +env.filters['pascal'] = pascal +class template(object): + def __init__(self, identifier): + # TODO: archives (zipfile, tarfile) + self.id = identifier + # is identifier a builtin? + self.path = builtins(identifier) + if os.path.isdir(self.path): + return + # is identifier a directory? + self.path = identifier + if os.path.isdir(self.path): + return + die("{} is not a valid module template".format(identifier)) + + def __str__(self): + return self.id + + def files(self): + """ Lists the (local) path and content of all files in the template + """ + for root, _, files in os.walk(self.path): + for f in files: + path = os.path.join(root, f) + yield path, open(path, 'rb').read() + + def render_to(self, modname, directory, params=None): + """ Render this module template to ``dest`` with the provided + rendering parameters + """ + # overwrite with local + for path, content in self.files(): + local = os.path.relpath(path, self.path) + # strip .template extension + root, ext = os.path.splitext(local) + if ext == '.template': + local = root + dest = os.path.join(directory, modname, local) + destdir = os.path.dirname(dest) + if not os.path.exists(destdir): + os.makedirs(destdir) + + with open(dest, 'wb') as f: + if ext not in ('.py', '.xml', '.csv', '.js', '.rst', '.html', '.template'): + f.write(content) + else: + env.from_string(content.decode('utf-8'))\ + .stream(params or {})\ + .dump(f, encoding='utf-8') + +def die(message, code=1): + print >>sys.stderr, message + sys.exit(code) + +def warn(message): + # ASK: shall we use logger ? + print "WARNING: " + message |
