[MERGE] forward port of branch 7.0 up to revid 5270 chs@openerp.com-20140403084524...
[odoo/odoo.git] / openerpcommand / initialize.py
1 """
2 Install OpenERP on a new (by default) database.
3 """
4 import contextlib
5 import errno
6 import os
7 import sys
8 import time
9
10 import common
11
12 def install_openerp(database_name, create_database_flag, module_names, install_demo_data):
13     import openerp
14     config = openerp.tools.config
15
16     if create_database_flag:
17         with lock_file('/tmp/global_openerp_create_database.lock'):
18             create_database(database_name)
19
20     config['init'] = dict.fromkeys(module_names, 1)
21
22     # Install the import hook, to import openerp.addons.<module>.
23     openerp.modules.module.initialize_sys_path()
24
25     registry = openerp.modules.registry.RegistryManager.get(
26         database_name, update_module=True, force_demo=install_demo_data)
27
28     return registry
29
30 # From http://code.activestate.com/recipes/576572/
31 @contextlib.contextmanager
32 def lock_file(path, wait_delay=.1, max_try=600):
33     attempt = 0
34     while True:
35         attempt += 1
36         if attempt > max_try:
37             raise IOError("Could not lock file %s." % path)
38         try:
39             fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
40         except OSError, e:
41             if e.errno != errno.EEXIST:
42                 raise
43             time.sleep(wait_delay)
44             continue
45         else:
46             break
47     try:
48         yield fd
49     finally:
50         os.close(fd)
51         os.unlink(path)
52
53 # TODO turn template1 in a parameter
54 # This should be exposed from openerp (currently in
55 # openerp/service/web_services.py).
56 def create_database(database_name):
57     import openerp
58     db = openerp.sql_db.db_connect('template1')
59     cr = db.cursor() # TODO `with db as cr:`
60     try:
61         cr.autocommit(True)
62         cr.execute("""CREATE DATABASE "%s"
63             ENCODING 'unicode' TEMPLATE "template1" """ \
64             % (database_name,))
65     finally:
66         cr.close()
67
68 def run(args):
69     assert args.database
70     assert not (args.module and args.all_modules)
71
72     import openerp
73
74     config = openerp.tools.config
75
76     if args.tests:
77         config['log_handler'] = [':INFO']
78         config['test_enable'] = True
79         config['without_demo'] = False
80     else:
81         config['log_handler'] = [':CRITICAL']
82         config['test_enable'] = False
83         config['without_demo'] = True
84
85     if args.addons:
86         args.addons = args.addons.split(':')
87     else:
88         args.addons = []
89     config['addons_path'] = ','.join(args.addons)
90
91     if args.all_modules:
92         module_names = common.get_addons_from_paths(args.addons, args.exclude)
93     elif args.module:
94         module_names = args.module
95     else:
96         module_names = ['base']
97
98     if args.coverage:
99         import coverage
100         # Without the `include` kwarg, coverage generates 'memory:0xXXXXX'
101         # filenames (which do not exist) and cause it to crash. No idea why.
102         cov = coverage.coverage(branch=True, include='*.py')
103         cov.start()
104     openerp.netsvc.init_logger()
105     registry = install_openerp(args.database, not args.no_create, module_names, not config['without_demo'])
106     if args.coverage:
107         cov.stop()
108         cov.html_report(directory='coverage')
109         # If we wanted the report on stdout:
110         # cov.report()
111
112     # The `_assertion_report` attribute was added on the registry during the
113     # OpenERP 7.0 development.
114     if hasattr(registry, '_assertion_report'):
115         sys.exit(1 if registry._assertion_report.failures else 0)
116
117 def add_parser(subparsers):
118     parser = subparsers.add_parser('initialize',
119         description='Create and initialize a new OpenERP database.')
120     parser.add_argument('-d', '--database', metavar='DATABASE',
121         **common.required_or_default('DATABASE', 'the database to create'))
122     common.add_addons_argument(parser)
123     parser.add_argument('--module', metavar='MODULE', action='append',
124         help='specify a module to install'
125         ' (this option can be repeated)')
126     parser.add_argument('--all-modules', action='store_true',
127         help='install all visible modules (not compatible with --module)')
128     parser.add_argument('--no-create', action='store_true',
129         help='do not create the database, only initialize it')
130     parser.add_argument('--exclude', metavar='MODULE', action='append',
131         help='exclude a module from installation'
132         ' (this option can be repeated)')
133     parser.add_argument('--tests', action='store_true',
134         help='run the tests as modules are installed'
135         ' (use the `run-tests` command to choose specific'
136         ' tests to run against an existing database).'
137         ' Demo data are installed.')
138     parser.add_argument('--coverage', action='store_true',
139         help='report code coverage (particularly useful with --tests).'
140         ' The report is generated in a coverage directory and you can'
141         ' then point your browser to coverage/index.html.')
142
143     parser.set_defaults(run=run)