Basic scaffolding
authorFabien Meghazi <fme@openerp.com>
Wed, 28 May 2014 09:31:00 +0000 (11:31 +0200)
committerFabien Meghazi <fme@openerp.com>
Wed, 28 May 2014 09:31:00 +0000 (11:31 +0200)
openerp/cli/__init__.py
openerp/cli/scaffold.py [new file with mode: 0644]
openerp/cli/scaffold/__init__.jinja2 [new file with mode: 0644]
openerp/cli/scaffold/__openerp__.jinja2 [new file with mode: 0644]
openerp/cli/scaffold/controllers.jinja2 [new file with mode: 0644]
openerp/cli/scaffold/ir.model.access.jinja2 [new file with mode: 0644]
openerp/cli/scaffold/models.jinja2 [new file with mode: 0644]

index 2f9caad..4414162 100644 (file)
@@ -36,6 +36,7 @@ class Help(Command):
 
 import server
 import deploy
+import scaffold
 
 def main():
     args = sys.argv[1:]
diff --git a/openerp/cli/scaffold.py b/openerp/cli/scaffold.py
new file mode 100644 (file)
index 0000000..4d9304c
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import argparse
+import functools
+import keyword
+import os
+import re
+import sys
+
+import jinja2
+
+from . import Command
+
+class Scaffold(Command):
+    "Generate an Odoo module skeleton."
+
+    def __init__(self):
+        super(Scaffold, self).__init__()
+        env = jinja2.Environment(loader=jinja2.PackageLoader(
+            'openerp.cli', 'scaffold'))
+        env.filters['snake'] = snake
+        self.env = env
+
+    def scaffold(self, args):
+        # TODO: make this function callable even if the module already
+        #       exists. (update mode for scaffolding)
+        from pudb import set_trace;set_trace() ############################## Breakpoint ##############################
+        args.dependency = 'base'
+        if args.web:
+            args.dependency = 'web'
+        elif args.theme:
+            args.dependency = 'website'
+        dest = os.path.abspath(os.path.expanduser(args.dest))
+
+        module_name = snake(args.module)
+        module = functools.partial(os.path.join, dest, module_name)
+
+        if os.path.exists(module()):
+            message = "The path `%s` already exists." % module()
+            die(message)
+
+        self.dump('__openerp__.jinja2', module('__openerp__.py'), config=args)
+        self.dump('__init__.jinja2', module('__init__.py'), modules=[
+            args.controller and 'controllers',
+            args.model and 'models'
+        ])
+        self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args)
+
+
+    def dump(self, template, dest, **kwargs):
+        outdir = os.path.dirname(dest)
+        if not os.path.exists(outdir):
+            os.makedirs(outdir)
+        self.env.get_template(template).stream(**kwargs).dump(dest)
+        # add trailing newline which jinja removes
+        with open(dest, 'a') as f:
+            f.write('\n')
+
+    def run(self, args):
+        parser = argparse.ArgumentParser(
+            prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1],
+            description=self.__doc__
+        )
+        parser.add_argument('module', help="Name of the module to generate")
+        parser.add_argument('dest', nargs='?', help='Directory where the module should be created (default to current directory)', default=".")
+
+
+        if not args:
+            sys.exit(parser.print_help())
+
+        args = parser.parse_args(args=args)
+
+        self.scaffold(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 identifier(s):
+    if keyword.iskeyword(s):
+        die("%s is a Python keyword and can not be used as a name" % s)
+    if not re.match('[A-Za-z_][A-Za-z0-9_]*', s):
+        die("%s is not a valid Python identifier" % s)
+    return s
+
+def directory(p):
+    expanded = os.path.abspath(
+        os.path.expanduser(
+            os.path.expandvars(p)))
+    if not os.path.exists(expanded):
+        os.makedirs(expanded)
+    if not os.path.isdir(expanded):
+        die("%s exists but is not a directory" % p)
+    return expanded
+
+def die(message, code=1):
+    print >>sys.stderr, message
+    sys.exit(code)
diff --git a/openerp/cli/scaffold/__init__.jinja2 b/openerp/cli/scaffold/__init__.jinja2
new file mode 100644 (file)
index 0000000..0124cdd
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+{% for module in modules if module -%}
+import {{ module }}
+{% endfor %}
diff --git a/openerp/cli/scaffold/__openerp__.jinja2 b/openerp/cli/scaffold/__openerp__.jinja2
new file mode 100644 (file)
index 0000000..0dbd6f8
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "{{ config.module }}",
+    # short description, used as subtitles on modules listings
+    'summary': """
+        Short (1 phrase/line) summary of the module's purpose, used as
+        subtitle on modules listing or apps.openerp.com""",
+    # long description of module purpose
+    'description': """
+    """,
+    # Who you are
+    'author': "Acme Corp.",
+    'website': "http://www.example.com",
+
+    # categories can be used to filter modules in modules listing
+    'category': 'Uncategorized',
+    'version': '0.1',
+
+    # any module necessary for this one to work correctly
+    'depends': ['{{ config.dependency }}'],
+    'data': [
+        {{- "'security/ir.model.access.csv'" if config.model -}}
+    ],
+    'tests': [
+    ],
+}
diff --git a/openerp/cli/scaffold/controllers.jinja2 b/openerp/cli/scaffold/controllers.jinja2
new file mode 100644 (file)
index 0000000..3cc4736
--- /dev/null
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+from openerp import http
+from openerp.addons.web.controllers import main
+
+class {{ config.controller }}(main.Home):
+    @http.route('/', auth='none')
+    def index(self):
+        return "Hello, world!"
diff --git a/openerp/cli/scaffold/ir.model.access.jinja2 b/openerp/cli/scaffold/ir.model.access.jinja2
new file mode 100644 (file)
index 0000000..e5e2fb3
--- /dev/null
@@ -0,0 +1,6 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+{% if config.model -%}
+access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}}
+access_{{ config.module|snake }}_{{ config.model|snake }},{{- '' -}}
+model_{{ config.module|snake }}_{{ config.model|snake }},,1,0,0,0
+{%- endif %}
diff --git a/openerp/cli/scaffold/models.jinja2 b/openerp/cli/scaffold/models.jinja2
new file mode 100644 (file)
index 0000000..878bf9b
--- /dev/null
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+from openerp.osv import orm, fields
+
+class {{ config.model }}(orm.Model):
+    _name = "{{ config.module|snake }}.{{ config.model|snake }}"
+
+    _columns = {
+        'name': fields.char(),
+    }