2 # -*- coding: utf-8 -*-
14 class Scaffold(Command):
15 "Generate an Odoo module skeleton."
18 super(Scaffold, self).__init__()
19 env = jinja2.Environment(loader=jinja2.PackageLoader(
20 'openerp.cli', 'scaffold'))
21 env.filters['snake'] = snake
23 self.manifest = '__openerp__'
25 def scaffold(self, args):
26 args.dependency = 'base'
27 # TODO: update dependencies according to --web and --theme
29 # args.dependency = 'web'
31 # args.dependency = 'website'
33 dest = directory(args.dest)
35 module_name = snake(args.init)
36 module = functools.partial(os.path.join, dest, module_name)
37 if os.path.exists(module()):
38 die("Can't initialize module in `%s`: Directory already exists." % module())
40 module_name = dest.split(os.path.sep)[-1]
41 # find the module's root directory
42 while not os.path.exists(os.path.join(dest, '%s.py' % self.manifest)):
43 new_dest = os.path.abspath(os.path.join(dest, os.pardir))
45 die("Can't find module directory. Please `cd` to it's path or use --dest")
46 module_name = dest.split(os.path.sep)[-1]
48 module = functools.partial(os.path.join, dest)
49 args.module = module_name
52 self.dump('%s.jinja2' % self.manifest, module('%s.py' % self.manifest), config=args)
55 model_module = snake(args.model)
56 model_file = module('models', '%s.py' % model_module)
57 if os.path.exists(model_file):
58 die("Model `%s` already exists !" % model_file)
59 self.add_init_import(module('__init__.py'), 'models')
60 self.add_init_import(module('models', '__init__.py'), model_module)
61 self.dump('models.jinja2', model_file, config=args)
64 controller_module = snake(args.controller)
65 controller_file = module('controllers', '%s.py' % controller_module)
66 if os.path.exists(controller_file):
67 die("Controller `%s` already exists !" % controller_file)
68 self.add_init_import(module('__init__.py'), 'controllers')
69 self.add_init_import(module('controllers', '__init__.py'), controller_module)
70 self.dump('controllers.jinja2', module('controllers', controller_file), config=args)
72 # self.dump('ir.model.access.jinja2', module('security', 'ir.model.access.csv'), config=args)
75 def add_init_import(self, path, module):
76 if not os.path.exists(path):
77 self.dump('__init__.jinja2', path, modules=[module])
79 with open(path, "r") as f:
82 if ('import %s' % module) in lines:
84 with open(path, "a") as f:
85 f.write('\nimport %s' % module)
87 def dump(self, template, dest, **kwargs):
88 outdir = os.path.dirname(dest)
89 if not os.path.exists(outdir):
91 self.env.get_template(template).stream(**kwargs).dump(dest)
92 # add trailing newline which jinja removes
93 with open(dest, 'a') as f:
97 parser = argparse.ArgumentParser(
98 prog="%s scaffold" % sys.argv[0].split(os.path.sep)[-1],
99 description=self.__doc__
101 parser.add_argument('--init', type=identifier, help='Initialize a new Odoo module')
103 parser.add_argument('--dest', default=".",
104 help='Directory where the module should be created/updated (default to current directory)')
106 parser.add_argument('--model', type=identifier, help="Name of the model to add")
108 parser.add_argument('--controller', type=identifier, help="Name of the controller to add")
110 parser.add_argument('--web', action='store_true', default=False,
111 help="Generate structure for a webclient module")
113 parser.add_argument('--theme', action='store_true', default=False,
114 help="Generate structure for a Website theme")
117 sys.exit(parser.print_help())
118 args = parser.parse_args(args=args)
122 """ snake cases ``s``
127 # insert a space before each uppercase character preceded by a
128 # non-uppercase letter
129 s = re.sub(r'(?<=[^A-Z])\B([A-Z])', r' \1', s)
130 # lowercase everything, split on whitespace and join
131 return '_'.join(s.lower().split())
134 if keyword.iskeyword(s):
135 die("%s is a Python keyword and can not be used as a name" % s)
136 if not re.match('[A-Za-z_][A-Za-z0-9_]*', s):
137 die("%s is not a valid Python identifier" % s)
141 expanded = os.path.abspath(
143 os.path.expandvars(p)))
144 if not os.path.exists(expanded):
145 os.makedirs(expanded)
146 if not os.path.isdir(expanded):
147 die("%s exists but is not a directory" % p)
150 def die(message, code=1):
151 print >>sys.stderr, message