NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

codereloading.py (9363B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\codereloading.py
      2 import __builtin__
      3 import inspect
      4 import logging
      5 import os
      6 import Queue
      7 import sys
      8 import time
      9 import traceback
     10 import weakref
     11 import blue
     12 import signals
     13 import uthread
     14 from codereload import xreload
     15 from eveprefs import prefs
     16 from watchdog.events import FileSystemEventHandler
     17 from watchdog.observers import Observer
     18 logger = logging.getLogger(__name__)
     19 logger.addHandler(logging.NullHandler())
     20 
     21 class CodeReloadHandler(FileSystemEventHandler):
     22     EXCLUDED_FOLDERS = [ os.path.normpath(folder) for folder in ['packages/audio2',
     23      'packages/d3dinfo',
     24      'packages/destiny',
     25      'packages/eveLocalization',
     26      'packages/geo2',
     27      'packages/geo2helpers',
     28      'packages/imageutils',
     29      'packages/inputmethod',
     30      'packages/pyFSD',
     31      'packages/spacemouse',
     32      'packages/videoplayer'] ]
     33 
     34     def __init__(self):
     35         super(CodeReloadHandler, self).__init__()
     36         self._reload_queue = Queue.Queue()
     37         self.on_file_reloaded = signals.Signal()
     38         self.on_file_reload_failed = signals.Signal()
     39         uthread.new(self._monitor_reload_queue, weakref.ref(self))
     40 
     41     @staticmethod
     42     def _monitor_reload_queue(self_ref):
     43         while True:
     44             self = self_ref()
     45             if self is None:
     46                 return
     47             while not self._reload_queue.empty():
     48                 try:
     49                     filename = self._reload_queue.get_nowait()
     50                 except Queue.Empty:
     51                     break
     52 
     53                 self.reload_file(filename)
     54 
     55             del self
     56             blue.pyos.synchro.Yield()
     57 
     58     def on_modified(self, event):
     59         super(CodeReloadHandler, self).on_modified(event)
     60         if event.is_directory:
     61             return
     62         logger.debug('File modification detected: %s', event)
     63         self._reload_queue.put(event.src_path, block=False)
     64 
     65     def on_moved(self, event):
     66         super(CodeReloadHandler, self).on_moved(event)
     67         if event.is_directory:
     68             return
     69         logger.debug('File move modification detected: %s', event)
     70         self._reload_queue.put(event.dest_path, block=False)
     71 
     72     def reload_file(self, filename):
     73         orig_filename = filename
     74         logger.debug('enter reload_file(%s)', orig_filename)
     75         filename = os.path.normpath(os.path.abspath(filename))
     76         for excluded_folder in self.EXCLUDED_FOLDERS:
     77             if excluded_folder in filename:
     78                 logger.debug('reload_file[%s] excluded because of excluded_folder[%s]' % (filename, excluded_folder))
     79                 return
     80 
     81         if filename[-3:] != '.py':
     82             return
     83 
     84         def find_module(filename):
     85             filename = os.path.normpath(filename)
     86             normalized_case_filename = os.path.normcase(filename)
     87             for prefix in sys.path[1:]:
     88                 prefix = os.path.normcase(os.path.normpath(prefix))
     89                 if not normalized_case_filename.startswith(prefix):
     90                     continue
     91                 p, f = os.path.split(filename)
     92                 if not f:
     93                     logger.error('Unexpected missing module name for filename %s', filename)
     94                     continue
     95                 p = p[len(prefix) + len(os.path.sep):]
     96                 p = p.replace(os.path.sep, '.')
     97                 f = f[:-3]
     98                 if f != '__init__':
     99                     if p:
    100                         p = p + '.' + f
    101                     else:
    102                         p = f
    103                 m = sys.modules.get(p, None)
    104                 if m is not None:
    105                     return m
    106 
    107         module = find_module(filename)
    108         if module is None:
    109             logger.warning('Could not find module to reload for filename %s', orig_filename)
    110         else:
    111             try:
    112                 t = time.time()
    113                 with open(filename) as stream:
    114                     source = stream.read() + '\n'
    115                 seconds_read = time.time() - t
    116                 logger.info('Compiling %s using source %s', module.__name__, filename)
    117                 code = compile(source, filename, 'exec')
    118                 logger.info('Reloading %s', module)
    119                 seconds_compile = time.time() - t - seconds_read
    120                 xreload(module, code)
    121                 uthread.new(self.on_file_reloaded, filename, module)
    122                 seconds_total = time.time() - t
    123                 seconds_xreload = seconds_total - seconds_compile
    124                 logger.info('Reloaded %s in %.3f seconds (read: %.3f seconds, compile: %.3f seconds, xreload: %.3f seconds)', module, seconds_total, seconds_read, seconds_compile, seconds_xreload)
    125             except Exception:
    126                 logger.exception('reload_file failed for %s', filename)
    127                 self.on_file_reload_failed(filename, sys.exc_info())
    128 
    129 
    130 class FsdReloadHandler(FileSystemEventHandler):
    131 
    132     def __init__(self):
    133         super(FsdReloadHandler, self).__init__()
    134 
    135     def on_modified(self, event):
    136         super(FsdReloadHandler, self).on_modified(event)
    137         logger.debug('FSD modification detected: %s', event.src_path)
    138         try:
    139             from fsdBuiltData.common.base import BuiltDataLoader
    140         except ImportError:
    141             logger.exception('Failed importing fsdBuiltData')
    142             return
    143 
    144         for subClass in BuiltDataLoader.__subclasses__():
    145             try:
    146                 if subClass.CheckReloadDataFromDisk():
    147                     logger.info('Reloaded FSD data for %s: %s', subClass.__name__, subClass.GetAutobuildFilePath())
    148             except Exception:
    149                 logger.exception('Failed to reload FSD data')
    150 
    151 
    152 def _OnFileReloaded(filename, module):
    153     try:
    154         sm = getattr(__builtin__, 'sm', None)
    155         if sm is None:
    156             logger.warn(' sm not defined, cannot reload services.')
    157             return
    158         guids = [ cls.__guid__[4:] for name, cls in inspect.getmembers(module, inspect.isclass) if getattr(cls, '__guid__', '').startswith('svc.') ]
    159         sm.Reload(set(guids))
    160         reloadHook = getattr(module, '__SakeReloadHook', None)
    161         if reloadHook is not None:
    162             reloadHook()
    163         logger.info('Reloaded %s', filename)
    164         print 'Reloaded', filename
    165     except Exception:
    166         logger.exception('Unhandled exception in _OnFileReloaded')
    167 
    168 
    169 def _OnFileReloadFailed(filename, exc_info):
    170     sys.stderr.write('Failed to reload: %s\n' % filename)
    171     traceback.print_exception(*exc_info)
    172 
    173 
    174 __SAKE_INSTALLATION_ATTEMPTED = False
    175 __OBSERVER = None
    176 __WATCHES = []
    177 
    178 def FileSystemObserver():
    179     global __OBSERVER
    180     if __OBSERVER is None:
    181         __OBSERVER = Observer()
    182     return __OBSERVER
    183 
    184 
    185 def InstallSakeAutocompiler():
    186     global __SAKE_INSTALLATION_ATTEMPTED
    187     if not __SAKE_INSTALLATION_ATTEMPTED:
    188         if prefs.clusterMode == 'LOCAL' and not blue.pyos.packaged:
    189             try:
    190                 InitializeCodeReloadSpy()
    191                 InitializeFSDReloadSpy()
    192             except Exception:
    193                 logger.exception('sake AutoCompiler failed to install.')
    194 
    195         else:
    196             logger.info('Skipping sake AutoCompiler installation.')
    197         if __OBSERVER is not None:
    198             __OBSERVER.start()
    199             logger.info('AutoCompiler installation complete.')
    200         __SAKE_INSTALLATION_ATTEMPTED = True
    201     else:
    202         logger.info('Tried to install sake AutoCompiler but already installed.')
    203 
    204 
    205 def InitializeCodeReloadSpy(onFileReloaded = _OnFileReloaded, onFileReloadFailed = _OnFileReloadFailed):
    206     global __WATCHES
    207     blueSpy = CodeReloadHandler()
    208     blueSpy.on_file_reloaded.connect(onFileReloaded)
    209     blueSpy.on_file_reload_failed.connect(onFileReloadFailed)
    210 
    211     def filterOutSubPaths(paths):
    212         newPaths = []
    213         for absPath, relPath in sorted([ (os.path.normcase(os.path.abspath(path) + os.sep), path) for path in paths ]):
    214             if not len([ path for path, _ in newPaths if absPath.startswith(path) ]):
    215                 newPaths.append((absPath, relPath))
    216 
    217         return [ path for _, path in newPaths ]
    218 
    219     paths = filterOutSubPaths(blue.paths.GetExpandedSearchPaths()['lib'])
    220     for path in paths:
    221         logger.info('Observing: %s', path)
    222         __WATCHES.append(FileSystemObserver().schedule(blueSpy, path, recursive=True))
    223 
    224     logger.info('Installed sake AutoCompiler.' + repr(paths))
    225 
    226 
    227 def InitializeFSDReloadSpy(boot_role = None):
    228     from fsd import GetBranchRoot, GetFullName, AbsJoin
    229     from eveprefs import boot
    230     branch_root = GetBranchRoot()
    231     if boot_role is None:
    232         boot_role = boot.role
    233     if boot_role == 'server':
    234         paths = [GetFullName(AbsJoin(branch_root, 'eve/autobuild/staticData/server'))]
    235     elif boot_role == 'client':
    236         paths = [GetFullName(AbsJoin(branch_root, 'eve/autobuild/staticData/client'))]
    237     else:
    238         return
    239     handler = FsdReloadHandler()
    240     for path in paths:
    241         __WATCHES.append(FileSystemObserver().schedule(handler, path, recursive=True))
    242 
    243 
    244 def OnFSDReload(path):
    245     from fsdBuiltData.common.base import BuiltDataLoader
    246     for subClass in BuiltDataLoader.__subclasses__():
    247         try:
    248             if subClass.CheckReloadDataFromDisk():
    249                 print 'Reloaded FSD data for %s: %s' % (subClass.__name__, subClass.GetAutobuildFilePath())
    250         except:
    251             logger.exception('Failed to reload FSD data')