web/lib/django/utils/autoreload.py
changeset 0 0d40e90630ef
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 # Autoreloading launcher.
       
     2 # Borrowed from Peter Hunt and the CherryPy project (http://www.cherrypy.org).
       
     3 # Some taken from Ian Bicking's Paste (http://pythonpaste.org/).
       
     4 #
       
     5 # Portions copyright (c) 2004, CherryPy Team (team@cherrypy.org)
       
     6 # All rights reserved.
       
     7 #
       
     8 # Redistribution and use in source and binary forms, with or without modification,
       
     9 # are permitted provided that the following conditions are met:
       
    10 #
       
    11 #     * Redistributions of source code must retain the above copyright notice,
       
    12 #       this list of conditions and the following disclaimer.
       
    13 #     * Redistributions in binary form must reproduce the above copyright notice,
       
    14 #       this list of conditions and the following disclaimer in the documentation
       
    15 #       and/or other materials provided with the distribution.
       
    16 #     * Neither the name of the CherryPy Team nor the names of its contributors
       
    17 #       may be used to endorse or promote products derived from this software
       
    18 #       without specific prior written permission.
       
    19 #
       
    20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
       
    21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    23 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
       
    24 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
       
    26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
       
    27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
       
    28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30 
       
    31 import os, sys, time
       
    32 
       
    33 try:
       
    34     import thread
       
    35 except ImportError:
       
    36     import dummy_thread as thread
       
    37 
       
    38 # This import does nothing, but it's necessary to avoid some race conditions
       
    39 # in the threading module. See http://code.djangoproject.com/ticket/2330 .
       
    40 try:
       
    41     import threading
       
    42 except ImportError:
       
    43     pass
       
    44 
       
    45 
       
    46 RUN_RELOADER = True
       
    47 
       
    48 _mtimes = {}
       
    49 _win = (sys.platform == "win32")
       
    50 
       
    51 def code_changed():
       
    52     global _mtimes, _win
       
    53     for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())):
       
    54         if filename.endswith(".pyc") or filename.endswith(".pyo"):
       
    55             filename = filename[:-1]
       
    56         if not os.path.exists(filename):
       
    57             continue # File might be in an egg, so it can't be reloaded.
       
    58         stat = os.stat(filename)
       
    59         mtime = stat.st_mtime
       
    60         if _win:
       
    61             mtime -= stat.st_ctime
       
    62         if filename not in _mtimes:
       
    63             _mtimes[filename] = mtime
       
    64             continue
       
    65         if mtime != _mtimes[filename]:
       
    66             _mtimes = {}
       
    67             return True
       
    68     return False
       
    69 
       
    70 def reloader_thread():
       
    71     while RUN_RELOADER:
       
    72         if code_changed():
       
    73             sys.exit(3) # force reload
       
    74         time.sleep(1)
       
    75 
       
    76 def restart_with_reloader():
       
    77     while True:
       
    78         args = [sys.executable] + sys.argv
       
    79         if sys.platform == "win32":
       
    80             args = ['"%s"' % arg for arg in args]
       
    81         new_environ = os.environ.copy()
       
    82         new_environ["RUN_MAIN"] = 'true'
       
    83         exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)
       
    84         if exit_code != 3:
       
    85             return exit_code
       
    86 
       
    87 def python_reloader(main_func, args, kwargs):
       
    88     if os.environ.get("RUN_MAIN") == "true":
       
    89         thread.start_new_thread(main_func, args, kwargs)
       
    90         try:
       
    91             reloader_thread()
       
    92         except KeyboardInterrupt:
       
    93             pass
       
    94     else:
       
    95         try:
       
    96             sys.exit(restart_with_reloader())
       
    97         except KeyboardInterrupt:
       
    98             pass
       
    99 
       
   100 def jython_reloader(main_func, args, kwargs):
       
   101     from _systemrestart import SystemRestart
       
   102     thread.start_new_thread(main_func, args)
       
   103     while True:
       
   104         if code_changed():
       
   105             raise SystemRestart
       
   106         time.sleep(1)
       
   107 
       
   108 
       
   109 def main(main_func, args=None, kwargs=None):
       
   110     if args is None:
       
   111         args = ()
       
   112     if kwargs is None:
       
   113         kwargs = {}
       
   114     if sys.platform.startswith('java'):
       
   115         reloader = jython_reloader
       
   116     else:
       
   117         reloader = python_reloader
       
   118     reloader(main_func, args, kwargs)
       
   119