Remplace all occurences of my_browse_rec.product_id.product_tmpl_id.field to my_brows...
[odoo/odoo.git] / openerp-server
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 ##############################################################################
4 #
5 #    OpenERP, Open Source Management Solution
6 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 """
24 OpenERP - Server
25 OpenERP is an ERP+CRM program for small and medium businesses.
26
27 The whole source code is distributed under the terms of the
28 GNU Public Licence.
29
30 (c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
31 """
32
33 import imp
34 import logging
35 import os
36 import signal
37 import sys
38 import threading
39 import traceback
40 import time
41
42 import openerp
43 __author__ = openerp.release.author
44 __version__ = openerp.release.version
45
46 # Also use the `openerp` logger for the main script.
47 _logger = logging.getLogger('openerp')
48
49 def check_root_user():
50     """ Exit if the process's user is 'root' (on POSIX system)."""
51     if os.name == 'posix':
52         import pwd
53         if pwd.getpwuid(os.getuid())[0] == 'root' :
54             sys.stderr.write("Running as user 'root' is a security risk, aborting.\n")
55             sys.exit(1)
56
57 def check_postgres_user():
58     """ Exit if the configured database user is 'postgres'.
59
60     This function assumes the configuration has been initialized.
61     """
62     config = openerp.tools.config
63     if config['db_user'] == 'postgres':
64         sys.stderr.write("Using the database user 'postgres' is a security risk, aborting.")
65         sys.exit(1)
66
67 def report_configuration():
68     """ Log the server version and some configuration values.
69
70     This function assumes the configuration has been initialized.
71     """
72     config = openerp.tools.config
73     _logger.info("OpenERP version %s", __version__)
74     for name, value in [('addons paths', config['addons_path']),
75                         ('database hostname', config['db_host'] or 'localhost'),
76                         ('database port', config['db_port'] or '5432'),
77                         ('database user', config['db_user'])]:
78         _logger.info("%s: %s", name, value)
79
80 def setup_pid_file():
81     """ Create a file with the process id written in it.
82
83     This function assumes the configuration has been initialized.
84     """
85     config = openerp.tools.config
86     if config['pidfile']:
87         fd = open(config['pidfile'], 'w')
88         pidtext = "%d" % (os.getpid())
89         fd.write(pidtext)
90         fd.close()
91
92 def preload_registry(dbname):
93     """ Preload a registry, and start the cron."""
94     try:
95         db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
96
97         # jobs will start to be processed later, when openerp.cron.start_master_thread() is called by openerp.service.start_services()
98         registry.schedule_cron_jobs()
99     except Exception:
100         _logger.exception('Failed to initialize database `%s`.', dbname)
101
102 def run_test_file(dbname, test_file):
103     """ Preload a registry, possibly run a test file, and start the cron."""
104     try:
105         db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
106         cr = db.cursor()
107         _logger.info('loading test file %s', test_file)
108         openerp.tools.convert_yaml_import(cr, 'base', file(test_file), {}, 'test', True)
109         cr.rollback()
110         cr.close()
111     except Exception:
112         _logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
113
114
115 def export_translation():
116     config = openerp.tools.config
117     dbname = config['db_name']
118
119     if config["language"]:
120         msg = "language %s" % (config["language"],)
121     else:
122         msg = "new language"
123     _logger.info('writing translation file for %s to %s', msg,
124         config["translate_out"])
125
126     fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
127     buf = file(config["translate_out"], "w")
128     cr = openerp.pooler.get_db(dbname).cursor()
129     openerp.tools.trans_export(config["language"],
130         config["translate_modules"] or ["all"], buf, fileformat, cr)
131     cr.close()
132     buf.close()
133
134     _logger.info('translation file written successfully')
135
136 def import_translation():
137     config = openerp.tools.config
138     context = {'overwrite': config["overwrite_existing_translations"]}
139     dbname = config['db_name']
140
141     cr = openerp.pooler.get_db(dbname).cursor()
142     openerp.tools.trans_load( cr, config["translate_in"], config["language"],
143         context=context)
144     cr.commit()
145     cr.close()
146
147 # Variable keeping track of the number of calls to the signal handler defined
148 # below. This variable is monitored by ``quit_on_signals()``.
149 quit_signals_received = 0
150
151 def signal_handler(sig, frame):
152     """ Signal handler: exit ungracefully on the second handled signal.
153
154     :param sig: the signal number
155     :param frame: the interrupted stack frame or None
156     """
157     global quit_signals_received
158     quit_signals_received += 1
159     if quit_signals_received > 1:
160         # logging.shutdown was already called at this point.
161         sys.stderr.write("Forced shutdown.\n")
162         os._exit(0)
163
164 def dumpstacks(sig, frame):
165     """ Signal handler: dump a stack trace for each existing thread."""
166     # code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
167     # modified for python 2.5 compatibility
168     threads_info = dict([(th.ident, {'name': th.name,
169                                     'uid': getattr(th,'uid','n/a')})
170                                 for th in threading.enumerate()])
171     code = []
172     for threadId, stack in sys._current_frames().items():
173         thread_info = threads_info.get(threadId)
174         code.append("\n# Thread: %s (id:%s) (uid:%s)" % \
175                     (thread_info and thread_info['name'] or 'n/a',
176                      threadId,
177                      thread_info and thread_info['uid'] or 'n/a'))
178         for filename, lineno, name, line in traceback.extract_stack(stack):
179             code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
180             if line:
181                 code.append("  %s" % (line.strip()))
182     _logger.info("\n".join(code))
183
184 def setup_signal_handlers():
185     """ Register the signal handler defined above. """
186     SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
187     if os.name == 'posix':
188         map(lambda sig: signal.signal(sig, signal_handler), SIGNALS)
189         signal.signal(signal.SIGQUIT, dumpstacks)
190     elif os.name == 'nt':
191         import win32api
192         win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1)
193
194 def quit_on_signals():
195     """ Wait for one or two signals then shutdown the server.
196
197     The first SIGINT or SIGTERM signal will initiate a graceful shutdown while
198     a second one if any will force an immediate exit.
199
200     """
201     # Wait for a first signal to be handled. (time.sleep will be interrupted
202     # by the signal handler.) The try/except is for the win32 case.
203     try:
204         while quit_signals_received == 0:
205             time.sleep(60)
206     except KeyboardInterrupt, e:
207         pass
208
209     if config['pidfile']:
210         os.unlink(config['pidfile'])
211
212     openerp.service.stop_services()
213     sys.exit(0)
214
215 def configure_babel_localedata_path():
216     # Workaround: py2exe and babel.
217     if hasattr(sys, 'frozen'):
218         import babel
219         babel.localedata._dirname = os.path.join(os.path.dirname(sys.executable), 'localedata')
220
221 if __name__ == "__main__":
222
223     os.environ["TZ"] = "UTC"
224
225     check_root_user()
226     openerp.tools.config.parse_config(sys.argv[1:])
227
228     check_postgres_user()
229     openerp.netsvc.init_logger()
230     report_configuration()
231
232     config = openerp.tools.config
233
234     configure_babel_localedata_path()
235
236     setup_signal_handlers()
237
238     if config["test_file"]:
239         run_test_file(config['db_name'], config['test_file'])
240         sys.exit(0)
241
242     if config["translate_out"]:
243         export_translation()
244         sys.exit(0)
245
246     if config["translate_in"]:
247         import_translation()
248         sys.exit(0)
249
250     if not config["stop_after_init"]:
251         # Some module register themselves when they are loaded so we need the
252         # services to be running before loading any registry.
253         openerp.service.start_services()
254
255     for m in openerp.conf.server_wide_modules:
256         try:
257             openerp.modules.module.load_openerp_module(m)
258         except Exception:
259             msg = ''
260             if m == 'web':
261                 msg = """
262 The `web` module is provided by the addons found in the `openerp-web` project.
263 Maybe you forgot to add those addons in your addons_path configuration."""
264             _logger.exception('Failed to load server-wide module `%s`.%s', m, msg)
265
266     if config['db_name']:
267         for dbname in config['db_name'].split(','):
268             preload_registry(dbname)
269
270     if config["stop_after_init"]:
271         sys.exit(0)
272
273     setup_pid_file()
274     _logger.info('OpenERP server is running, waiting for connections...')
275     quit_on_signals()
276
277 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: