[MERGE] forward port branch saas-14 up to cded89b531
This commit is contained in:
@@ -1,13 +1,27 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import fields, models
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class IrLogging(models.Model):
|
||||
_name = 'ir.logging'
|
||||
_order = 'id DESC'
|
||||
|
||||
create_date = fields.Datetime(readonly=True)
|
||||
create_uid = fields.Integer(string='Uid', readonly=True) # Integer not m2o is intentionnal
|
||||
# The _log_access fields are defined manually for the following reasons:
|
||||
#
|
||||
# - The entries in ir_logging are filled in with sql queries bypassing the orm. As the --log-db
|
||||
# cli option allows to insert ir_logging entries into a remote database, the one2many *_uid
|
||||
# fields make no sense in the first place but we will keep it for backward compatibility.
|
||||
#
|
||||
# - Also, when an ir_logging entry is triggered by the orm (when using --log-db) at the moment
|
||||
# it is making changes to the res.users model, the ALTER TABLE will aquire an exclusive lock
|
||||
# on res_users, preventing the ir_logging INSERT to be processed, hence the ongoing module
|
||||
# install/update will hang forever as the orm is blocked by the ir_logging query that will
|
||||
# never occur.
|
||||
create_uid = fields.Integer(string='Created by', readonly=True)
|
||||
create_date = fields.Datetime(string='Created on', readonly=True)
|
||||
write_uid = fields.Integer(string='Last Updated by', readonly=True)
|
||||
write_date = fields.Datetime(string='Last Updated on', readonly=True)
|
||||
|
||||
name = fields.Char(required=True)
|
||||
type = fields.Selection([('client', 'Client'), ('server', 'Server')], required=True, index=True)
|
||||
dbname = fields.Char(string='Database Name', index=True)
|
||||
@@ -16,3 +30,8 @@ class IrLogging(models.Model):
|
||||
path = fields.Char(required=True)
|
||||
func = fields.Char(string='Function', required=True)
|
||||
line = fields.Char(required=True)
|
||||
|
||||
@api.model_cr
|
||||
def init(self):
|
||||
super(IrLogging, self).init()
|
||||
self._cr.execute("ALTER TABLE ir_logging DROP CONSTRAINT IF EXISTS ir_logging_write_uid_fkey")
|
||||
|
||||
+94
-27
@@ -25,9 +25,25 @@ if os.name == 'posix':
|
||||
import fcntl
|
||||
import resource
|
||||
import psutil
|
||||
try:
|
||||
import inotify
|
||||
from inotify.adapters import InotifyTrees
|
||||
from inotify.constants import IN_MODIFY, IN_CREATE, IN_MOVED_TO
|
||||
INOTIFY_LISTEN_EVENTS = IN_MODIFY | IN_CREATE | IN_MOVED_TO
|
||||
except ImportError:
|
||||
inotify = None
|
||||
else:
|
||||
# Windows shim
|
||||
signal.SIGHUP = -1
|
||||
inotify = None
|
||||
|
||||
if not inotify:
|
||||
try:
|
||||
import watchdog
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileCreatedEvent, FileModifiedEvent, FileMovedEvent
|
||||
except ImportError:
|
||||
watchdog = None
|
||||
|
||||
# Optional process names for workers
|
||||
try:
|
||||
@@ -44,13 +60,6 @@ from odoo.tools import stripped_sys_argv, dumpstacks, log_ormcache_stats
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import watchdog
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileCreatedEvent, FileModifiedEvent, FileMovedEvent
|
||||
except ImportError:
|
||||
watchdog = None
|
||||
|
||||
SLEEP_INTERVAL = 60 # 1 min
|
||||
|
||||
def memory_info(process):
|
||||
@@ -120,7 +129,25 @@ class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving.
|
||||
#----------------------------------------------------------
|
||||
# FileSystem Watcher for autoreload and cache invalidation
|
||||
#----------------------------------------------------------
|
||||
class FSWatcher(object):
|
||||
class FSWatcherBase(object):
|
||||
def handle_file(self, path):
|
||||
if path.endswith('.py') and not os.path.basename(path).startswith('.~'):
|
||||
try:
|
||||
# Forward-ports: watch out PY3 compatibility!
|
||||
source = open(path, 'rb').read() + '\n'
|
||||
compile(source, path, 'exec')
|
||||
except IOError:
|
||||
_logger.error('autoreload: python code change detected, IOError for %s', path)
|
||||
except SyntaxError:
|
||||
_logger.error('autoreload: python code change detected, SyntaxError in %s', path)
|
||||
else:
|
||||
if not getattr(odoo, 'phoenix', False):
|
||||
_logger.info('autoreload: python code updated, autoreload activated')
|
||||
restart()
|
||||
return True
|
||||
|
||||
|
||||
class FSWatcherWatchdog(FSWatcherBase):
|
||||
def __init__(self):
|
||||
self.observer = Observer()
|
||||
for path in odoo.modules.module.ad_paths:
|
||||
@@ -131,27 +158,60 @@ class FSWatcher(object):
|
||||
if isinstance(event, (FileCreatedEvent, FileModifiedEvent, FileMovedEvent)):
|
||||
if not event.is_directory:
|
||||
path = getattr(event, 'dest_path', event.src_path)
|
||||
if path.endswith('.py') and not os.path.basename(path).startswith('.~'):
|
||||
try:
|
||||
source = open(path, 'rb').read() + '\n'
|
||||
compile(source, path, 'exec')
|
||||
except FileNotFoundError:
|
||||
_logger.error('autoreload: python code change detected, FileNotFound for %s', path)
|
||||
except SyntaxError:
|
||||
_logger.error('autoreload: python code change detected, SyntaxError in %s', path)
|
||||
else:
|
||||
if not getattr(odoo, 'phoenix', False):
|
||||
_logger.info('autoreload: python code updated, autoreload activated')
|
||||
restart()
|
||||
self.handle_file(path)
|
||||
|
||||
def start(self):
|
||||
self.observer.start()
|
||||
_logger.info('AutoReload watcher running')
|
||||
_logger.info('AutoReload watcher running with watchdog')
|
||||
|
||||
def stop(self):
|
||||
self.observer.stop()
|
||||
self.observer.join()
|
||||
|
||||
|
||||
class FSWatcherInotify(FSWatcherBase):
|
||||
def __init__(self):
|
||||
self.started = False
|
||||
# ignore warnings from inotify in case we have duplicate addons paths.
|
||||
inotify.adapters._LOGGER.setLevel(logging.ERROR)
|
||||
# recreate a list as InotifyTrees' __init__ deletes the list's items
|
||||
paths_to_watch = []
|
||||
for path in odoo.modules.module.ad_paths:
|
||||
paths_to_watch.append(path)
|
||||
_logger.info('Watching addons folder %s', path)
|
||||
self.watcher = InotifyTrees(paths_to_watch, mask=INOTIFY_LISTEN_EVENTS, block_duration_s=.5)
|
||||
|
||||
def run(self):
|
||||
_logger.info('AutoReload watcher running with inotify')
|
||||
dir_creation_events = set(('IN_MOVED_TO', 'IN_CREATE'))
|
||||
while self.started:
|
||||
for event in self.watcher.event_gen(timeout_s=0, yield_nones=False):
|
||||
(_, type_names, path, filename) = event
|
||||
if 'IN_ISDIR' not in type_names:
|
||||
# despite not having IN_DELETE in the watcher's mask, the
|
||||
# watcher sends these events when a directory is deleted.
|
||||
if 'IN_DELETE' not in type_names:
|
||||
full_path = os.path.join(path, filename)
|
||||
if self.handle_file(full_path):
|
||||
return
|
||||
elif dir_creation_events.intersection(type_names):
|
||||
full_path = os.path.join(path, filename)
|
||||
for root, _, files in os.walk(full_path):
|
||||
for file in files:
|
||||
if self.handle_file(os.path.join(root, file)):
|
||||
return
|
||||
|
||||
def start(self):
|
||||
self.started = True
|
||||
self.thread = threading.Thread(target=self.run, name="odoo.service.autoreload.watcher")
|
||||
self.thread.setDaemon(True)
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
self.started = False
|
||||
self.thread.join()
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Servers: Threaded, Gevented and Prefork
|
||||
#----------------------------------------------------------
|
||||
@@ -956,21 +1016,28 @@ def start(preload=None, stop=False):
|
||||
server = ThreadedServer(odoo.service.wsgi_server.application)
|
||||
|
||||
watcher = None
|
||||
if 'reload' in config['dev_mode']:
|
||||
if watchdog:
|
||||
watcher = FSWatcher()
|
||||
if 'reload' in config['dev_mode'] and not odoo.evented:
|
||||
if inotify:
|
||||
watcher = FSWatcherInotify()
|
||||
watcher.start()
|
||||
elif watchdog:
|
||||
watcher = FSWatcherWatchdog()
|
||||
watcher.start()
|
||||
else:
|
||||
_logger.warning("'watchdog' module not installed. Code autoreload feature is disabled")
|
||||
if os.name == 'posix' and platform.system() != 'Darwin':
|
||||
module = 'inotify'
|
||||
else:
|
||||
module = 'watchdog'
|
||||
_logger.warning("'%s' module not installed. Code autoreload feature is disabled", module)
|
||||
if 'werkzeug' in config['dev_mode']:
|
||||
server.app = DebuggedApplication(server.app, evalex=True)
|
||||
|
||||
rc = server.run(preload, stop)
|
||||
|
||||
if watcher:
|
||||
watcher.stop()
|
||||
# like the legend of the phoenix, all ends with beginnings
|
||||
if getattr(odoo, 'phoenix', False):
|
||||
if watcher:
|
||||
watcher.stop()
|
||||
_reexec()
|
||||
|
||||
return rc if rc else 0
|
||||
|
||||
Reference in New Issue
Block a user