Merge lp:~openerp-dev/openobject-server/trunk-trunk-datadir-chs into lp:openobject-server

Proposed by Christophe Simonis (OpenERP)
Status: Merged
Merged at revision: 5103
Proposed branch: lp:~openerp-dev/openobject-server/trunk-trunk-datadir-chs
Merge into: lp:openobject-server
Diff against target: 1115 lines (+642/-168)
13 files modified
openerp/addons/base/ir/ir_attachment.py (+41/-29)
openerp/addons/base/module/wizard/base_module_import.py (+0/-2)
openerp/addons/base/tests/test_ir_attachment.py (+68/-65)
openerp/cli/server.py (+1/-1)
openerp/http.py (+1/-22)
openerp/modules/module.py (+9/-7)
openerp/release.py (+2/-2)
openerp/service/db.py (+1/-6)
openerp/service/server.py (+2/-3)
openerp/tools/__init__.py (+1/-0)
openerp/tools/appdirs.py (+477/-0)
openerp/tools/config.py (+29/-4)
openerp/tools/translate.py (+10/-27)
To merge this branch: bzr merge lp:~openerp-dev/openobject-server/trunk-trunk-datadir-chs
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+202059@code.launchpad.net
To post a comment you must log in.
5046. By Christophe Simonis (OpenERP)

[FIX] attachments: filestore use dbname instead of dbuuid

5047. By Antony Lesuisse (OpenERP)

[MERGE] trunk

5048. By Antony Lesuisse (OpenERP)

[FIX] move appsdirs to tools

5049. By Christophe Simonis (OpenERP)

merge upstream

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openerp/addons/base/ir/ir_attachment.py'
--- openerp/addons/base/ir/ir_attachment.py 2014-01-16 09:17:16 +0000
+++ openerp/addons/base/ir/ir_attachment.py 2014-02-27 16:58:29 +0000
@@ -64,19 +64,37 @@
64 data[attachment.id] = False64 data[attachment.id] = False
65 return data65 return data
6666
67 def _storage(self, cr, uid, context=None):
68 return self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'ir_attachment.location', 'file')
69
70 @tools.ormcache()
71 def _filestore(self, cr, uid, context=None):
72 return os.path.join(tools.config['data_dir'], 'filestore', cr.dbname)
73
67 # 'data' field implementation74 # 'data' field implementation
68 def _full_path(self, cr, uid, location, path):75 def _full_path(self, cr, uid, location, path):
69 # location = 'file:filestore'76 # sanitize ath
70 assert location.startswith('file:'), "Unhandled filestore location %s" % location77 path = re.sub('[.]', '', path)
71 location = location[5:]
72
73 # sanitize location name and path
74 location = re.sub('[.]','',location)
75 location = location.strip('/\\')
76
77 path = re.sub('[.]','',path)
78 path = path.strip('/\\')78 path = path.strip('/\\')
79 return os.path.join(tools.config['root_path'], location, cr.dbname, path)79 return os.path.join(self._filestore(cr, uid), path)
80
81 def _get_path(self, cr, uid, location, bin_data):
82 sha = hashlib.sha1(bin_data).hexdigest()
83
84 # retro compatibility
85 fname = sha[:3] + '/' + sha
86 full_path = self._full_path(cr, uid, location, fname)
87 if os.path.isfile(full_path):
88 return fname, full_path # keep existing path
89
90 # scatter files across 256 dirs
91 # we use '/' in the db (even on windows)
92 fname = sha[:2] + '/' + sha
93 full_path = self._full_path(cr, uid, location, fname)
94 dirname = os.path.dirname(full_path)
95 if not os.path.isdir(dirname):
96 os.makedirs(dirname)
97 return fname, full_path
8098
81 def _file_read(self, cr, uid, location, fname, bin_size=False):99 def _file_read(self, cr, uid, location, fname, bin_size=False):
82 full_path = self._full_path(cr, uid, location, fname)100 full_path = self._full_path(cr, uid, location, fname)
@@ -92,18 +110,13 @@
92110
93 def _file_write(self, cr, uid, location, value):111 def _file_write(self, cr, uid, location, value):
94 bin_value = value.decode('base64')112 bin_value = value.decode('base64')
95 fname = hashlib.sha1(bin_value).hexdigest()113 fname, full_path = self._get_path(cr, uid, location, bin_value)
96 # scatter files across 1024 dirs114 if not os.path.exists(full_path):
97 # we use '/' in the db (even on windows)115 try:
98 fname = fname[:3] + '/' + fname116 with open(full_path, 'wb') as fp:
99 full_path = self._full_path(cr, uid, location, fname)117 fp.write(bin_value)
100 try:118 except IOError:
101 dirname = os.path.dirname(full_path)119 _logger.error("_file_write writing %s", full_path)
102 if not os.path.isdir(dirname):
103 os.makedirs(dirname)
104 open(full_path,'wb').write(bin_value)
105 except IOError:
106 _logger.error("_file_write writing %s",full_path)
107 return fname120 return fname
108121
109 def _file_delete(self, cr, uid, location, fname):122 def _file_delete(self, cr, uid, location, fname):
@@ -122,10 +135,10 @@
122 if context is None:135 if context is None:
123 context = {}136 context = {}
124 result = {}137 result = {}
125 location = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ir_attachment.location')138 location = self._storage(cr, uid, context)
126 bin_size = context.get('bin_size')139 bin_size = context.get('bin_size')
127 for attach in self.browse(cr, uid, ids, context=context):140 for attach in self.browse(cr, uid, ids, context=context):
128 if location and attach.store_fname:141 if location != 'db' and attach.store_fname:
129 result[attach.id] = self._file_read(cr, uid, location, attach.store_fname, bin_size)142 result[attach.id] = self._file_read(cr, uid, location, attach.store_fname, bin_size)
130 else:143 else:
131 result[attach.id] = attach.db_datas144 result[attach.id] = attach.db_datas
@@ -137,9 +150,9 @@
137 return True150 return True
138 if context is None:151 if context is None:
139 context = {}152 context = {}
140 location = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ir_attachment.location')153 location = self._storage(cr, uid, context)
141 file_size = len(value.decode('base64'))154 file_size = len(value.decode('base64'))
142 if location:155 if location != 'db':
143 attach = self.browse(cr, uid, id, context=context)156 attach = self.browse(cr, uid, id, context=context)
144 if attach.store_fname:157 if attach.store_fname:
145 self._file_delete(cr, uid, location, attach.store_fname)158 self._file_delete(cr, uid, location, attach.store_fname)
@@ -285,8 +298,8 @@
285 if isinstance(ids, (int, long)):298 if isinstance(ids, (int, long)):
286 ids = [ids]299 ids = [ids]
287 self.check(cr, uid, ids, 'unlink', context=context)300 self.check(cr, uid, ids, 'unlink', context=context)
288 location = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ir_attachment.location')301 location = self._storage(cr, uid, context)
289 if location:302 if location != 'db':
290 for attach in self.browse(cr, uid, ids, context=context):303 for attach in self.browse(cr, uid, ids, context=context):
291 if attach.store_fname:304 if attach.store_fname:
292 self._file_delete(cr, uid, location, attach.store_fname)305 self._file_delete(cr, uid, location, attach.store_fname)
@@ -303,4 +316,3 @@
303 cr, uid, 'base', 'action_attachment', context=context)316 cr, uid, 'base', 'action_attachment', context=context)
304317
305# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:318# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
306
307319
=== modified file 'openerp/addons/base/module/wizard/base_module_import.py'
--- openerp/addons/base/module/wizard/base_module_import.py 2013-10-18 15:48:05 +0000
+++ openerp/addons/base/module/wizard/base_module_import.py 2014-02-27 16:58:29 +0000
@@ -28,8 +28,6 @@
28from openerp.osv import osv, fields28from openerp.osv import osv, fields
29from openerp.tools.translate import _29from openerp.tools.translate import _
3030
31ADDONS_PATH = tools.config['addons_path'].split(",")[-1]
32
33class base_module_import(osv.osv_memory):31class base_module_import(osv.osv_memory):
34 """ Import Module """32 """ Import Module """
3533
3634
=== modified file 'openerp/addons/base/tests/test_ir_attachment.py'
--- openerp/addons/base/tests/test_ir_attachment.py 2012-12-16 19:03:17 +0000
+++ openerp/addons/base/tests/test_ir_attachment.py 2014-02-27 16:58:29 +0000
@@ -1,89 +1,92 @@
1import hashlib1import hashlib
2import os2import os
33
4import unittest2
5
6import openerp4import openerp
7import openerp.tests.common5import openerp.tests.common
86
7HASH_SPLIT = 2 # FIXME: testing implementations detail is not a good idea
8
9class test_ir_attachment(openerp.tests.common.TransactionCase):9class test_ir_attachment(openerp.tests.common.TransactionCase):
1010 def setUp(self):
11 def test_00_attachment_flow(self):11 super(test_ir_attachment, self).setUp()
12 registry, cr, uid = self.registry, self.cr, self.uid12 registry, cr, uid = self.registry, self.cr, self.uid
13 root_path = openerp.tools.config['root_path']13 self.ira = registry('ir.attachment')
14 ira = registry('ir.attachment')14 self.filestore = self.ira._filestore(cr, uid)
1515
16 # Blob116 # Blob1
17 blob1 = 'blob1'17 self.blob1 = 'blob1'
18 blob1_b64 = blob1.encode('base64')18 self.blob1_b64 = self.blob1.encode('base64')
19 blob1_hash = hashlib.sha1(blob1).hexdigest()19 blob1_hash = hashlib.sha1(self.blob1).hexdigest()
20 blob1_fname = blob1_hash[:3] + '/' + blob1_hash20 self.blob1_fname = blob1_hash[:HASH_SPLIT] + '/' + blob1_hash
2121
22 # Blob222 # Blob2
23 blob2 = 'blob2'23 blob2 = 'blob2'
24 blob2_b64 = blob2.encode('base64')24 self.blob2_b64 = blob2.encode('base64')
25 blob2_hash = hashlib.sha1(blob2).hexdigest()25
26 blob2_fname = blob2_hash[:3] + '/' + blob2_hash26 def test_01_store_in_db(self):
27 registry, cr, uid = self.registry, self.cr, self.uid
28
29 # force storing in database
30 registry('ir.config_parameter').set_param(cr, uid, 'ir_attachment.location', 'db')
2731
28 # 'ir_attachment.location' is undefined test database storage32 # 'ir_attachment.location' is undefined test database storage
29 a1 = ira.create(cr, uid, {'name': 'a1', 'datas': blob1_b64})33 a1 = self.ira.create(cr, uid, {'name': 'a1', 'datas': self.blob1_b64})
30 a1_read = ira.read(cr, uid, [a1], ['datas'])34 a1_read = self.ira.read(cr, uid, [a1], ['datas'])
31 self.assertEqual(a1_read[0]['datas'], blob1_b64)35 self.assertEqual(a1_read[0]['datas'], self.blob1_b64)
3236
33 cr.execute("select id,db_datas from ir_attachment where id = %s", (a1,) )37 a1_db_datas = self.ira.browse(cr, uid, a1).db_datas
34 a1_db_datas = str(cr.fetchall()[0][1])38 self.assertEqual(a1_db_datas, self.blob1_b64)
35 self.assertEqual(a1_db_datas, blob1_b64)39
3640 def test_02_store_on_disk(self):
37 # define a location for filestore41 registry, cr, uid = self.registry, self.cr, self.uid
38 registry('ir.config_parameter').set_param(cr, uid, 'ir_attachment.location', 'file:///filestore')42
3943 a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
40 # Test file storage44 a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
41 a2 = ira.create(cr, uid, {'name': 'a2', 'datas': blob1_b64})45
42 a2_read = ira.read(cr, uid, [a2], ['datas'])46 self.assertEqual(a2_store_fname, self.blob1_fname)
43 self.assertEqual(a2_read[0]['datas'], blob1_b64)47 self.assertTrue(os.path.isfile(os.path.join(self.filestore, a2_store_fname)))
4448
45 cr.execute("select id,store_fname from ir_attachment where id = %s", (a2,) )49 def test_03_no_duplication(self):
46 a2_store_fname = cr.fetchall()[0][1]50 registry, cr, uid = self.registry, self.cr, self.uid
47 self.assertEqual(a2_store_fname, blob1_fname)51
4852 a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
49 a2_fn = os.path.join(root_path, 'filestore', cr.dbname, blob1_hash[:3], blob1_hash)53 a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
50 fc = file(a2_fn).read()54
51 self.assertEqual(fc, blob1)55 a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64})
5256 a3_store_fname = self.ira.browse(cr, uid, a3).store_fname
53 # create a3 with same blob57
54 a3 = ira.create(cr, uid, {'name': 'a3', 'datas': blob1_b64})
55 a3_read = ira.read(cr, uid, [a3], ['datas'])
56 self.assertEqual(a3_read[0]['datas'], blob1_b64)
57
58 cr.execute("select id,store_fname from ir_attachment where id = %s", (a3,) )
59 a3_store_fname = cr.fetchall()[0][1]
60 self.assertEqual(a3_store_fname, a2_store_fname)58 self.assertEqual(a3_store_fname, a2_store_fname)
6159
62 # create a4 blob260 def test_04_keep_file(self):
63 a4 = ira.create(cr, uid, {'name': 'a4', 'datas': blob2_b64})61 registry, cr, uid = self.registry, self.cr, self.uid
64 a4_read = ira.read(cr, uid, [a4], ['datas'])62
65 self.assertEqual(a4_read[0]['datas'], blob2_b64)63 a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
6664 a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64})
67 a4_fn = os.path.join(root_path, 'filestore', cr.dbname, blob2_hash[:3], blob2_hash)65
68 self.assertTrue(os.path.isfile(a4_fn))66 a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
6967 a2_fn = os.path.join(self.filestore, a2_store_fname)
70 # delete a3 but file stays68
71 ira.unlink(cr, uid, [a3])69 self.ira.unlink(cr, uid, [a3])
72 self.assertTrue(os.path.isfile(a2_fn))70 self.assertTrue(os.path.isfile(a2_fn))
7371
74 # delete a2 it is unlinked72 # delete a2 it is unlinked
75 ira.unlink(cr, uid, [a2])73 self.ira.unlink(cr, uid, [a2])
76 self.assertFalse(os.path.isfile(a2_fn))74 self.assertFalse(os.path.isfile(a2_fn))
7775
78 # update a4 blob2 by blob176 def test_05_change_data_change_file(self):
79 ira.write(cr, uid, [a4], {'datas': blob1_b64})77 registry, cr, uid = self.registry, self.cr, self.uid
80 a4_read = ira.read(cr, uid, [a4], ['datas'])78
81 self.assertEqual(a4_read[0]['datas'], blob1_b64)79 a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
8280 a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
83 # file of a4 disapear and a2 reappear81 a2_fn = os.path.join(self.filestore, a2_store_fname)
84 self.assertFalse(os.path.isfile(a4_fn))82
85 self.assertTrue(os.path.isfile(a2_fn))83 self.assertTrue(os.path.isfile(a2_fn))
8684
87 # everybody applause85 self.ira.write(cr, uid, [a2], {'datas': self.blob2_b64})
8886 self.assertFalse(os.path.isfile(a2_fn))
8987
88 new_a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
89 self.assertNotEqual(a2_store_fname, new_a2_store_fname)
90
91 new_a2_fn = os.path.join(self.filestore, new_a2_store_fname)
92 self.assertTrue(os.path.isfile(new_a2_fn))
9093
=== modified file 'openerp/cli/server.py'
--- openerp/cli/server.py 2014-02-09 01:46:36 +0000
+++ openerp/cli/server.py 2014-02-27 16:58:29 +0000
@@ -72,7 +72,7 @@
72 """72 """
73 config = openerp.tools.config73 config = openerp.tools.config
74 _logger.info("OpenERP version %s", __version__)74 _logger.info("OpenERP version %s", __version__)
75 for name, value in [('addons paths', config['addons_path']),75 for name, value in [('addons paths', openerp.modules.module.ad_paths),
76 ('database hostname', config['db_host'] or 'localhost'),76 ('database hostname', config['db_host'] or 'localhost'),
77 ('database port', config['db_port'] or '5432'),77 ('database port', config['db_port'] or '5432'),
78 ('database user', config['db_user'])]:78 ('database user', config['db_user'])]:
7979
=== modified file 'openerp/http.py'
--- openerp/http.py 2014-02-26 16:16:27 +0000
+++ openerp/http.py 2014-02-27 16:58:29 +0000
@@ -995,33 +995,12 @@
995 start_response(status, new_headers)995 start_response(status, new_headers)
996 return self.app(environ, start_wrapped)996 return self.app(environ, start_wrapped)
997997
998def session_path():
999 try:
1000 import pwd
1001 username = pwd.getpwuid(os.geteuid()).pw_name
1002 except ImportError:
1003 try:
1004 username = getpass.getuser()
1005 except Exception:
1006 username = "unknown"
1007 path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
1008 try:
1009 os.mkdir(path, 0700)
1010 except OSError as exc:
1011 if exc.errno == errno.EEXIST:
1012 # directory exists: ensure it has the correct permissions
1013 # this will fail if the directory is not owned by the current user
1014 os.chmod(path, 0700)
1015 else:
1016 raise
1017 return path
1018
1019class Root(object):998class Root(object):
1020 """Root WSGI application for the OpenERP Web Client.999 """Root WSGI application for the OpenERP Web Client.
1021 """1000 """
1022 def __init__(self):1001 def __init__(self):
1023 # Setup http sessions1002 # Setup http sessions
1024 path = session_path()1003 path = openerp.tools.config.session_dir
1025 _logger.debug('HTTP sessions stored in: %s', path)1004 _logger.debug('HTTP sessions stored in: %s', path)
1026 self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)1005 self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
10271006
10281007
=== modified file 'openerp/modules/module.py'
--- openerp/modules/module.py 2014-02-18 10:18:47 +0000
+++ openerp/modules/module.py 2014-02-27 16:58:29 +0000
@@ -3,7 +3,7 @@
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).6# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
7#7#
8# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -40,9 +40,6 @@
40_logger = logging.getLogger(__name__)40_logger = logging.getLogger(__name__)
41_test_logger = logging.getLogger('openerp.tests')41_test_logger = logging.getLogger('openerp.tests')
4242
43# addons path ','.joined
44_ad = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'addons') # default addons path (base)
45
46# addons path as a list43# addons path as a list
47ad_paths = []44ad_paths = []
4845
@@ -90,8 +87,13 @@
90 if ad_paths:87 if ad_paths:
91 return88 return
9289
93 ad_paths = map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))90 ad_paths = [tools.config.addons_data_dir]
94 ad_paths.append(os.path.abspath(_ad)) # for get_module_path91 ad_paths += map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))
92
93 # add base module path
94 base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'addons'))
95 ad_paths += [base_path]
96
95 sys.meta_path.append(AddonsImportHook())97 sys.meta_path.append(AddonsImportHook())
9698
97def get_module_path(module, downloaded=False, display_warning=True):99def get_module_path(module, downloaded=False, display_warning=True):
@@ -108,7 +110,7 @@
108 return opj(adp, module)110 return opj(adp, module)
109111
110 if downloaded:112 if downloaded:
111 return opj(_ad, module)113 return opj(tools.config.addons_data_dir, module)
112 if display_warning:114 if display_warning:
113 _logger.warning('module %s: module not found', module)115 _logger.warning('module %s: module not found', module)
114 return False116 return False
115117
=== modified file 'openerp/release.py'
--- openerp/release.py 2014-02-11 10:53:15 +0000
+++ openerp/release.py 2014-02-27 16:58:29 +0000
@@ -32,7 +32,7 @@
32# (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0)32# (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0)
33version_info = (8, 0, 0, ALPHA, 1)33version_info = (8, 0, 0, ALPHA, 1)
34version = '.'.join(map(str, version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '')34version = '.'.join(map(str, version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '')
35serie = major_version = '.'.join(map(str, version_info[:2]))35series = serie = major_version = '.'.join(map(str, version_info[:2]))
3636
37description = 'OpenERP Server'37description = 'OpenERP Server'
38long_desc = '''OpenERP is a complete ERP and CRM. The main features are accounting (analytic38long_desc = '''OpenERP is a complete ERP and CRM. The main features are accounting (analytic
@@ -50,6 +50,6 @@
50author_email = 'info@openerp.com'50author_email = 'info@openerp.com'
51license = 'AGPL-3'51license = 'AGPL-3'
5252
53nt_service_name = "openerp-server-" + serie53nt_service_name = "openerp-server-" + series
5454
55# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:55# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
5656
=== modified file 'openerp/service/db.py'
--- openerp/service/db.py 2014-02-20 13:27:00 +0000
+++ openerp/service/db.py 2014-02-27 16:58:29 +0000
@@ -276,15 +276,10 @@
276 cr.autocommit(True) # avoid transaction block276 cr.autocommit(True) # avoid transaction block
277 try:277 try:
278 cr.execute('ALTER DATABASE "%s" RENAME TO "%s"' % (old_name, new_name))278 cr.execute('ALTER DATABASE "%s" RENAME TO "%s"' % (old_name, new_name))
279 _logger.info('RENAME DB: %s -> %s', old_name, new_name)
279 except Exception, e:280 except Exception, e:
280 _logger.error('RENAME DB: %s -> %s failed:\n%s', old_name, new_name, e)281 _logger.error('RENAME DB: %s -> %s failed:\n%s', old_name, new_name, e)
281 raise Exception("Couldn't rename database %s to %s: %s" % (old_name, new_name, e))282 raise Exception("Couldn't rename database %s to %s: %s" % (old_name, new_name, e))
282 else:
283 fs = os.path.join(openerp.tools.config['root_path'], 'filestore')
284 if os.path.exists(os.path.join(fs, old_name)):
285 os.rename(os.path.join(fs, old_name), os.path.join(fs, new_name))
286
287 _logger.info('RENAME DB: %s -> %s', old_name, new_name)
288 return True283 return True
289284
290def exp_db_exist(db_name):285def exp_db_exist(db_name):
291286
=== modified file 'openerp/service/server.py'
--- openerp/service/server.py 2014-02-21 23:10:10 +0000
+++ openerp/service/server.py 2014-02-27 16:58:29 +0000
@@ -108,15 +108,14 @@
108 self.handler = EventHandler(self)108 self.handler = EventHandler(self)
109 self.notifier = pyinotify.Notifier(self.wm, self.handler, timeout=0)109 self.notifier = pyinotify.Notifier(self.wm, self.handler, timeout=0)
110 mask = pyinotify.IN_MODIFY | pyinotify.IN_CREATE # IN_MOVED_FROM, IN_MOVED_TO ?110 mask = pyinotify.IN_MODIFY | pyinotify.IN_CREATE # IN_MOVED_FROM, IN_MOVED_TO ?
111 for path in openerp.tools.config.options["addons_path"].split(','):111 for path in openerp.modules.modules.ad_paths:
112 _logger.info('Watching addons folder %s', path)112 _logger.info('Watching addons folder %s', path)
113 self.wm.add_watch(path, mask, rec=True)113 self.wm.add_watch(path, mask, rec=True)
114114
115 def process_data(self, files):115 def process_data(self, files):
116 xml_files = [i for i in files if i.endswith('.xml')]116 xml_files = [i for i in files if i.endswith('.xml')]
117 addons_path = openerp.tools.config.options["addons_path"].split(',')
118 for i in xml_files:117 for i in xml_files:
119 for path in addons_path:118 for path in openerp.modules.modules.ad_paths:
120 if i.startswith(path):119 if i.startswith(path):
121 # find out wich addons path the file belongs to120 # find out wich addons path the file belongs to
122 # and extract it's module name121 # and extract it's module name
123122
=== modified file 'openerp/tools/__init__.py'
--- openerp/tools/__init__.py 2013-02-12 14:24:10 +0000
+++ openerp/tools/__init__.py 2014-02-27 16:58:29 +0000
@@ -21,6 +21,7 @@
2121
22import copy22import copy
23import win3223import win32
24import appdirs
24from config import config25from config import config
25from misc import *26from misc import *
26from convert import *27from convert import *
2728
=== added file 'openerp/tools/appdirs.py'
--- openerp/tools/appdirs.py 1970-01-01 00:00:00 +0000
+++ openerp/tools/appdirs.py 2014-02-27 16:58:29 +0000
@@ -0,0 +1,477 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2005-2010 ActiveState Software Inc.
4# Copyright (c) 2013 Eddy Petrișor
5
6"""Utilities for determining application-specific dirs.
7
8See <http://github.com/ActiveState/appdirs> for details and usage.
9"""
10# Dev Notes:
11# - MSDN on where to store app data files:
12# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
13# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
14# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
15
16__version_info__ = (1, 3, 0)
17__version__ = '.'.join(map(str, __version_info__))
18
19
20import sys
21import os
22
23PY3 = sys.version_info[0] == 3
24
25if PY3:
26 unicode = str
27
28
29
30def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
31 r"""Return full path to the user-specific data dir for this application.
32
33 "appname" is the name of application.
34 If None, just the system directory is returned.
35 "appauthor" (only required and used on Windows) is the name of the
36 appauthor or distributing body for this application. Typically
37 it is the owning company name. This falls back to appname.
38 "version" is an optional version path element to append to the
39 path. You might want to use this if you want multiple versions
40 of your app to be able to run independently. If used, this
41 would typically be "<major>.<minor>".
42 Only applied when appname is present.
43 "roaming" (boolean, default False) can be set True to use the Windows
44 roaming appdata directory. That means that for users on a Windows
45 network setup for roaming profiles, this user data will be
46 sync'd on login. See
47 <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
48 for a discussion of issues.
49
50 Typical user data directories are:
51 Mac OS X: ~/Library/Application Support/<AppName>
52 Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
53 Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
54 Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
55 Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
56 Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
57
58 For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
59 That means, by deafult "~/.local/share/<AppName>".
60 """
61 if sys.platform == "win32":
62 if appauthor is None:
63 appauthor = appname
64 const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
65 path = os.path.normpath(_get_win_folder(const))
66 if appname:
67 path = os.path.join(path, appauthor, appname)
68 elif sys.platform == 'darwin':
69 path = os.path.expanduser('~/Library/Application Support/')
70 if appname:
71 path = os.path.join(path, appname)
72 else:
73 path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
74 if appname:
75 path = os.path.join(path, appname)
76 if appname and version:
77 path = os.path.join(path, version)
78 return path
79
80
81def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
82 """Return full path to the user-shared data dir for this application.
83
84 "appname" is the name of application.
85 If None, just the system directory is returned.
86 "appauthor" (only required and used on Windows) is the name of the
87 appauthor or distributing body for this application. Typically
88 it is the owning company name. This falls back to appname.
89 "version" is an optional version path element to append to the
90 path. You might want to use this if you want multiple versions
91 of your app to be able to run independently. If used, this
92 would typically be "<major>.<minor>".
93 Only applied when appname is present.
94 "multipath" is an optional parameter only applicable to *nix
95 which indicates that the entire list of data dirs should be
96 returned. By default, the first item from XDG_DATA_DIRS is
97 returned, or '/usr/local/share/<AppName>',
98 if XDG_DATA_DIRS is not set
99
100 Typical user data directories are:
101 Mac OS X: /Library/Application Support/<AppName>
102 Unix: /usr/local/share/<AppName> or /usr/share/<AppName>
103 Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
104 Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
105 Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7.
106
107 For Unix, this is using the $XDG_DATA_DIRS[0] default.
108
109 WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
110 """
111 if sys.platform == "win32":
112 if appauthor is None:
113 appauthor = appname
114 path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
115 if appname:
116 path = os.path.join(path, appauthor, appname)
117 elif sys.platform == 'darwin':
118 path = os.path.expanduser('/Library/Application Support')
119 if appname:
120 path = os.path.join(path, appname)
121 else:
122 # XDG default for $XDG_DATA_DIRS
123 # only first, if multipath is False
124 path = os.getenv('XDG_DATA_DIRS',
125 os.pathsep.join(['/usr/local/share', '/usr/share']))
126 pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ]
127 if appname:
128 if version:
129 appname = os.path.join(appname, version)
130 pathlist = [ os.sep.join([x, appname]) for x in pathlist ]
131
132 if multipath:
133 path = os.pathsep.join(pathlist)
134 else:
135 path = pathlist[0]
136 return path
137
138 if appname and version:
139 path = os.path.join(path, version)
140 return path
141
142
143def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
144 r"""Return full path to the user-specific config dir for this application.
145
146 "appname" is the name of application.
147 If None, just the system directory is returned.
148 "appauthor" (only required and used on Windows) is the name of the
149 appauthor or distributing body for this application. Typically
150 it is the owning company name. This falls back to appname.
151 "version" is an optional version path element to append to the
152 path. You might want to use this if you want multiple versions
153 of your app to be able to run independently. If used, this
154 would typically be "<major>.<minor>".
155 Only applied when appname is present.
156 "roaming" (boolean, default False) can be set True to use the Windows
157 roaming appdata directory. That means that for users on a Windows
158 network setup for roaming profiles, this user data will be
159 sync'd on login. See
160 <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
161 for a discussion of issues.
162
163 Typical user data directories are:
164 Mac OS X: same as user_data_dir
165 Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined
166 Win *: same as user_data_dir
167
168 For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
169 That means, by deafult "~/.local/share/<AppName>".
170 """
171 if sys.platform in [ "win32", "darwin" ]:
172 path = user_data_dir(appname, appauthor, None, roaming)
173 else:
174 path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
175 if appname:
176 path = os.path.join(path, appname)
177 if appname and version:
178 path = os.path.join(path, version)
179 return path
180
181
182def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
183 """Return full path to the user-shared data dir for this application.
184
185 "appname" is the name of application.
186 If None, just the system directory is returned.
187 "appauthor" (only required and used on Windows) is the name of the
188 appauthor or distributing body for this application. Typically
189 it is the owning company name. This falls back to appname.
190 "version" is an optional version path element to append to the
191 path. You might want to use this if you want multiple versions
192 of your app to be able to run independently. If used, this
193 would typically be "<major>.<minor>".
194 Only applied when appname is present.
195 "multipath" is an optional parameter only applicable to *nix
196 which indicates that the entire list of config dirs should be
197 returned. By default, the first item from XDG_CONFIG_DIRS is
198 returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
199
200 Typical user data directories are:
201 Mac OS X: same as site_data_dir
202 Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
203 $XDG_CONFIG_DIRS
204 Win *: same as site_data_dir
205 Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
206
207 For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
208
209 WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
210 """
211 if sys.platform in [ "win32", "darwin" ]:
212 path = site_data_dir(appname, appauthor)
213 if appname and version:
214 path = os.path.join(path, version)
215 else:
216 # XDG default for $XDG_CONFIG_DIRS
217 # only first, if multipath is False
218 path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
219 pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ]
220 if appname:
221 if version:
222 appname = os.path.join(appname, version)
223 pathlist = [ os.sep.join([x, appname]) for x in pathlist ]
224
225 if multipath:
226 path = os.pathsep.join(pathlist)
227 else:
228 path = pathlist[0]
229 return path
230
231def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
232 r"""Return full path to the user-specific cache dir for this application.
233
234 "appname" is the name of application.
235 If None, just the system directory is returned.
236 "appauthor" (only required and used on Windows) is the name of the
237 appauthor or distributing body for this application. Typically
238 it is the owning company name. This falls back to appname.
239 "version" is an optional version path element to append to the
240 path. You might want to use this if you want multiple versions
241 of your app to be able to run independently. If used, this
242 would typically be "<major>.<minor>".
243 Only applied when appname is present.
244 "opinion" (boolean) can be False to disable the appending of
245 "Cache" to the base app data dir for Windows. See
246 discussion below.
247
248 Typical user cache directories are:
249 Mac OS X: ~/Library/Caches/<AppName>
250 Unix: ~/.cache/<AppName> (XDG default)
251 Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
252 Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
253
254 On Windows the only suggestion in the MSDN docs is that local settings go in
255 the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
256 app data dir (the default returned by `user_data_dir` above). Apps typically
257 put cache data somewhere *under* the given dir here. Some examples:
258 ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
259 ...\Acme\SuperApp\Cache\1.0
260 OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
261 This can be disabled with the `opinion=False` option.
262 """
263 if sys.platform == "win32":
264 if appauthor is None:
265 appauthor = appname
266 path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
267 if appname:
268 path = os.path.join(path, appauthor, appname)
269 if opinion:
270 path = os.path.join(path, "Cache")
271 elif sys.platform == 'darwin':
272 path = os.path.expanduser('~/Library/Caches')
273 if appname:
274 path = os.path.join(path, appname)
275 else:
276 path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
277 if appname:
278 path = os.path.join(path, appname)
279 if appname and version:
280 path = os.path.join(path, version)
281 return path
282
283def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
284 r"""Return full path to the user-specific log dir for this application.
285
286 "appname" is the name of application.
287 If None, just the system directory is returned.
288 "appauthor" (only required and used on Windows) is the name of the
289 appauthor or distributing body for this application. Typically
290 it is the owning company name. This falls back to appname.
291 "version" is an optional version path element to append to the
292 path. You might want to use this if you want multiple versions
293 of your app to be able to run independently. If used, this
294 would typically be "<major>.<minor>".
295 Only applied when appname is present.
296 "opinion" (boolean) can be False to disable the appending of
297 "Logs" to the base app data dir for Windows, and "log" to the
298 base cache dir for Unix. See discussion below.
299
300 Typical user cache directories are:
301 Mac OS X: ~/Library/Logs/<AppName>
302 Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined
303 Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
304 Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
305
306 On Windows the only suggestion in the MSDN docs is that local settings
307 go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
308 examples of what some windows apps use for a logs dir.)
309
310 OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
311 value for Windows and appends "log" to the user cache dir for Unix.
312 This can be disabled with the `opinion=False` option.
313 """
314 if sys.platform == "darwin":
315 path = os.path.join(
316 os.path.expanduser('~/Library/Logs'),
317 appname)
318 elif sys.platform == "win32":
319 path = user_data_dir(appname, appauthor, version); version=False
320 if opinion:
321 path = os.path.join(path, "Logs")
322 else:
323 path = user_cache_dir(appname, appauthor, version); version=False
324 if opinion:
325 path = os.path.join(path, "log")
326 if appname and version:
327 path = os.path.join(path, version)
328 return path
329
330
331class AppDirs(object):
332 """Convenience wrapper for getting application dirs."""
333 def __init__(self, appname, appauthor=None, version=None,
334 roaming=False, multipath=False):
335 self.appname = appname
336 self.appauthor = appauthor
337 self.version = version
338 self.roaming = roaming
339 self.multipath = multipath
340 @property
341 def user_data_dir(self):
342 return user_data_dir(self.appname, self.appauthor,
343 version=self.version, roaming=self.roaming)
344 @property
345 def site_data_dir(self):
346 return site_data_dir(self.appname, self.appauthor,
347 version=self.version, multipath=self.multipath)
348 @property
349 def user_config_dir(self):
350 return user_config_dir(self.appname, self.appauthor,
351 version=self.version, roaming=self.roaming)
352 @property
353 def site_config_dir(self):
354 return site_data_dir(self.appname, self.appauthor,
355 version=self.version, multipath=self.multipath)
356 @property
357 def user_cache_dir(self):
358 return user_cache_dir(self.appname, self.appauthor,
359 version=self.version)
360 @property
361 def user_log_dir(self):
362 return user_log_dir(self.appname, self.appauthor,
363 version=self.version)
364
365
366
367
368#---- internal support stuff
369
370def _get_win_folder_from_registry(csidl_name):
371 """This is a fallback technique at best. I'm not sure if using the
372 registry for this guarantees us the correct answer for all CSIDL_*
373 names.
374 """
375 import _winreg
376
377 shell_folder_name = {
378 "CSIDL_APPDATA": "AppData",
379 "CSIDL_COMMON_APPDATA": "Common AppData",
380 "CSIDL_LOCAL_APPDATA": "Local AppData",
381 }[csidl_name]
382
383 key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
384 r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
385 dir, type = _winreg.QueryValueEx(key, shell_folder_name)
386 return dir
387
388def _get_win_folder_with_pywin32(csidl_name):
389 from win32com.shell import shellcon, shell
390 dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
391 # Try to make this a unicode path because SHGetFolderPath does
392 # not return unicode strings when there is unicode data in the
393 # path.
394 try:
395 dir = unicode(dir)
396
397 # Downgrade to short path name if have highbit chars. See
398 # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
399 has_high_char = False
400 for c in dir:
401 if ord(c) > 255:
402 has_high_char = True
403 break
404 if has_high_char:
405 try:
406 import win32api
407 dir = win32api.GetShortPathName(dir)
408 except ImportError:
409 pass
410 except UnicodeError:
411 pass
412 return dir
413
414def _get_win_folder_with_ctypes(csidl_name):
415 import ctypes
416
417 csidl_const = {
418 "CSIDL_APPDATA": 26,
419 "CSIDL_COMMON_APPDATA": 35,
420 "CSIDL_LOCAL_APPDATA": 28,
421 }[csidl_name]
422
423 buf = ctypes.create_unicode_buffer(1024)
424 ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
425
426 # Downgrade to short path name if have highbit chars. See
427 # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
428 has_high_char = False
429 for c in buf:
430 if ord(c) > 255:
431 has_high_char = True
432 break
433 if has_high_char:
434 buf2 = ctypes.create_unicode_buffer(1024)
435 if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
436 buf = buf2
437
438 return buf.value
439
440if sys.platform == "win32":
441 try:
442 import win32com.shell
443 _get_win_folder = _get_win_folder_with_pywin32
444 except ImportError:
445 try:
446 import ctypes
447 _get_win_folder = _get_win_folder_with_ctypes
448 except ImportError:
449 _get_win_folder = _get_win_folder_from_registry
450
451
452
453#---- self test code
454
455if __name__ == "__main__":
456 appname = "MyApp"
457 appauthor = "MyCompany"
458
459 props = ("user_data_dir", "site_data_dir",
460 "user_config_dir", "site_config_dir",
461 "user_cache_dir", "user_log_dir")
462
463 print("-- app dirs (with optional 'version')")
464 dirs = AppDirs(appname, appauthor, version="1.0")
465 for prop in props:
466 print("%s: %s" % (prop, getattr(dirs, prop)))
467
468 print("\n-- app dirs (without optional 'version')")
469 dirs = AppDirs(appname, appauthor)
470 for prop in props:
471 print("%s: %s" % (prop, getattr(dirs, prop)))
472
473 print("\n-- app dirs (without optional 'appauthor')")
474 dirs = AppDirs(appname)
475 for prop in props:
476 print("%s: %s" % (prop, getattr(dirs, prop)))
477
0478
=== modified file 'openerp/tools/config.py'
--- openerp/tools/config.py 2014-02-12 22:52:40 +0000
+++ openerp/tools/config.py 2014-02-27 16:58:29 +0000
@@ -3,7 +3,7 @@
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).6# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
7#7#
8# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -29,6 +29,7 @@
29import openerp.loglevels as loglevels29import openerp.loglevels as loglevels
30import logging30import logging
31import openerp.release as release31import openerp.release as release
32import appdirs
3233
33class MyOption (optparse.Option, object):34class MyOption (optparse.Option, object):
34 """ optparse Option with two additional attributes.35 """ optparse Option with two additional attributes.
@@ -59,6 +60,9 @@
5960
60DEFAULT_LOG_HANDLER = [':INFO']61DEFAULT_LOG_HANDLER = [':INFO']
6162
63def _get_default_datadir():
64 return appdirs.user_data_dir(appname='OpenERP', appauthor=release.author)
65
62class configmanager(object):66class configmanager(object):
63 def __init__(self, fname=None):67 def __init__(self, fname=None):
64 # Options not exposed on the command line. Command line options will be added68 # Options not exposed on the command line. Command line options will be added
@@ -106,6 +110,9 @@
106 help="specify additional addons paths (separated by commas).",110 help="specify additional addons paths (separated by commas).",
107 action="callback", callback=self._check_addons_path, nargs=1, type="string")111 action="callback", callback=self._check_addons_path, nargs=1, type="string")
108 group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules default=web")112 group.add_option("--load", dest="server_wide_modules", help="Comma-separated list of server-wide modules default=web")
113
114 group.add_option("-D", "--data-dir", dest="data_dir", my_default=_get_default_datadir(),
115 help="Directory where to store OpenERP data")
109 parser.add_option_group(group)116 parser.add_option_group(group)
110117
111 # XML-RPC / HTTP118 # XML-RPC / HTTP
@@ -348,6 +355,7 @@
348 # (../etc from the server)355 # (../etc from the server)
349 # if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,356 # if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,
350 # else he won't be able to save the configurations, or even to start the server...357 # else he won't be able to save the configurations, or even to start the server...
358 # TODO use appdirs
351 if os.name == 'nt':359 if os.name == 'nt':
352 rcfilepath = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'openerp-server.conf')360 rcfilepath = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'openerp-server.conf')
353 else:361 else:
@@ -358,7 +366,6 @@
358 or os.environ.get('OPENERP_SERVER') or rcfilepath)366 or os.environ.get('OPENERP_SERVER') or rcfilepath)
359 self.load()367 self.load()
360368
361
362 # Verify that we want to log or not, if not the output will go to stdout369 # Verify that we want to log or not, if not the output will go to stdout
363 if self.options['logfile'] in ('None', 'False'):370 if self.options['logfile'] in ('None', 'False'):
364 self.options['logfile'] = False371 self.options['logfile'] = False
@@ -387,7 +394,6 @@
387 elif isinstance(self.options[arg], basestring) and self.casts[arg].type in optparse.Option.TYPE_CHECKER:394 elif isinstance(self.options[arg], basestring) and self.casts[arg].type in optparse.Option.TYPE_CHECKER:
388 self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg])395 self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg])
389396
390
391 if isinstance(self.options['log_handler'], basestring):397 if isinstance(self.options['log_handler'], basestring):
392 self.options['log_handler'] = self.options['log_handler'].split(',')398 self.options['log_handler'] = self.options['log_handler'].split(',')
393399
@@ -399,7 +405,8 @@
399 'list_db', 'xmlrpcs', 'proxy_mode',405 'list_db', 'xmlrpcs', 'proxy_mode',
400 'test_file', 'test_enable', 'test_commit', 'test_report_directory',406 'test_file', 'test_enable', 'test_commit', 'test_report_directory',
401 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'unaccent',407 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'unaccent',
402 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request', 'auto_reload'408 'workers', 'limit_memory_hard', 'limit_memory_soft', 'limit_time_cpu', 'limit_time_real', 'limit_request',
409 'auto_reload', 'data_dir',
403 ]410 ]
404411
405 for arg in keys:412 for arg in keys:
@@ -617,6 +624,24 @@
617 def __getitem__(self, key):624 def __getitem__(self, key):
618 return self.options[key]625 return self.options[key]
619626
627 @property
628 def addons_data_dir(self):
629 d = os.path.join(self['data_dir'], 'addons', release.series)
630 if not os.path.exists(d):
631 os.makedirs(d, 0700)
632 else:
633 os.chmod(d, 0700)
634 return d
635
636 @property
637 def session_dir(self):
638 d = os.path.join(self['data_dir'], 'sessions', release.series)
639 if not os.path.exists(d):
640 os.makedirs(d, 0700)
641 else:
642 os.chmod(d, 0700)
643 return d
644
620config = configmanager()645config = configmanager()
621646
622647
623648
=== modified file 'openerp/tools/translate.py'
--- openerp/tools/translate.py 2014-02-06 11:02:20 +0000
+++ openerp/tools/translate.py 2014-02-27 16:58:29 +0000
@@ -778,49 +778,32 @@
778 if model_obj._sql_constraints:778 if model_obj._sql_constraints:
779 push_local_constraints(module, model_obj, 'sql_constraints')779 push_local_constraints(module, model_obj, 'sql_constraints')
780780
781 def get_module_from_path(path, mod_paths=None):
782 if not mod_paths:
783 # First, construct a list of possible paths
784 def_path = os.path.abspath(os.path.join(config.config['root_path'], 'addons')) # default addons path (base)
785 ad_paths= map(lambda m: os.path.abspath(m.strip()),config.config['addons_path'].split(','))
786 mod_paths=[def_path]
787 for adp in ad_paths:
788 mod_paths.append(adp)
789 if not os.path.isabs(adp):
790 mod_paths.append(adp)
791 elif adp.startswith(def_path):
792 mod_paths.append(adp[len(def_path)+1:])
793 for mp in mod_paths:
794 if path.startswith(mp) and (os.path.dirname(path) != mp):
795 path = path[len(mp)+1:]
796 return path.split(os.path.sep)[0]
797 return 'base' # files that are not in a module are considered as being in 'base' module
798781
799 modobj = registry['ir.module.module']782 modobj = registry['ir.module.module']
800 installed_modids = modobj.search(cr, uid, [('state', '=', 'installed')])783 installed_modids = modobj.search(cr, uid, [('state', '=', 'installed')])
801 installed_modules = map(lambda m: m['name'], modobj.read(cr, uid, installed_modids, ['name']))784 installed_modules = map(lambda m: m['name'], modobj.read(cr, uid, installed_modids, ['name']))
802785
803 root_path = os.path.join(config.config['root_path'], 'addons')786 path_list = list(openerp.modules.module.ad_paths)
804
805 apaths = map(os.path.abspath, map(str.strip, config.config['addons_path'].split(',')))
806 if root_path in apaths:
807 path_list = apaths
808 else :
809 path_list = [root_path,] + apaths
810
811 # Also scan these non-addon paths787 # Also scan these non-addon paths
812 for bin_path in ['osv', 'report' ]:788 for bin_path in ['osv', 'report' ]:
813 path_list.append(os.path.join(config.config['root_path'], bin_path))789 path_list.append(os.path.join(config.config['root_path'], bin_path))
814790
815 _logger.debug("Scanning modules at paths: ", path_list)791 _logger.debug("Scanning modules at paths: ", path_list)
816792
817 mod_paths = []793 mod_paths = list(path_list)
794
795 def get_module_from_path(path):
796 for mp in mod_paths:
797 if path.startswith(mp) and (os.path.dirname(path) != mp):
798 path = path[len(mp)+1:]
799 return path.split(os.path.sep)[0]
800 return 'base' # files that are not in a module are considered as being in 'base' module
818801
819 def verified_module_filepaths(fname, path, root):802 def verified_module_filepaths(fname, path, root):
820 fabsolutepath = join(root, fname)803 fabsolutepath = join(root, fname)
821 frelativepath = fabsolutepath[len(path):]804 frelativepath = fabsolutepath[len(path):]
822 display_path = "addons%s" % frelativepath805 display_path = "addons%s" % frelativepath
823 module = get_module_from_path(fabsolutepath, mod_paths=mod_paths)806 module = get_module_from_path(fabsolutepath)
824 if ('all' in modules or module in modules) and module in installed_modules:807 if ('all' in modules or module in modules) and module in installed_modules:
825 return module, fabsolutepath, frelativepath, display_path808 return module, fabsolutepath, frelativepath, display_path
826 return None, None, None, None809 return None, None, None, None