Refactor scaffolding engine so it can be used from outside
This commit is contained in:
parent
fcc854a4e1
commit
14f7d31a5f
|
@ -12,94 +12,11 @@ import jinja2
|
|||
|
||||
from . import Command
|
||||
|
||||
MANIFEST = '__openerp__'
|
||||
|
||||
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
|
||||
self.manifest = '__openerp__'
|
||||
|
||||
def scaffold(self, args):
|
||||
args.dependency = 'base'
|
||||
# TODO: update dependencies according to --web and --theme
|
||||
# if args.web:
|
||||
# args.dependency = 'web'
|
||||
# elif args.theme:
|
||||
# args.dependency = 'website'
|
||||
|
||||
dest = directory(args.dest)
|
||||
if args.init:
|
||||
args.module = snake(args.init)
|
||||
module = functools.partial(os.path.join, dest, args.module)
|
||||
if os.path.exists(module()):
|
||||
die("Can't initialize module in `%s`: Directory already exists." % module())
|
||||
if self.get_module_root(dest):
|
||||
die("Can't init a new module in another module, you probably want to run this "
|
||||
"command from your project's root")
|
||||
else:
|
||||
args.module, dest = self.get_module_root(dest)
|
||||
module = functools.partial(os.path.join, dest)
|
||||
|
||||
if args.init:
|
||||
self.dump('%s.jinja2' % self.manifest, module('%s.py' % self.manifest), config=args)
|
||||
|
||||
if args.model:
|
||||
model_module = snake(args.model)
|
||||
model_file = module('models', '%s.py' % model_module)
|
||||
if os.path.exists(model_file):
|
||||
die("Model `%s` already exists !" % model_file)
|
||||
self.add_init_import(module('__init__.py'), 'models')
|
||||
self.add_init_import(module('models', '__init__.py'), model_module)
|
||||
self.dump('models.jinja2', model_file, config=args)
|
||||
self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args)
|
||||
|
||||
if args.controller:
|
||||
controller_module = snake(args.controller)
|
||||
controller_file = module('controllers', '%s.py' % controller_module)
|
||||
if os.path.exists(controller_file):
|
||||
die("Controller `%s` already exists !" % controller_file)
|
||||
self.add_init_import(module('__init__.py'), 'controllers')
|
||||
# Check if the controller name correspond to a model and expose result to templates
|
||||
args.has_model = self.has_import(module('models', '__init__.py'), controller_module)
|
||||
self.add_init_import(module('controllers', '__init__.py'), controller_module)
|
||||
self.dump('controllers.jinja2', module('controllers', controller_file), config=args)
|
||||
|
||||
def get_module_root(self, path):
|
||||
module_name = path.split(os.path.sep)[-1]
|
||||
# find the module's root directory
|
||||
while not os.path.exists(os.path.join(path, '%s.py' % self.manifest)):
|
||||
new_path = os.path.abspath(os.path.join(path, os.pardir))
|
||||
if path == new_path:
|
||||
return None
|
||||
module_name = path.split(os.path.sep)[-1]
|
||||
path = new_path
|
||||
return (module_name, path)
|
||||
|
||||
def has_import(self, initfile, module):
|
||||
with open(initfile, 'r') as f:
|
||||
for imp in ast.parse(f.read()).body:
|
||||
if isinstance(imp, ast.Import):
|
||||
if module in [mod.name for mod in imp.names]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_init_import(self, initfile, module):
|
||||
if not(os.path.exists(initfile) and self.has_import(initfile, module)):
|
||||
self.dump('__init__.jinja2', initfile, modules=[module])
|
||||
|
||||
def dump(self, template, dest, **kwargs):
|
||||
outdir = os.path.dirname(dest)
|
||||
kwargs['create'] = not os.path.exists(dest)
|
||||
if not os.path.exists(outdir):
|
||||
os.makedirs(outdir)
|
||||
content = self.env.get_template(template).render(**kwargs)
|
||||
with open(dest, 'a') as f:
|
||||
f.write(content)
|
||||
|
||||
def run(self, args):
|
||||
# TODO: bash completion file
|
||||
parser = argparse.ArgumentParser(
|
||||
|
@ -124,7 +41,99 @@ class Scaffold(Command):
|
|||
if not args:
|
||||
sys.exit(parser.print_help())
|
||||
args = parser.parse_args(args=args)
|
||||
self.scaffold(args)
|
||||
|
||||
dest = directory(args.dest)
|
||||
if args.init:
|
||||
dest = os.path.join(dest, args.init)
|
||||
if os.path.exists(dest):
|
||||
die("Can't initialize module in `%s`: Directory already exists." % dest)
|
||||
if get_module_root(dest):
|
||||
die("Can't init a new module in another Odoo module, you probably want to run this "
|
||||
"command from your project's root")
|
||||
else:
|
||||
mroot = get_module_root(dest)
|
||||
if not mroot:
|
||||
die("The path `%s` provided does not point to an existing Odoo module. "
|
||||
"Forgot to `--init` ?" % dest)
|
||||
dest = mroot
|
||||
|
||||
scaffold = ScaffoldModule(dest)
|
||||
if args.model:
|
||||
scaffold.add_model(args.model)
|
||||
if args.controller:
|
||||
scaffold.add_controller(args.controller)
|
||||
|
||||
class ScaffoldModule(object):
|
||||
"""
|
||||
Object for scaffolding existing or new Odoo modules
|
||||
|
||||
@param path: Path of an existing module or path of module to create
|
||||
"""
|
||||
def __init__(self, path):
|
||||
env = jinja2.Environment(loader=jinja2.PackageLoader(
|
||||
'openerp.cli', 'scaffold'))
|
||||
env.filters['snake'] = snake
|
||||
self.env = env
|
||||
self.path = functools.partial(os.path.join, directory(path))
|
||||
self.created = not os.path.exists(self.path())
|
||||
directory(path, create=True)
|
||||
if self.created:
|
||||
self.module_name = self.path().split(os.path.sep)[-1]
|
||||
self.dump('%s.jinja2' % MANIFEST, self.path('%s.py' % MANIFEST))
|
||||
else:
|
||||
# TODO: get this information from manifest
|
||||
self.module_name = self.path().split(os.path.sep)[-1]
|
||||
|
||||
def add_model(self, model):
|
||||
model_module = snake(model)
|
||||
model_file = self.path('models', '%s.py' % model_module)
|
||||
if os.path.exists(model_file):
|
||||
die("Model `%s` already exists !" % model_file)
|
||||
self.add_init_import(self.path('__init__.py'), 'models')
|
||||
self.add_init_import(self.path('models', '__init__.py'), model_module)
|
||||
self.dump('models.jinja2', model_file, model=model)
|
||||
self.dump('ir.model.access.jinja2', self.path('security', 'ir.model.access.csv'), model=model)
|
||||
|
||||
def add_controller(self, controller):
|
||||
controller_module = snake(controller)
|
||||
controller_file = self.path('controllers', '%s.py' % controller_module)
|
||||
if os.path.exists(controller_file):
|
||||
die("Controller `%s` already exists !" % controller_file)
|
||||
self.add_init_import(self.path('__init__.py'), 'controllers')
|
||||
# Check if the controller name correspond to a model and expose result to templates
|
||||
has_model = self.has_import(self.path('models', '__init__.py'), controller_module)
|
||||
self.add_init_import(self.path('controllers', '__init__.py'), controller_module)
|
||||
self.dump('controllers.jinja2', self.path('controllers', controller_file),
|
||||
controller=controller, has_model=has_model)
|
||||
|
||||
def has_import(self, initfile, module):
|
||||
with open(initfile, 'r') as f:
|
||||
for imp in ast.parse(f.read()).body:
|
||||
if isinstance(imp, ast.Import):
|
||||
if module in [mod.name for mod in imp.names]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def ensure_dependency_to(self, module):
|
||||
# TODO: update dependencies according to --web and --theme
|
||||
# if args.web:
|
||||
# args.dependency = 'web'
|
||||
# elif args.theme:
|
||||
# args.dependency = 'website'
|
||||
pass
|
||||
|
||||
def add_init_import(self, initfile, module):
|
||||
if not(os.path.exists(initfile) and self.has_import(initfile, module)):
|
||||
self.dump('__init__.jinja2', initfile, modules=[module])
|
||||
|
||||
def dump(self, template, dest, **kwargs):
|
||||
outdir = os.path.dirname(dest)
|
||||
kwargs['file_created'] = not os.path.exists(dest)
|
||||
if not os.path.exists(outdir):
|
||||
os.makedirs(outdir)
|
||||
content = self.env.get_template(template).render(module_name=self.module_name, **kwargs)
|
||||
with open(dest, 'a') as f:
|
||||
f.write(content)
|
||||
|
||||
def snake(s):
|
||||
""" snake cases ``s``
|
||||
|
@ -145,16 +154,33 @@ def identifier(s):
|
|||
die("%s is not a valid Python identifier" % s)
|
||||
return s
|
||||
|
||||
def directory(p):
|
||||
def directory(p, create=False):
|
||||
expanded = os.path.abspath(
|
||||
os.path.expanduser(
|
||||
os.path.expandvars(p)))
|
||||
if not os.path.exists(expanded):
|
||||
if create and not os.path.exists(expanded):
|
||||
os.makedirs(expanded)
|
||||
if not os.path.isdir(expanded):
|
||||
if create and not os.path.isdir(expanded):
|
||||
die("%s exists but is not a directory" % p)
|
||||
return expanded
|
||||
|
||||
def get_module_root(path):
|
||||
"""
|
||||
Get closest module's root begining from path
|
||||
|
||||
@param path: Path from which the lookup should start
|
||||
|
||||
@return: Module root path
|
||||
"""
|
||||
# find the module's root directory
|
||||
while not os.path.exists(os.path.join(path, '%s.py' % MANIFEST)):
|
||||
new_path = os.path.abspath(os.path.join(path, os.pardir))
|
||||
if path == new_path:
|
||||
return None
|
||||
path = new_path
|
||||
return path
|
||||
|
||||
|
||||
def die(message, code=1):
|
||||
print >>sys.stderr, message
|
||||
sys.exit(code)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{% if create -%}# -*- coding: utf-8 -*-{%- endif %}
|
||||
{% if file_created -%}# -*- coding: utf-8 -*-{%- endif %}
|
||||
{% for module in modules if module -%}import {{ module }}
|
||||
{%- endfor %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "{{ config.module }}",
|
||||
'name': "{{ module_name }}",
|
||||
|
||||
'summary': """
|
||||
Short (1 phrase/line) summary of the module's purpose, used as
|
||||
|
@ -21,7 +21,6 @@
|
|||
# any module necessary for this one to work correctly
|
||||
'depends': ['base'],
|
||||
'data': [
|
||||
# {{- "'security/ir.model.access.csv'" if config.model -}}
|
||||
],
|
||||
|
||||
'demo': [
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
from openerp import http
|
||||
from openerp.addons.web.controllers import main
|
||||
|
||||
class {{ config.controller }}(main.Home):
|
||||
@http.route('/{{ config.module }}/{{ config.controller }}', auth='public')
|
||||
class {{ controller }}(main.Home):
|
||||
@http.route('/{{ module_name }}/{{ controller }}', auth='public')
|
||||
def index(self):
|
||||
return "Hello, world!"
|
||||
{% if config.has_model %}
|
||||
@http.route('/{{ config.module }}/{{ config.controller }}/<model("{{ config.module }}.{{ config.controller }}"):{{ config.controller }}>'], type='http', auth='public')
|
||||
def {{ config.controller }}(self, {{ config.controller }}, **kw):
|
||||
return "Hello, %r!" % {{ config.controller }}
|
||||
{% if has_model %}
|
||||
@http.route('/{{ module_name }}/{{ controller }}/<model("{{ module_name }}.{{ controller }}"):{{ controller }}>'], type='http', auth='public')
|
||||
def {{ controller }}(self, {{ controller }}, **kw):
|
||||
return "Hello, %r!" % {{ controller }}
|
||||
{% endif %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% if create -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %}
|
||||
{% 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
|
||||
{% if file_created -%}id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink{%- endif %}
|
||||
{% if model -%}
|
||||
access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}}
|
||||
access_{{ module_name|snake }}_{{ model|snake }},{{- '' -}}
|
||||
model_{{ module_name|snake }}_{{ model|snake }},,1,0,0,0
|
||||
{%- endif %}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
class {{ config.model }}(orm.Model):
|
||||
_name = "{{ config.module|snake }}.{{ config.model|snake }}"
|
||||
class {{ model }}(orm.Model):
|
||||
_name = "{{ module_name|snake }}.{{ model|snake }}"
|
||||
|
||||
_columns = {
|
||||
'name': fields.char(),
|
||||
|
|
Loading…
Reference in New Issue