~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/tornado/tornado/autoreload.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Copyright 2009 Facebook
 
4
#
 
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 
6
# not use this file except in compliance with the License. You may obtain
 
7
# a copy of the License at
 
8
#
 
9
#     http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
# Unless required by applicable law or agreed to in writing, software
 
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
14
# License for the specific language governing permissions and limitations
 
15
# under the License.
 
16
 
 
17
"""A module to automatically restart the server when a module is modified.
 
18
 
 
19
This module depends on IOLoop, so it will not work in WSGI applications
 
20
and Google AppEngine.
 
21
"""
 
22
 
 
23
import functools
 
24
import errno
 
25
import ioloop
 
26
import logging
 
27
import os
 
28
import os.path
 
29
import sys
 
30
import types
 
31
 
 
32
_log = logging.getLogger('tornado.autoreload')
 
33
 
 
34
def start(io_loop=None, check_time=500):
 
35
    """Restarts the process automatically when a module is modified.
 
36
 
 
37
    We run on the I/O loop, and restarting is a destructive operation,
 
38
    so will terminate any pending requests.
 
39
    """
 
40
    io_loop = io_loop or ioloop.IOLoop.instance()
 
41
    modify_times = {}
 
42
    callback = functools.partial(_reload_on_update, io_loop, modify_times)
 
43
    scheduler = ioloop.PeriodicCallback(callback, check_time, io_loop=io_loop)
 
44
    scheduler.start()
 
45
 
 
46
 
 
47
_reload_attempted = False
 
48
 
 
49
def _reload_on_update(io_loop, modify_times):
 
50
    global _reload_attempted
 
51
    if _reload_attempted:
 
52
        # We already tried to reload and it didn't work, so don't try again.
 
53
        return
 
54
    for module in sys.modules.values():
 
55
        # Some modules play games with sys.modules (e.g. email/__init__.py
 
56
        # in the standard library), and occasionally this can cause strange
 
57
        # failures in getattr.  Just ignore anything that's not an ordinary
 
58
        # module.
 
59
        if not isinstance(module, types.ModuleType): continue
 
60
        path = getattr(module, "__file__", None)
 
61
        if not path: continue
 
62
        if path.endswith(".pyc") or path.endswith(".pyo"):
 
63
            path = path[:-1]
 
64
        try:
 
65
            modified = os.stat(path).st_mtime
 
66
        except:
 
67
            continue
 
68
        if path not in modify_times:
 
69
            modify_times[path] = modified
 
70
            continue
 
71
        if modify_times[path] != modified:
 
72
            _log.info("%s modified; restarting server", path)
 
73
            _reload_attempted = True
 
74
            for fd in io_loop._handlers.keys():
 
75
                try:
 
76
                    os.close(fd)
 
77
                except:
 
78
                    pass
 
79
            try:
 
80
                os.execv(sys.executable, [sys.executable] + sys.argv)
 
81
            except OSError, e:
 
82
                # Mac OS X versions prior to 10.6 do not support execv in
 
83
                # a process that contains multiple threads.  Instead of
 
84
                # re-executing in the current process, start a new one
 
85
                # and cause the current process to exit.  This isn't
 
86
                # ideal since the new process is detached from the parent
 
87
                # terminal and thus cannot easily be killed with ctrl-C,
 
88
                # but it's better than not being able to autoreload at
 
89
                # all.
 
90
                # Unfortunately the errno returned in this case does not
 
91
                # appear to be consistent, so we can't easily check for
 
92
                # this error specifically.
 
93
                os.spawnv(os.P_NOWAIT, sys.executable,
 
94
                          [sys.executable] + sys.argv)
 
95
                sys.exit(0)