[MERGE]: Merge with lp:openobject-server
bzr revid: rpa@tinyerp.com-20100924053725-hq7yztizail9m3ul bzr revid: rpa@tinyerp.com-20100927052905-mnf9z0ee9oeakf67
This commit is contained in:
+24
-12
@@ -757,16 +757,21 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
||||
|
||||
return has_updates
|
||||
|
||||
def _check_module_names(cr, module_names):
|
||||
mod_names = set(module_names)
|
||||
if 'base' in mod_names:
|
||||
# ignore dummy 'all' module
|
||||
if 'all' in mod_names:
|
||||
mod_names.remove('all')
|
||||
if mod_names:
|
||||
cr.execute("SELECT count(id) AS count FROM ir_module_module WHERE name in %s", (tuple(mod_names),))
|
||||
if cr.dictfetchone()['count'] != len(mod_names):
|
||||
# find out what module name(s) are incorrect:
|
||||
cr.execute("SELECT name FROM ir_module_module")
|
||||
incorrect_names = mod_names.difference([x['name'] for x in cr.dictfetchall()])
|
||||
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 check_module_name(cr, mods, state):
|
||||
for mod in mods:
|
||||
id = modobj.search(cr, 1, ['&', ('state', '=', state), ('name', '=', mod)])
|
||||
if id:
|
||||
getattr(modobj, states[state])(cr, 1, id)
|
||||
elif mod != 'all':
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: invalid module name!' % (mod))
|
||||
|
||||
if not status:
|
||||
status = {}
|
||||
cr = db.cursor()
|
||||
@@ -795,16 +800,23 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
|
||||
if update_module:
|
||||
modobj = pool.get('ir.module.module')
|
||||
states = {'installed': 'button_upgrade', 'uninstalled': 'button_install'}
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
|
||||
if ('base' in tools.config['init']) or ('base' in tools.config['update']):
|
||||
modobj.update_list(cr, 1)
|
||||
|
||||
_check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys()))
|
||||
|
||||
mods = [k for k in tools.config['init'] if tools.config['init'][k]]
|
||||
check_module_name(cr, mods, 'uninstalled')
|
||||
if mods:
|
||||
ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
|
||||
if ids:
|
||||
modobj.button_install(cr, 1, ids)
|
||||
|
||||
mods = [k for k in tools.config['update'] if tools.config['update'][k]]
|
||||
check_module_name(cr, mods, 'installed')
|
||||
if mods:
|
||||
ids = modobj.search(cr, 1, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
|
||||
if ids:
|
||||
modobj.button_upgrade(cr, 1, ids)
|
||||
|
||||
cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))
|
||||
|
||||
|
||||
@@ -1906,8 +1906,10 @@
|
||||
<tree editable="bottom" string="Config Wizard Steps">
|
||||
<field name="sequence"/>
|
||||
<field name="action_id"/>
|
||||
<field name="restart"/>
|
||||
<field name="state" readonly="1"/>
|
||||
<button name="action_launch" states="open" string="Launch" type="object" icon="gtk-execute" help="Launch Configuration Wizard"/>
|
||||
<button name="action_open" states="cancel,skip,done" string="Set as todo" type="object" icon="gtk-convert"/>
|
||||
<button name="action_launch" states="open" string="Launch this wizard" type="object" icon="gtk-execute"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -1927,10 +1929,8 @@
|
||||
<field name="groups_id" nolabel="1" colspan="4"/>
|
||||
<group colspan="4" col="4">
|
||||
<field name="state" colspan="2" readonly="1"/>
|
||||
<button name="action_launch" states="open" string="Launch" type="object" icon="gtk-execute" help="Launch Configuration Wizard"/>
|
||||
<button name="action_open" states="cancel,skip,done"
|
||||
string="Set as Todo" type="object"
|
||||
icon="gtk-convert"/>
|
||||
<button name="action_launch" states="open" string="Launch" type="object" icon="gtk-execute" help="Launch this wizard"/>
|
||||
<button name="action_open" states="cancel,skip,done" string="Set as todo" type="object" icon="gtk-convert"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -753,7 +753,7 @@ act_window_close()
|
||||
TODO_STATES = [('open', 'To Do'),
|
||||
('done', 'Done'),
|
||||
('skip','Skipped'),
|
||||
('cancel','Cancel')]
|
||||
('cancel','Cancelled')]
|
||||
|
||||
class ir_actions_todo(osv.osv):
|
||||
_name = 'ir.actions.todo'
|
||||
@@ -769,9 +769,9 @@ class ir_actions_todo(osv.osv):
|
||||
'note':fields.text('Text', translate=True),
|
||||
}
|
||||
_defaults={
|
||||
'state': lambda *a: 'open',
|
||||
'sequence': lambda *a: 10,
|
||||
'restart': lambda *a: 'always',
|
||||
'state': 'open',
|
||||
'sequence': 10,
|
||||
'restart': 'onskip',
|
||||
}
|
||||
_order="sequence,id"
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ class ir_attachment(osv.osv):
|
||||
'datas': fields.binary('Data'),
|
||||
'datas_fname': fields.char('Filename',size=256),
|
||||
'description': fields.text('Description'),
|
||||
'res_name': fields.function(_name_get_resname, type='char',
|
||||
string='Resource Name', method=True),
|
||||
'res_name': fields.function(_name_get_resname, type='char', size=128,
|
||||
string='Resource Name', method=True, store=True),
|
||||
'res_model': fields.char('Resource Object',size=64, readonly=True,
|
||||
help="The database object this attachment will be attached to"),
|
||||
'res_id': fields.integer('Resource ID', readonly=True,
|
||||
|
||||
@@ -88,7 +88,7 @@ class report_custom(osv.osv):
|
||||
c_f[i] = []
|
||||
tmp = report.fields_child0[i]
|
||||
for j in range(3):
|
||||
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
|
||||
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j),{},{'tmp':tmp}), browse_null) and eval('tmp.field_child'+str(j)+'.ttype',{},{'tmp':tmp})) or None)
|
||||
if not reduce(lambda x,y : x or y, map(lambda x: x in ['integer', 'float'], c_f[1])):
|
||||
raise osv.except_osv(_('Invalid operation'), _('Second field should be figures'))
|
||||
|
||||
@@ -101,7 +101,7 @@ class report_custom(osv.osv):
|
||||
c_f[i] = []
|
||||
tmp = report.fields_child0[i]
|
||||
for j in range(3):
|
||||
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j)), browse_null) and eval('tmp.field_child'+str(j)+'.ttype')) or None)
|
||||
c_f[i].append((not isinstance(eval('tmp.field_child'+str(j),{},{'tmp':tmp}), browse_null) and eval('tmp.field_child'+str(j)+'.ttype',{},{'tmp':tmp})) or None)
|
||||
|
||||
if i == 0:
|
||||
pass
|
||||
|
||||
@@ -162,9 +162,9 @@
|
||||
<field name="installed_version"/>
|
||||
<field name="latest_version"/>
|
||||
<field name="state"/>
|
||||
<button name="button_install" states="uninstalled" string="Schedule for Installation" icon="terp-gtk-jump-to-ltr" type="object" help="Schedule for Installation"/>
|
||||
<button name="button_install" states="uninstalled" string="Schedule for Installation" icon="terp-gtk-jump-to-ltr" type="object"/>
|
||||
<button name="button_install_cancel" states="to install" string="Cancel Install" icon="gtk-cancel" type="object"/>
|
||||
<button name="button_upgrade" states="installed" string="Schedule Upgrade" icon="terp-gtk-go-back-rtl" type="object" help="Schedule Upgrade"/>
|
||||
<button name="button_upgrade" states="installed" string="Schedule Upgrade" icon="terp-gtk-go-back-rtl" type="object"/>
|
||||
<button name="button_uninstall" states="installed" string="Uninstall (beta)" icon="terp-dialog-close" type="object"/>
|
||||
<button name="button_uninstall_cancel" states="to remove" string="Cancel Uninstall" icon="gtk-cancel" type="object"/>
|
||||
<button name="button_upgrade_cancel" states="to upgrade" string="Cancel Upgrade" icon="gtk-cancel" type="object"/>
|
||||
|
||||
@@ -3,27 +3,24 @@
|
||||
<data>
|
||||
|
||||
<record id="view_base_language_install" model="ir.ui.view">
|
||||
<field name="name">Install Language</field>
|
||||
<field name="name">Load Official Translation</field>
|
||||
<field name="model">base.language.install</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="System Upgrade">
|
||||
<group colspan="2" col="4">
|
||||
<separator string="System Upgrade" colspan="6"/>
|
||||
<newline/>
|
||||
<label align="0.0" string="Choose a language to install:" colspan="4"/>
|
||||
<field name="lang" colspan="4"/>
|
||||
<label align="0.0" string="Note that this operation may take a few minutes." colspan="4"/>
|
||||
<separator string="" colspan="6"/>
|
||||
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
|
||||
<button name="lang_install" string="Start installation" type="object" icon="gtk-ok"/>
|
||||
</group>
|
||||
</form>
|
||||
<form string="Load Official Translation">
|
||||
<separator string="Load an Official Translation" colspan="4"/>
|
||||
<group colspan="4"><field name="lang"/></group>
|
||||
<label string="" colspan="4"/>
|
||||
<label string="Please be patient, as this operation may take a few minutes..." colspan="4"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
|
||||
<button name="lang_install" string="Load" type="object" icon="gtk-ok"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_base_language_install" model="ir.actions.act_window">
|
||||
<field name="name">Install Language</field>
|
||||
<field name="name">Load Official Translation</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">base.language.install</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -38,23 +35,21 @@
|
||||
parent="menu_translation"/>
|
||||
|
||||
<record id="view_base_language_install_msg" model="ir.ui.view">
|
||||
<field name="name">Install Language Message</field>
|
||||
<field name="name">Official Translation Loaded</field>
|
||||
<field name="model">base.module.import.msg</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Language file loaded.">
|
||||
<group colspan="2" col="4">
|
||||
<separator string="Installation Done" colspan="4"/>
|
||||
<label align="0.0" string="The selected language has been successfully installed.\nYou must change the preferences of the user and open a new menu to view changes." colspan="4"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<button special="cancel" string="OK" icon="gtk-ok"/>
|
||||
</group>
|
||||
<form string="Official Translation Loaded">
|
||||
<separator string="Official Translation Loaded" colspan="4"/>
|
||||
<label string="The selected language has been successfully installed.\nYou must change the preferences of the user and open a new menu to view the changes." colspan="4"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<button special="cancel" string="OK" icon="gtk-ok"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_base_language_install_msg" model="ir.actions.act_window">
|
||||
<field name="name">Install Language Message</field>
|
||||
<field name="name">Official Translation Loaded</field>
|
||||
<field name="res_model">base.module.import.msg</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
##############################################################################
|
||||
|
||||
from osv import osv,fields
|
||||
from operator import attrgetter
|
||||
from tools.misc import attrgetter
|
||||
import time
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Properties
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -31,7 +32,6 @@ class ir_property(osv.osv):
|
||||
|
||||
def _models_field_get(self, cr, uid, field_key, field_value, context=None):
|
||||
get = attrgetter(field_key, field_value)
|
||||
|
||||
obj = self.pool.get('ir.model.fields')
|
||||
ids = obj.search(cr, uid, [('view_load','=',1)], context=context)
|
||||
res = set()
|
||||
@@ -40,7 +40,7 @@ class ir_property(osv.osv):
|
||||
return res
|
||||
|
||||
def _models_get(self, cr, uid, context=None):
|
||||
return self._models_field_get(cr, uid, 'model', 'name', context)
|
||||
return self._models_field_get(cr, uid, 'model', 'model_id.name', context)
|
||||
|
||||
def _models_get2(self, cr, uid, context=None):
|
||||
return self._models_field_get(cr, uid, 'relation', 'relation', context)
|
||||
@@ -50,7 +50,7 @@ class ir_property(osv.osv):
|
||||
'name': fields.char('Name', size=128, select=1),
|
||||
|
||||
'res_id': fields.reference('Resource', selection=_models_get, size=128,
|
||||
help="If not set, act as default property", select=1),
|
||||
help="If not set, acts as a default value for new resources", select=1),
|
||||
'company_id': fields.many2one('res.company', 'Company', select=1),
|
||||
'fields_id': fields.many2one('ir.model.fields', 'Field', ondelete='cascade', required=True, select=1),
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<assert
|
||||
model="res.currency.rate"
|
||||
search="[('currency_id', '=', ref('INR'))]"
|
||||
count="3"
|
||||
count="1"
|
||||
string="Rate entries for Indian rupee">
|
||||
<test expr="True"/>
|
||||
</assert>
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
<!-- model="res.currency"-->
|
||||
<!-- id="INR"-->
|
||||
<!-- string="Indian rupee rate in 2009">-->
|
||||
<!-- <!-- date specified in data element's context -->-->
|
||||
<!-- date specified in data element's context -->
|
||||
<!-- <test expr="str(rate)">65.8287</test>-->
|
||||
<!-- </assert>-->
|
||||
<!-- </assert> -->
|
||||
<assert
|
||||
model="res.currency"
|
||||
id="INR"
|
||||
string="Indian rupee rate in 2002"
|
||||
context="{'date': '2010-06-01'}">
|
||||
<test expr="str(rate)">58.8287</test>
|
||||
<test expr="str(rate)">59.9739</test>
|
||||
</assert>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+10
-2
@@ -348,11 +348,19 @@ class Agent(object):
|
||||
current_thread.dbname = dbname # hack hack
|
||||
cls._logger.notifyChannel('timers', LOG_DEBUG, "Run %s.%s(*%r, **%r)" % (function.im_class.__name__, function.func_name, args, kwargs))
|
||||
delattr(current_thread, 'dbname')
|
||||
threading.Thread(target=function, args=args, kwargs=kwargs).start()
|
||||
task_thread = threading.Thread(target=function, name='netsvc.Agent.task', args=args, kwargs=kwargs)
|
||||
# force non-daemon task threads (the runner thread must be daemon, and this property is inherited by default)
|
||||
task_thread.setDaemon(False)
|
||||
task_thread.start()
|
||||
time.sleep(1)
|
||||
time.sleep(60)
|
||||
|
||||
threading.Thread(target=Agent.runner).start()
|
||||
agent_runner = threading.Thread(target=Agent.runner, name="netsvc.Agent.runner")
|
||||
# the agent runner is a typical daemon thread, that will never quit and must be
|
||||
# terminated when the main process exits - with no consequence (the processing
|
||||
# threads it spawns are not marked daemon)
|
||||
agent_runner.setDaemon(True)
|
||||
agent_runner.start()
|
||||
|
||||
|
||||
import traceback
|
||||
|
||||
+57
-41
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
@@ -16,7 +16,7 @@
|
||||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
@@ -27,16 +27,19 @@ 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 - Tiny sprl
|
||||
(c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a.
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------
|
||||
# python imports
|
||||
#----------------------------------------------------------
|
||||
import sys
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import pwd
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
import release
|
||||
__author__ = release.author
|
||||
@@ -52,23 +55,22 @@ if pwd.getpwuid(os.getuid())[0] == 'root' :
|
||||
# get logger
|
||||
#----------------------------------------------------------
|
||||
import netsvc
|
||||
logger = netsvc.Logger()
|
||||
logger = logging.getLogger('server')
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# import the tools module so that the commandline parameters are parsed
|
||||
#-----------------------------------------------------------------------
|
||||
import tools
|
||||
|
||||
logger.notifyChannel("server", netsvc.LOG_INFO, "version - %s" % release.version )
|
||||
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.notifyChannel("server", netsvc.LOG_INFO, "%s - %s" % ( name, value ))
|
||||
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.notifyChannel("server", netsvc.LOG_ERROR, "%s" % ("Attempted to connect database with postgres user. This is a security flaws, aborting."))
|
||||
logger.error("Connecting to the database as 'postgres' user is forbidden, as it present major security issues. Shutting down.")
|
||||
sys.exit(1)
|
||||
|
||||
import time
|
||||
@@ -76,7 +78,7 @@ import time
|
||||
#----------------------------------------------------------
|
||||
# init net service
|
||||
#----------------------------------------------------------
|
||||
logger.notifyChannel("objects", netsvc.LOG_INFO, 'initialising distributed objects services')
|
||||
logger.info('initialising distributed objects services')
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# connect to the database and initialize it with base if needed
|
||||
@@ -117,8 +119,7 @@ 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)
|
||||
if tools.config["test_file"]:
|
||||
logger.notifyChannel("init", netsvc.LOG_INFO,
|
||||
'loading test file %s' % (tools.config["test_file"],))
|
||||
logger.info('loading test file %s', tools.config["test_file"])
|
||||
cr = db.cursor()
|
||||
tools.convert_yaml_import(cr, 'base', file(tools.config["test_file"]), {}, 'test', True)
|
||||
cr.rollback()
|
||||
@@ -134,16 +135,14 @@ if tools.config["translate_out"]:
|
||||
msg = "language %s" % (tools.config["language"],)
|
||||
else:
|
||||
msg = "new language"
|
||||
logger.notifyChannel("init", netsvc.LOG_INFO,
|
||||
'writing translation file for %s to %s' % (msg,
|
||||
tools.config["translate_out"]))
|
||||
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")
|
||||
tools.trans_export(tools.config["language"], tools.config["translate_modules"], buf, fileformat)
|
||||
buf.close()
|
||||
|
||||
logger.notifyChannel("init", netsvc.LOG_INFO, 'translation file written successfully')
|
||||
logger.info('translation file written successfully')
|
||||
sys.exit(0)
|
||||
|
||||
if tools.config["translate_in"]:
|
||||
@@ -169,30 +168,23 @@ SIGNALS = dict(
|
||||
[(getattr(signal, sign), sign) for sign in LST_SIGNALS]
|
||||
)
|
||||
|
||||
def handler(signum, _):
|
||||
netsvc.quit_signals_received = 0
|
||||
|
||||
def handler(signum, frame):
|
||||
"""
|
||||
:param signum: the signal number
|
||||
:param _:
|
||||
:param frame: the interrupted stack frame or None
|
||||
"""
|
||||
netsvc.Agent.quit()
|
||||
netsvc.Server.quitAll()
|
||||
if tools.config['pidfile']:
|
||||
os.unlink(tools.config['pidfile'])
|
||||
logger.notifyChannel('shutdown', netsvc.LOG_INFO,
|
||||
"Shutdown Server! - %s" % ( SIGNALS[signum], ))
|
||||
logger.shutdown()
|
||||
sys.exit(0)
|
||||
netsvc.quit_signals_received += 1
|
||||
if netsvc.quit_signals_received > 1:
|
||||
sys.stderr.write("Forced shutdown.\n")
|
||||
os._exit(0)
|
||||
|
||||
for signum in SIGNALS:
|
||||
signal.signal(signum, handler)
|
||||
|
||||
|
||||
import threading
|
||||
import traceback
|
||||
def dumpstacks(signum, _):
|
||||
def dumpstacks(signum, frame):
|
||||
# code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
|
||||
|
||||
id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
|
||||
# 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))
|
||||
@@ -200,25 +192,49 @@ def dumpstacks(signum, _):
|
||||
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))
|
||||
|
||||
logger.notifyChannel("dumpstacks", netsvc.LOG_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.notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
'the server is running, waiting for connections...')
|
||||
logger.info('OpenERP server is running, waiting for connections...')
|
||||
|
||||
while True:
|
||||
while netsvc.quit_signals_received == 0:
|
||||
time.sleep(60)
|
||||
|
||||
quit()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
+1
-1
@@ -777,7 +777,7 @@ class related(function):
|
||||
if not ids: return {}
|
||||
relation = obj._name
|
||||
if self._type in ('one2many', 'many2many'):
|
||||
res = {}.fromkeys(ids, [])
|
||||
res = dict([(i, []) for i in ids])
|
||||
else:
|
||||
res = {}.fromkeys(ids, False)
|
||||
|
||||
|
||||
@@ -2275,6 +2275,9 @@ class orm(orm_template):
|
||||
del r['id']
|
||||
if groupby and fget[groupby]['type'] == 'many2one':
|
||||
data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=groupby, context=context)
|
||||
# the IDS of the records that has groupby field value = False or ''
|
||||
# should be added too
|
||||
data_ids += filter(lambda x:x not in data_ids, alldata.keys())
|
||||
data = self.read(cr, uid, data_ids, groupby and [groupby] or ['id'], context=context)
|
||||
# restore order of the search as read() uses the default _order (this is only for groups, so the size of data_read shoud be small):
|
||||
data.sort(lambda x,y: cmp(data_ids.index(x['id']), data_ids.index(y['id'])))
|
||||
|
||||
@@ -73,7 +73,7 @@ class report_custom(report_int):
|
||||
for cond in conditions:
|
||||
if cond and cond[0]:
|
||||
c = cond[0]
|
||||
temp = c[0](eval('obj.'+c[1]))
|
||||
temp = c[0](eval('obj.'+c[1],{'obj': obj}))
|
||||
if not eval('\''+temp+'\''+' '+c[2]+' '+'\''+str(c[3])+'\''):
|
||||
tobreak = True
|
||||
if tobreak:
|
||||
@@ -87,7 +87,7 @@ class report_custom(report_int):
|
||||
row_canvas[i]=False
|
||||
elif len(fields[i])==1:
|
||||
if not isinstance(obj, browse_null):
|
||||
row.append(str(eval('obj.'+fields[i][0])))
|
||||
row.append(str(eval('obj.'+fields[i][0],{'obj': obj})))
|
||||
else:
|
||||
row.append(None)
|
||||
else:
|
||||
@@ -107,7 +107,7 @@ class report_custom(report_int):
|
||||
else:
|
||||
key = levels.keys()
|
||||
for l in key:
|
||||
objs = eval('obj.'+l)
|
||||
objs = eval('obj.'+l,{'obj': obj})
|
||||
if not isinstance(objs, browse_record_list) and type(objs) <> type([]):
|
||||
objs = [objs]
|
||||
field_new = []
|
||||
@@ -192,7 +192,7 @@ class report_custom(report_int):
|
||||
def build_tree(obj, level, depth):
|
||||
res = self._row_get(cr, uid,[obj], new_fields, new_cond)
|
||||
level.append(depth)
|
||||
new_obj = eval('obj.'+report['field_parent'][1])
|
||||
new_obj = eval('obj.'+report['field_parent'][1],{'obj': obj})
|
||||
if not isinstance(new_obj, list) :
|
||||
new_obj = [new_obj]
|
||||
for o in new_obj:
|
||||
|
||||
@@ -137,7 +137,7 @@ class BaseHttpDaemon(threading.Thread, netsvc.Server):
|
||||
_RealProto = '??'
|
||||
|
||||
def __init__(self, interface, port, handler):
|
||||
threading.Thread.__init__(self)
|
||||
threading.Thread.__init__(self, name='%sDaemon-%d'%(self._RealProto, port))
|
||||
netsvc.Server.__init__(self)
|
||||
self.__port = port
|
||||
self.__interface = interface
|
||||
|
||||
@@ -102,7 +102,7 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
|
||||
|
||||
class TinySocketServerThread(threading.Thread,netsvc.Server):
|
||||
def __init__(self, interface, port, secure=False):
|
||||
threading.Thread.__init__(self, name="Net-RPC socket")
|
||||
threading.Thread.__init__(self, name="NetRPCDaemon-%d"%port)
|
||||
netsvc.Server.__init__(self)
|
||||
self.__port = port
|
||||
self.__interface = interface
|
||||
|
||||
+26
-7
@@ -419,6 +419,13 @@ def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False,
|
||||
:return: True if the mail was delivered successfully to the smtp,
|
||||
else False (+ exception logged)
|
||||
"""
|
||||
class WriteToLogger(object):
|
||||
def __init__(self):
|
||||
self.logger = netsvc.Logger()
|
||||
|
||||
def write(self, s):
|
||||
self.logger.notifyChannel('email_send', netsvc.LOG_DEBUG, s)
|
||||
|
||||
if openobject_id:
|
||||
message['Message-Id'] = generate_tracking_message_id(openobject_id)
|
||||
|
||||
@@ -534,13 +541,6 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
|
||||
part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
|
||||
msg.attach(part)
|
||||
|
||||
class WriteToLogger(object):
|
||||
def __init__(self):
|
||||
self.logger = netsvc.Logger()
|
||||
|
||||
def write(self, s):
|
||||
self.logger.notifyChannel('email_send', netsvc.LOG_DEBUG, s)
|
||||
|
||||
return _email_send(email_from, flatten([email_to, email_cc, email_bcc]), msg, openobject_id=openobject_id, ssl=ssl, debug=debug)
|
||||
|
||||
#----------------------------------------------------------
|
||||
@@ -1406,5 +1406,24 @@ def upload_data(email, data, type='SURVEY'):
|
||||
a = upload_data_thread(email, data, type)
|
||||
a.start()
|
||||
return True
|
||||
|
||||
|
||||
# port of python 2.6's attrgetter with support for dotted notation
|
||||
def resolve_attr(obj, attr):
|
||||
for name in attr.split("."):
|
||||
obj = getattr(obj, name)
|
||||
return obj
|
||||
|
||||
def attrgetter(*items):
|
||||
if len(items) == 1:
|
||||
attr = items[0]
|
||||
def g(obj):
|
||||
return resolve_attr(obj, attr)
|
||||
else:
|
||||
def g(obj):
|
||||
return tuple(resolve_attr(obj, attr) for attr in items)
|
||||
return g
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user