[MERGE] merge of the openerp python module branch.

bzr revid: vmt@openerp.com-20110208150149-x4vu09aj42ezma5a
This commit is contained in:
Vo Minh Thu 2011-02-08 16:01:49 +01:00
commit 6713d57ab1
413 changed files with 678 additions and 592 deletions

View File

@ -1,255 +1,19 @@
#!/usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: UTF-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
OpenERP - Server
OpenERP is an ERP+CRM program for small and medium businesses.
The whole source code is distributed under the terms of the
GNU Public Licence.
(c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a.
"""
#----------------------------------------------------------
# python imports
#----------------------------------------------------------
import logging
import os import os
import signal
import sys import sys
import threading
import traceback
import release if __name__ == "__main__":
__author__ = release.author print '-' * 70
__version__ = release.version print "DEPRECATED: you are starting the OpenERP server with its old path,"
print "please use the new executable (available in the parent directory)."
print '-' * 70
if os.name == 'posix': # Change to the parent directory ...
import pwd os.chdir(os.path.normpath(os.path.dirname(__file__)))
# We DON't log this using the standard logger, because we might mess os.chdir('..')
# with the logfile's permissions. Just do a quick exit here. # ... and execute the new executable.
if pwd.getpwuid(os.getuid())[0] == 'root' : os.execv('openerp-server.py', sys.argv)
sys.stderr.write("Attempted to run OpenERP server as root. This is not good, aborting.\n")
sys.exit(1)
#----------------------------------------------------------
# get logger
#----------------------------------------------------------
import netsvc
logger = logging.getLogger('server')
#-----------------------------------------------------------------------
# import the tools module so that the commandline parameters are parsed
#-----------------------------------------------------------------------
import tools
logger.info("OpenERP version - %s", release.version)
for name, value in [('addons_path', tools.config['addons_path']),
('database hostname', tools.config['db_host'] or 'localhost'),
('database port', tools.config['db_port'] or '5432'),
('database user', tools.config['db_user'])]:
logger.info("%s - %s", name, value)
# Don't allow if the connection to PostgreSQL done by postgres user
if tools.config['db_user'] == 'postgres':
logger.error("Connecting to the database as 'postgres' user is forbidden, as it present major security issues. Shutting down.")
sys.exit(1)
import time
#----------------------------------------------------------
# init net service
#----------------------------------------------------------
logger.info('initialising distributed objects services')
#---------------------------------------------------------------
# connect to the database and initialize it with base if needed
#---------------------------------------------------------------
import pooler
#----------------------------------------------------------
# import basic modules
#----------------------------------------------------------
import osv
import workflow
import report
import service
#----------------------------------------------------------
# import addons
#----------------------------------------------------------
import addons
#----------------------------------------------------------
# Load and update databases if requested
#----------------------------------------------------------
import service.http_server
if not ( tools.config["stop_after_init"] or \
tools.config["translate_in"] or \
tools.config["translate_out"] ):
service.http_server.init_servers()
service.http_server.init_xmlrpc()
service.http_server.init_static_http()
import service.netrpc_server
service.netrpc_server.init_servers()
if tools.config['db_name']:
for dbname in tools.config['db_name'].split(','):
db,pool = pooler.get_db_and_pool(dbname, update_module=tools.config['init'] or tools.config['update'], pooljobs=False)
cr = db.cursor()
if tools.config["test_file"]:
logger.info('loading test file %s', tools.config["test_file"])
tools.convert_yaml_import(cr, 'base', file(tools.config["test_file"]), {}, 'test', True)
cr.rollback()
pool.get('ir.cron')._poolJobs(db.dbname)
cr.close()
#----------------------------------------------------------
# translation stuff
#----------------------------------------------------------
if tools.config["translate_out"]:
import csv
if tools.config["language"]:
msg = "language %s" % (tools.config["language"],)
else:
msg = "new language"
logger.info('writing translation file for %s to %s', msg, tools.config["translate_out"])
fileformat = os.path.splitext(tools.config["translate_out"])[-1][1:].lower()
buf = file(tools.config["translate_out"], "w")
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_export(tools.config["language"], tools.config["translate_modules"] or ["all"], buf, fileformat, cr)
cr.close()
buf.close()
logger.info('translation file written successfully')
sys.exit(0)
if tools.config["translate_in"]:
context = {'overwrite': tools.config["overwrite_existing_translations"]}
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_load(cr,
tools.config["translate_in"],
tools.config["language"],
context=context)
tools.trans_update_res_ids(cr)
cr.commit()
cr.close()
sys.exit(0)
#----------------------------------------------------------------------------------
# if we don't want the server to continue to run after initialization, we quit here
#----------------------------------------------------------------------------------
if tools.config["stop_after_init"]:
sys.exit(0)
#----------------------------------------------------------
# Launch Servers
#----------------------------------------------------------
LST_SIGNALS = ['SIGINT', 'SIGTERM']
SIGNALS = dict(
[(getattr(signal, sign), sign) for sign in LST_SIGNALS]
)
netsvc.quit_signals_received = 0
def handler(signum, frame):
"""
:param signum: the signal number
:param frame: the interrupted stack frame or None
"""
netsvc.quit_signals_received += 1
if netsvc.quit_signals_received > 1:
sys.stderr.write("Forced shutdown.\n")
os._exit(0)
def dumpstacks(signum, frame):
# code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
# modified for python 2.5 compatibility
thread_map = dict(threading._active, **threading._limbo)
id2name = dict([(threadId, thread.getName()) for threadId, thread in thread_map.items()])
code = []
for threadId, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name[threadId], threadId))
for filename, lineno, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
if line:
code.append(" %s" % (line.strip()))
logging.getLogger('dumpstacks').info("\n".join(code))
for signum in SIGNALS:
signal.signal(signum, handler)
if os.name == 'posix':
signal.signal(signal.SIGQUIT, dumpstacks)
def quit():
netsvc.Agent.quit()
netsvc.Server.quitAll()
if tools.config['pidfile']:
os.unlink(tools.config['pidfile'])
logger = logging.getLogger('shutdown')
logger.info("Initiating OpenERP Server shutdown")
logger.info("Hit CTRL-C again or send a second signal to immediately terminate the server...")
logging.shutdown()
# manually join() all threads before calling sys.exit() to allow a second signal
# to trigger _force_quit() in case some non-daemon threads won't exit cleanly.
# threading.Thread.join() should not mask signals (at least in python 2.5)
for thread in threading.enumerate():
if thread != threading.currentThread() and not thread.isDaemon():
while thread.isAlive():
# need a busyloop here as thread.join() masks signals
# and would present the forced shutdown
thread.join(0.05)
time.sleep(0.05)
sys.exit(0)
if tools.config['pidfile']:
fd = open(tools.config['pidfile'], 'w')
pidtext = "%d" % (os.getpid())
fd.write(pidtext)
fd.close()
netsvc.Server.startAll()
logger.info('OpenERP server is running, waiting for connections...')
while netsvc.quit_signals_received == 0:
time.sleep(60)
quit()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

258
openerp-server.py Executable file
View File

@ -0,0 +1,258 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
OpenERP - Server
OpenERP is an ERP+CRM program for small and medium businesses.
The whole source code is distributed under the terms of the
GNU Public Licence.
(c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a.
"""
#----------------------------------------------------------
# python imports
#----------------------------------------------------------
import logging
import os
import signal
import sys
import threading
import traceback
import openerp.release as release
__author__ = release.author
__version__ = release.version
if os.name == 'posix':
import pwd
# We DON't log this using the standard logger, because we might mess
# with the logfile's permissions. Just do a quick exit here.
if pwd.getpwuid(os.getuid())[0] == 'root' :
sys.stderr.write("Attempted to run OpenERP server as root. This is not good, aborting.\n")
sys.exit(1)
#-----------------------------------------------------------------------
# import the tools module so that the commandline parameters are parsed
#-----------------------------------------------------------------------
import openerp.tools as tools
tools.config.parse_config(sys.argv[1:])
#----------------------------------------------------------
# get logger
#----------------------------------------------------------
import openerp.netsvc as netsvc
netsvc.init_logger()
logger = logging.getLogger('server')
logger.info("OpenERP version - %s", release.version)
for name, value in [('addons_path', tools.config['addons_path']),
('database hostname', tools.config['db_host'] or 'localhost'),
('database port', tools.config['db_port'] or '5432'),
('database user', tools.config['db_user'])]:
logger.info("%s - %s", name, value)
# Don't allow if the connection to PostgreSQL done by postgres user
if tools.config['db_user'] == 'postgres':
logger.error("Connecting to the database as 'postgres' user is forbidden, as it present major security issues. Shutting down.")
sys.exit(1)
import time
#----------------------------------------------------------
# init net service
#----------------------------------------------------------
logger.info('initialising distributed objects services')
#---------------------------------------------------------------
# connect to the database and initialize it with base if needed
#---------------------------------------------------------------
import openerp.pooler as pooler
#----------------------------------------------------------
# import basic modules
#----------------------------------------------------------
import openerp.osv as osv
import openerp.workflow as workflow
import openerp.report as report
import openerp.service as service
#----------------------------------------------------------
# import addons
#----------------------------------------------------------
import openerp.addons as addons
#----------------------------------------------------------
# Load and update databases if requested
#----------------------------------------------------------
import openerp.service.http_server as service_http_server
if not ( tools.config["stop_after_init"] or \
tools.config["translate_in"] or \
tools.config["translate_out"] ):
service_http_server.init_servers()
service_http_server.init_xmlrpc()
service_http_server.init_static_http()
import openerp.service.netrpc_server as service_netrpc_server
service_netrpc_server.init_servers()
if tools.config['db_name']:
for dbname in tools.config['db_name'].split(','):
db,pool = pooler.get_db_and_pool(dbname, update_module=tools.config['init'] or tools.config['update'], pooljobs=False)
cr = db.cursor()
if tools.config["test_file"]:
logger.info('loading test file %s', tools.config["test_file"])
tools.convert_yaml_import(cr, 'base', file(tools.config["test_file"]), {}, 'test', True)
cr.rollback()
pool.get('ir.cron')._poolJobs(db.dbname)
cr.close()
#----------------------------------------------------------
# translation stuff
#----------------------------------------------------------
if tools.config["translate_out"]:
import csv
if tools.config["language"]:
msg = "language %s" % (tools.config["language"],)
else:
msg = "new language"
logger.info('writing translation file for %s to %s', msg, tools.config["translate_out"])
fileformat = os.path.splitext(tools.config["translate_out"])[-1][1:].lower()
buf = file(tools.config["translate_out"], "w")
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_export(tools.config["language"], tools.config["translate_modules"] or ["all"], buf, fileformat, cr)
cr.close()
buf.close()
logger.info('translation file written successfully')
sys.exit(0)
if tools.config["translate_in"]:
context = {'overwrite': tools.config["overwrite_existing_translations"]}
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_load(cr,
tools.config["translate_in"],
tools.config["language"],
context=context)
tools.trans_update_res_ids(cr)
cr.commit()
cr.close()
sys.exit(0)
#----------------------------------------------------------------------------------
# if we don't want the server to continue to run after initialization, we quit here
#----------------------------------------------------------------------------------
if tools.config["stop_after_init"]:
sys.exit(0)
#----------------------------------------------------------
# Launch Servers
#----------------------------------------------------------
LST_SIGNALS = ['SIGINT', 'SIGTERM']
SIGNALS = dict(
[(getattr(signal, sign), sign) for sign in LST_SIGNALS]
)
netsvc.quit_signals_received = 0
def handler(signum, frame):
"""
:param signum: the signal number
:param frame: the interrupted stack frame or None
"""
netsvc.quit_signals_received += 1
if netsvc.quit_signals_received > 1:
sys.stderr.write("Forced shutdown.\n")
os._exit(0)
def dumpstacks(signum, frame):
# code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
# modified for python 2.5 compatibility
thread_map = dict(threading._active, **threading._limbo)
id2name = dict([(threadId, thread.getName()) for threadId, thread in thread_map.items()])
code = []
for threadId, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name[threadId], threadId))
for filename, lineno, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
if line:
code.append(" %s" % (line.strip()))
logging.getLogger('dumpstacks').info("\n".join(code))
for signum in SIGNALS:
signal.signal(signum, handler)
if os.name == 'posix':
signal.signal(signal.SIGQUIT, dumpstacks)
def quit():
netsvc.Agent.quit()
netsvc.Server.quitAll()
if tools.config['pidfile']:
os.unlink(tools.config['pidfile'])
logger = logging.getLogger('shutdown')
logger.info("Initiating OpenERP Server shutdown")
logger.info("Hit CTRL-C again or send a second signal to immediately terminate the server...")
logging.shutdown()
# manually join() all threads before calling sys.exit() to allow a second signal
# to trigger _force_quit() in case some non-daemon threads won't exit cleanly.
# threading.Thread.join() should not mask signals (at least in python 2.5)
for thread in threading.enumerate():
if thread != threading.currentThread() and not thread.isDaemon():
while thread.isAlive():
# need a busyloop here as thread.join() masks signals
# and would present the forced shutdown
thread.join(0.05)
time.sleep(0.05)
sys.exit(0)
if tools.config['pidfile']:
fd = open(tools.config['pidfile'], 'w')
pidtext = "%d" % (os.getpid())
fd.write(pidtext)
fd.close()
netsvc.Server.startAll()
logger.info('OpenERP server is running, waiting for connections...')
while netsvc.quit_signals_received == 0:
time.sleep(60)
quit()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -19,6 +19,23 @@
# #
############################################################################## ##############################################################################
import addons
import ir
import loglevels
import netsvc
import osv
import pooler
import pychart
import release
import report
import run_tests
import service
import sql_db
import test
import tiny_socket
import tools
import wizard
import workflow
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -25,17 +25,17 @@ from os.path import join as opj
import itertools import itertools
import zipimport import zipimport
import osv import openerp.osv as osv
import tools import openerp.tools as tools
import tools.osutil import openerp.tools.osutil as osutil
from tools.safe_eval import safe_eval as eval from openerp.tools.safe_eval import safe_eval as eval
import pooler import openerp.pooler as pooler
from tools.translate import _ from openerp.tools.translate import _
import netsvc import openerp.netsvc as netsvc
import zipfile import zipfile
import release import openerp.release as release
import re import re
import base64 import base64
@ -44,25 +44,32 @@ from cStringIO import StringIO
import logging import logging
logger = netsvc.Logger() logger = netsvc.Logger()
_ad = os.path.abspath(opj(tools.ustr(tools.config['root_path']), u'addons')) # default addons path (base) _ad = os.path.dirname(__file__) # default addons path (base)
ad_paths= map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(',')) ad_paths = []
sys.path.insert(1, _ad)
ad_cnt=1
for adp in ad_paths:
if adp != _ad:
sys.path.insert(ad_cnt, adp)
ad_cnt+=1
ad_paths.append(_ad) # for get_module_path
# Modules already loaded # Modules already loaded
loaded = [] loaded = []
def initialize_sys_path():
global ad_paths
if ad_paths:
return
ad_paths = map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))
sys.path.insert(1, _ad)
ad_cnt=1
for adp in ad_paths:
if adp != _ad:
sys.path.insert(ad_cnt, adp)
ad_cnt+=1
ad_paths.append(_ad) # for get_module_path
class Graph(dict): class Graph(dict):
def addNode(self, name, deps): def addNode(self, name, deps):
@ -160,6 +167,7 @@ class Node(Singleton):
def get_module_path(module, downloaded=False): def get_module_path(module, downloaded=False):
"""Return the path of the given module.""" """Return the path of the given module."""
initialize_sys_path()
for adp in ad_paths: for adp in ad_paths:
if os.path.exists(opj(adp, module)) or os.path.exists(opj(adp, '%s.zip' % module)): if os.path.exists(opj(adp, module)) or os.path.exists(opj(adp, '%s.zip' % module)):
return opj(adp, module) return opj(adp, module)
@ -186,7 +194,7 @@ def get_module_filetree(module, dir='.'):
zip = zipfile.ZipFile(path + ".zip") zip = zipfile.ZipFile(path + ".zip")
files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()] files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()]
else: else:
files = tools.osutil.listdir(path, True) files = osutil.listdir(path, True)
tree = {} tree = {}
for f in files: for f in files:
@ -218,7 +226,7 @@ def zip_directory(directory, b64enc=True, src=True):
def _zippy(archive, path, src=True): def _zippy(archive, path, src=True):
path = os.path.abspath(path) path = os.path.abspath(path)
base = os.path.basename(path) base = os.path.basename(path)
for f in tools.osutil.listdir(path, True): for f in osutil.listdir(path, True):
bf = os.path.basename(f) bf = os.path.basename(f)
if not RE_exclude.search(bf) and (src or bf in ('__openerp__.py', '__terp__.py') or not bf.endswith('.py')): if not RE_exclude.search(bf) and (src or bf in ('__openerp__.py', '__terp__.py') or not bf.endswith('.py')):
archive.write(os.path.join(path, f), os.path.join(base, f)) archive.write(os.path.join(path, f), os.path.join(base, f))
@ -302,6 +310,7 @@ def get_modules():
return map(clean, filter(is_really_module, os.listdir(dir))) return map(clean, filter(is_really_module, os.listdir(dir)))
plist = [] plist = []
initialize_sys_path()
for ad in ad_paths: for ad in ad_paths:
plist.extend(listdir(ad)) plist.extend(listdir(ad))
return list(set(plist)) return list(set(plist))
@ -442,6 +451,7 @@ def register_class(m):
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: registering objects' % m) logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: registering objects' % m)
mod_path = get_module_path(m) mod_path = get_module_path(m)
initialize_sys_path()
try: try:
zip_mod_path = mod_path + '.zip' zip_mod_path = mod_path + '.zip'
if not os.path.isfile(zip_mod_path): if not os.path.isfile(zip_mod_path):
@ -559,7 +569,7 @@ class MigrationManager(object):
a.update(b) a.update(b)
return a return a
from tools.parse_version import parse_version from openerp.tools.parse_version import parse_version
parsed_installed_version = parse_version(pkg.installed_version or '') parsed_installed_version = parse_version(pkg.installed_version or '')
current_version = parse_version(convert_version(pkg.data.get('version', '0'))) current_version = parse_version(convert_version(pkg.data.get('version', '0')))
@ -798,6 +808,14 @@ def _check_module_names(cr, module_names):
logging.getLogger('init').warning('invalid module names, ignored: %s', ", ".join(incorrect_names)) logging.getLogger('init').warning('invalid module names, ignored: %s', ", ".join(incorrect_names))
def load_modules(db, force_demo=False, status=None, update_module=False): def load_modules(db, force_demo=False, status=None, update_module=False):
initialize_sys_path()
# Backward compatibility: addons don't have to import openerp.xxx, they still can import xxx
for k, v in list(sys.modules.items()):
if k.startswith('openerp.') and sys.modules.get(k[8:]) is None:
sys.modules[k[8:]] = v
if not status: if not status:
status = {} status = {}
cr = db.cursor() cr = db.cursor()

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show More