X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=openerp%2Fservice%2Fserver.py;fp=openerp%2Fservice%2Fserver.py;h=9d10e29ebec2d0349265248cbc734c5f23955625;hb=e17222a38d2d4cd32057a59e65be82edd103836c;hp=43f9aadcbe769b84e94ca2998417d393233c82b1;hpb=2e092ace29d88e0ea892708b93dffa94a283e771;p=odoo%2Fodoo.git diff --git a/openerp/service/server.py b/openerp/service/server.py index 43f9aad..9d10e29 100644 --- a/openerp/service/server.py +++ b/openerp/service/server.py @@ -42,6 +42,13 @@ from openerp.tools.misc import stripped_sys_argv, dumpstacks _logger = logging.getLogger(__name__) +try: + import watchdog + from watchdog.observers import Observer + from watchdog.events import FileCreatedEvent, FileModifiedEvent +except ImportError: + watchdog = None + SLEEP_INTERVAL = 60 # 1 min #---------------------------------------------------------- @@ -106,90 +113,37 @@ class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving. super(ThreadedWSGIServerReloadable, self).server_activate() #---------------------------------------------------------- -# AutoReload watcher +# FileSystem Watcher for autoreload and cache invalidation #---------------------------------------------------------- - -class AutoReload(object): - def __init__(self, server): - self.server = server - self.files = {} - self.modules = {} - import pyinotify - class EventHandler(pyinotify.ProcessEvent): - def __init__(self, autoreload): - self.autoreload = autoreload - - def process_IN_CREATE(self, event): - _logger.debug('File created: %s', event.pathname) - self.autoreload.files[event.pathname] = 1 - - def process_IN_MODIFY(self, event): - _logger.debug('File modified: %s', event.pathname) - self.autoreload.files[event.pathname] = 1 - - self.wm = pyinotify.WatchManager() - self.handler = EventHandler(self) - self.notifier = pyinotify.Notifier(self.wm, self.handler, timeout=0) - mask = pyinotify.IN_MODIFY | pyinotify.IN_CREATE # IN_MOVED_FROM, IN_MOVED_TO ? +class FSWatcher(object): + def __init__(self): + self.observer = Observer() for path in openerp.modules.module.ad_paths: _logger.info('Watching addons folder %s', path) - self.wm.add_watch(path, mask, rec=True) - - def process_data(self, files): - xml_files = [i for i in files if i.endswith('.xml')] - for i in xml_files: - for path in openerp.modules.module.ad_paths: - if i.startswith(path): - # find out wich addons path the file belongs to - # and extract it's module name - right = i[len(path) + 1:].split('/') - if len(right) < 2: - continue - module = right[0] - self.modules[module] = 1 - if self.modules: - _logger.info('autoreload: xml change detected, autoreload activated') - restart() - - def process_python(self, files): - # process python changes - py_files = [i for i in files if i.endswith('.py')] - py_errors = [] - # TODO keep python errors until they are ok - if py_files: - for i in py_files: - try: - source = open(i, 'rb').read() + '\n' - compile(source, i, 'exec') - except SyntaxError: - py_errors.append(i) - if py_errors: - _logger.info('autoreload: python code change detected, errors found') - for i in py_errors: - _logger.info('autoreload: SyntaxError %s', i) - else: - _logger.info('autoreload: python code updated, autoreload activated') - restart() - - def check_thread(self): - # Check if some files have been touched in the addons path. - # If true, check if the touched file belongs to an installed module - # in any of the database used in the registry manager. - while 1: - while self.notifier.check_events(1000): - self.notifier.read_events() - self.notifier.process_events() - l = self.files.keys() - self.files.clear() - self.process_data(l) - self.process_python(l) + self.observer.schedule(self, path, recursive=True) + + def dispatch(self, event): + if isinstance(event, (FileCreatedEvent, FileModifiedEvent)): + if not event.is_directory: + path = event.src_path + if path.endswith('.py'): + try: + source = open(path, 'rb').read() + '\n' + compile(source, path, 'exec') + except SyntaxError: + _logger.error('autoreload: python code change detected, SyntaxError in %s', path) + else: + _logger.info('autoreload: python code updated, autoreload activated') + restart() - def run(self): - t = threading.Thread(target=self.check_thread) - t.setDaemon(True) - t.start() + def start(self): + self.observer.start() _logger.info('AutoReload watcher running') + def stop(self): + self.observer.stop() + self.observer.join() + #---------------------------------------------------------- # Servers: Threaded, Gevented and Prefork #---------------------------------------------------------- @@ -859,7 +813,8 @@ def _reexec(updated_modules=None): subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True) exe = os.path.basename(sys.executable) args = stripped_sys_argv() - args += ["-u", ','.join(updated_modules)] + if updated_modules: + args += ["-u", ','.join(updated_modules)] if not args or args[0] != exe: args.insert(0, exe) os.execv(sys.executable, args) @@ -932,18 +887,21 @@ def start(preload=None, stop=False): else: server = ThreadedServer(openerp.service.wsgi_server.application) - if config['auto_reload']: - autoreload = AutoReload(server) - autoreload.run() + watcher = None + if config['dev_mode']: + if watchdog: + watcher = FSWatcher() + watcher.start() + else: + _logger.warning("'watchdog' module not installed. Code autoreload feature is disabled") rc = server.run(preload, stop) # like the legend of the phoenix, all ends with beginnings if getattr(openerp, 'phoenix', False): - modules = [] - if config['auto_reload']: - modules = autoreload.modules.keys() - _reexec(modules) + if watcher: + watcher.stop() + _reexec() return rc if rc else 0