You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					131 lines
				
				3.7 KiB
			
		
		
			
		
	
	
					131 lines
				
				3.7 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								# -*- coding: utf-8 -
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This file is part of gunicorn released under the MIT license.
							 | 
						||
| 
								 | 
							
								# See the NOTICE for more information.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import os.path
							 | 
						||
| 
								 | 
							
								import re
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import time
							 | 
						||
| 
								 | 
							
								import threading
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Reloader(threading.Thread):
							 | 
						||
| 
								 | 
							
								    def __init__(self, extra_files=None, interval=1, callback=None):
							 | 
						||
| 
								 | 
							
								        super(Reloader, self).__init__()
							 | 
						||
| 
								 | 
							
								        self.setDaemon(True)
							 | 
						||
| 
								 | 
							
								        self._extra_files = set(extra_files or ())
							 | 
						||
| 
								 | 
							
								        self._extra_files_lock = threading.RLock()
							 | 
						||
| 
								 | 
							
								        self._interval = interval
							 | 
						||
| 
								 | 
							
								        self._callback = callback
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def add_extra_file(self, filename):
							 | 
						||
| 
								 | 
							
								        with self._extra_files_lock:
							 | 
						||
| 
								 | 
							
								            self._extra_files.add(filename)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_files(self):
							 | 
						||
| 
								 | 
							
								        fnames = [
							 | 
						||
| 
								 | 
							
								            re.sub('py[co]$', 'py', module.__file__)
							 | 
						||
| 
								 | 
							
								            for module in list(sys.modules.values())
							 | 
						||
| 
								 | 
							
								            if getattr(module, '__file__', None)
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        with self._extra_files_lock:
							 | 
						||
| 
								 | 
							
								            fnames.extend(self._extra_files)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return fnames
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def run(self):
							 | 
						||
| 
								 | 
							
								        mtimes = {}
							 | 
						||
| 
								 | 
							
								        while True:
							 | 
						||
| 
								 | 
							
								            for filename in self.get_files():
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    mtime = os.stat(filename).st_mtime
							 | 
						||
| 
								 | 
							
								                except OSError:
							 | 
						||
| 
								 | 
							
								                    continue
							 | 
						||
| 
								 | 
							
								                old_time = mtimes.get(filename)
							 | 
						||
| 
								 | 
							
								                if old_time is None:
							 | 
						||
| 
								 | 
							
								                    mtimes[filename] = mtime
							 | 
						||
| 
								 | 
							
								                    continue
							 | 
						||
| 
								 | 
							
								                elif mtime > old_time:
							 | 
						||
| 
								 | 
							
								                    if self._callback:
							 | 
						||
| 
								 | 
							
								                        self._callback(filename)
							 | 
						||
| 
								 | 
							
								            time.sleep(self._interval)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								has_inotify = False
							 | 
						||
| 
								 | 
							
								if sys.platform.startswith('linux'):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        from inotify.adapters import Inotify
							 | 
						||
| 
								 | 
							
								        import inotify.constants
							 | 
						||
| 
								 | 
							
								        has_inotify = True
							 | 
						||
| 
								 | 
							
								    except ImportError:
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if has_inotify:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class InotifyReloader(threading.Thread):
							 | 
						||
| 
								 | 
							
								        event_mask = (inotify.constants.IN_CREATE | inotify.constants.IN_DELETE
							 | 
						||
| 
								 | 
							
								                      | inotify.constants.IN_DELETE_SELF | inotify.constants.IN_MODIFY
							 | 
						||
| 
								 | 
							
								                      | inotify.constants.IN_MOVE_SELF | inotify.constants.IN_MOVED_FROM
							 | 
						||
| 
								 | 
							
								                      | inotify.constants.IN_MOVED_TO)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __init__(self, extra_files=None, callback=None):
							 | 
						||
| 
								 | 
							
								            super(InotifyReloader, self).__init__()
							 | 
						||
| 
								 | 
							
								            self.setDaemon(True)
							 | 
						||
| 
								 | 
							
								            self._callback = callback
							 | 
						||
| 
								 | 
							
								            self._dirs = set()
							 | 
						||
| 
								 | 
							
								            self._watcher = Inotify()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for extra_file in extra_files:
							 | 
						||
| 
								 | 
							
								                self.add_extra_file(extra_file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def add_extra_file(self, filename):
							 | 
						||
| 
								 | 
							
								            dirname = os.path.dirname(filename)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if dirname in self._dirs:
							 | 
						||
| 
								 | 
							
								                return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            self._watcher.add_watch(dirname, mask=self.event_mask)
							 | 
						||
| 
								 | 
							
								            self._dirs.add(dirname)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def get_dirs(self):
							 | 
						||
| 
								 | 
							
								            fnames = [
							 | 
						||
| 
								 | 
							
								                os.path.dirname(re.sub('py[co]$', 'py', module.__file__))
							 | 
						||
| 
								 | 
							
								                for module in list(sys.modules.values())
							 | 
						||
| 
								 | 
							
								                if hasattr(module, '__file__')
							 | 
						||
| 
								 | 
							
								            ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return set(fnames)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def run(self):
							 | 
						||
| 
								 | 
							
								            self._dirs = self.get_dirs()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for dirname in self._dirs:
							 | 
						||
| 
								 | 
							
								                self._watcher.add_watch(dirname, mask=self.event_mask)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for event in self._watcher.event_gen():
							 | 
						||
| 
								 | 
							
								                if event is None:
							 | 
						||
| 
								 | 
							
								                    continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                filename = event[3]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                self._callback(filename)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class InotifyReloader(object):
							 | 
						||
| 
								 | 
							
								        def __init__(self, callback=None):
							 | 
						||
| 
								 | 
							
								            raise ImportError('You must have the inotify module installed to '
							 | 
						||
| 
								 | 
							
								                              'use the inotify reloader')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								preferred_reloader = InotifyReloader if has_inotify else Reloader
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								reloader_engines = {
							 | 
						||
| 
								 | 
							
								    'auto': preferred_reloader,
							 | 
						||
| 
								 | 
							
								    'poll': Reloader,
							 | 
						||
| 
								 | 
							
								    'inotify': InotifyReloader,
							 | 
						||
| 
								 | 
							
								}
							 |