cubicweb/pyramid/pyramidctl.py
author Denis Laxalde <denis.laxalde@logilab.fr>
Fri, 10 Mar 2017 12:02:41 +0100
changeset 12052 1a1d2f5faddb
parent 12003 5236ce988805
child 12053 c3c9f2e1424c
permissions -rw-r--r--
[pyramid] Call repository's shutdown method atexit This way when run through a WSGI server (pserve, gunicorn, etc.) we make sure that the repository is properly shut down. In particular, this would wait for threads to terminate (otherwise, they'll be killed).
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11967
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     1
# copyright 2017 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     2
# copyright 2014-2016 UNLISH S.A.S. (Montpellier, FRANCE), all rights reserved.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     3
#
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     4
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     5
#
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     6
# This file is part of CubicWeb.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     7
#
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     8
# CubicWeb is free software: you can redistribute it and/or modify it under the
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
     9
# terms of the GNU Lesser General Public License as published by the Free
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    10
# Software Foundation, either version 2.1 of the License, or (at your option)
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    11
# any later version.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    12
#
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    13
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    14
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    15
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    16
# details.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    17
#
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    18
# You should have received a copy of the GNU Lesser General Public License along
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    19
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    20
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    21
"""
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    22
Provides a 'pyramid' command as a replacement to the 'start' command.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    23
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    24
The reloading strategy is heavily inspired by (and partially copied from)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    25
the pyramid script 'pserve'.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    26
"""
11967
83739be20fab [pyramid] Add a copyright and docstring to all modules
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11867
diff changeset
    27
11663
6fb9d9276880 [ccplugin] print_function
Julien Cristau <julien.cristau@logilab.fr>
parents: 11658
diff changeset
    28
from __future__ import print_function
6fb9d9276880 [ccplugin] print_function
Julien Cristau <julien.cristau@logilab.fr>
parents: 11658
diff changeset
    29
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    30
import atexit
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    31
import errno
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    32
import os
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    33
import signal
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    34
import sys
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    35
import time
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    36
import threading
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    37
import subprocess
12003
5236ce988805 [pyramid] Drop call to repository's start_looping_tasks method and warn about this
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11967
diff changeset
    38
import warnings
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    39
11867
c714e55fbce1 [cwctl] Kill deprecated ordered_instances method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11837
diff changeset
    40
from cubicweb import ExecutionError
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    41
from cubicweb.cwconfig import CubicWebConfiguration as cwcfg
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    42
from cubicweb.cwctl import CWCTL, InstanceCommand, init_cmdline_log_threshold
11681
b23d58050076 Merge cubicweb-pyramid cube
Yann Voté <yann.vote@logilab.fr>
parents: 11680
diff changeset
    43
from cubicweb.pyramid import wsgi_application_from_cwconfig
11672
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    44
from cubicweb.server import set_debug
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    45
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    46
import waitress
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    47
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    48
MAXFD = 1024
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    49
11672
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    50
DBG_FLAGS = ('RQL', 'SQL', 'REPO', 'HOOKS', 'OPS', 'SEC', 'MORE')
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    51
LOG_LEVELS = ('debug', 'info', 'warning', 'error')
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    52
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
    53
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    54
class PyramidStartHandler(InstanceCommand):
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    55
    """Start an interactive pyramid server.
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    56
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    57
    <instance>
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    58
      identifier of the instance to configure.
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    59
    """
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    60
    name = 'pyramid'
11814
ab8f652a9c99 [pyramid] Add action verb used in some messages displayed by the command
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11813
diff changeset
    61
    actionverb = 'started'
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    62
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    63
    options = (
11641
3d4e7be2e3c3 Add a --no-daemon option
Christophe de Vienne <christophe@unlish.com>
parents: 11640
diff changeset
    64
        ('no-daemon',
3d4e7be2e3c3 Add a --no-daemon option
Christophe de Vienne <christophe@unlish.com>
parents: 11640
diff changeset
    65
         {'action': 'store_true',
3d4e7be2e3c3 Add a --no-daemon option
Christophe de Vienne <christophe@unlish.com>
parents: 11640
diff changeset
    66
          'help': 'Run the server in the foreground.'}),
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    67
        ('debug-mode',
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    68
         {'action': 'store_true',
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    69
          'help': 'Activate the repository debug mode ('
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    70
                  'logs in the console and the debug toolbar).'
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    71
                  ' Implies --no-daemon'}),
11641
3d4e7be2e3c3 Add a --no-daemon option
Christophe de Vienne <christophe@unlish.com>
parents: 11640
diff changeset
    72
        ('debug',
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    73
         {'short': 'D', 'action': 'store_true',
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
    74
          'help': 'Equals to "--debug-mode --no-daemon --reload"'}),
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    75
        ('reload',
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    76
         {'action': 'store_true',
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    77
          'help': 'Restart the server if any source file is changed'}),
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    78
        ('reload-interval',
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    79
         {'type': 'int', 'default': 1,
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
    80
          'help': 'Interval, in seconds, between file modifications checks'}),
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    81
        ('loglevel',
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    82
         {'short': 'l', 'type': 'choice', 'metavar': '<log level>',
11672
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    83
          'default': None, 'choices': LOG_LEVELS,
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
    84
          'help': 'debug if -D is set, error otherwise; '
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
    85
                  'one of %s' % (LOG_LEVELS,),
11672
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    86
          }),
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    87
        ('dbglevel',
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    88
         {'type': 'multiple_choice', 'metavar': '<dbg level>',
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    89
          'default': None,
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    90
          'choices': DBG_FLAGS,
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    91
          'help': ('Set the server debugging flags; you may choose several '
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
    92
                   'values in %s; imply "debug" loglevel' % (DBG_FLAGS,)),
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
    93
          }),
11648
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
    94
        ('profile',
11652
e95725d7ce90 Allow to override config file options by cmdline arguments (closes #5724484)
David Douard <david.douard@logilab.fr>
parents: 11648
diff changeset
    95
         {'action': 'store_true',
11648
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
    96
          'default': False,
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
    97
          'help': 'Enable profiling'}),
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
    98
        ('profile-output',
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
    99
         {'type': 'string',
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   100
          'default': None,
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   101
          'help': 'Profiling output file (default: "program.prof")'}),
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   102
        ('profile-dump-every',
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   103
         {'type': 'int',
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   104
          'default': None,
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   105
          'metavar': 'N',
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   106
          'help': 'Dump profile stats to ouput every N requests '
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   107
                  '(default: 100)'}),
11813
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   108
        ('param',
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   109
         {'short': 'p',
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   110
          'type': 'named',
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   111
          'metavar': 'key1:value1,key2:value2',
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   112
          'default': {},
8a04a2cb5ba4 [pyramid] No more need to check CW version since it's now shipped with it
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11681
diff changeset
   113
          'help': 'override <key> configuration file option with <value>.'}),
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   114
    )
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   115
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   116
    _reloader_environ_key = 'CW_RELOADER_SHOULD_RUN'
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   117
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   118
    def debug(self, msg):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   119
        print('DEBUG - %s' % msg)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   120
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   121
    def info(self, msg):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   122
        print('INFO - %s' % msg)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   123
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   124
    def quote_first_command_arg(self, arg):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   125
        """
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   126
        There's a bug in Windows when running an executable that's
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   127
        located inside a path with a space in it.  This method handles
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   128
        that case, or on non-Windows systems or an executable with no
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   129
        spaces, it just leaves well enough alone.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   130
        """
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   131
        if (sys.platform != 'win32' or ' ' not in arg):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   132
            # Problem does not apply:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   133
            return arg
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   134
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   135
            import win32api
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   136
        except ImportError:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   137
            raise ValueError(
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   138
                "The executable %r contains a space, and in order to "
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   139
                "handle this issue you must have the win32api module "
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   140
                "installed" % arg)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   141
        arg = win32api.GetShortPathName(arg)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   142
        return arg
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   143
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   144
    def _remove_pid_file(self, written_pid, filename):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   145
        current_pid = os.getpid()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   146
        if written_pid != current_pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   147
            # A forked process must be exiting, not the process that
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   148
            # wrote the PID file
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   149
            return
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   150
        if not os.path.exists(filename):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   151
            return
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   152
        with open(filename) as f:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   153
            content = f.read().strip()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   154
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   155
            pid_in_file = int(content)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   156
        except ValueError:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   157
            pass
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   158
        else:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   159
            if pid_in_file != current_pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   160
                msg = "PID file %s contains %s, not expected PID %s"
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   161
                self.out(msg % (filename, pid_in_file, current_pid))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   162
                return
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   163
        self.info("Removing PID file %s" % filename)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   164
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   165
            os.unlink(filename)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   166
            return
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   167
        except OSError as e:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   168
            # Record, but don't give traceback
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   169
            self.out("Cannot remove PID file: (%s)" % e)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   170
        # well, at least lets not leave the invalid PID around...
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   171
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   172
            with open(filename, 'w') as f:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   173
                f.write('')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   174
        except OSError as e:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   175
            self.out('Stale PID left in file: %s (%s)' % (filename, e))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   176
        else:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   177
            self.out('Stale PID removed')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   178
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   179
    def record_pid(self, pid_file):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   180
        pid = os.getpid()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   181
        self.debug('Writing PID %s to %s' % (pid, pid_file))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   182
        with open(pid_file, 'w') as f:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   183
            f.write(str(pid))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   184
        atexit.register(
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   185
            self._remove_pid_file, pid, pid_file)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   186
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   187
    def daemonize(self, pid_file):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   188
        pid = live_pidfile(pid_file)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   189
        if pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   190
            raise ExecutionError(
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   191
                "Daemon is already running (PID: %s from PID file %s)"
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   192
                % (pid, pid_file))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   193
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   194
        self.debug('Entering daemon mode')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   195
        pid = os.fork()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   196
        if pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   197
            # The forked process also has a handle on resources, so we
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   198
            # *don't* want proper termination of the process, we just
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   199
            # want to exit quick (which os._exit() does)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   200
            os._exit(0)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   201
        # Make this the session leader
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   202
        os.setsid()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   203
        # Fork again for good measure!
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   204
        pid = os.fork()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   205
        if pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   206
            os._exit(0)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   207
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   208
        # @@: Should we set the umask and cwd now?
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   209
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   210
        import resource  # Resource usage information.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   211
        maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   212
        if (maxfd == resource.RLIM_INFINITY):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   213
            maxfd = MAXFD
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   214
        # Iterate through and close all file descriptors.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   215
        for fd in range(0, maxfd):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   216
            try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   217
                os.close(fd)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   218
            except OSError:  # ERROR, fd wasn't open to begin with (ignored)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   219
                pass
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   220
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   221
        if (hasattr(os, "devnull")):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   222
            REDIRECT_TO = os.devnull
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   223
        else:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   224
            REDIRECT_TO = "/dev/null"
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   225
        os.open(REDIRECT_TO, os.O_RDWR)  # standard input (0)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   226
        # Duplicate standard input to standard output and standard error.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   227
        os.dup2(0, 1)  # standard output (1)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   228
        os.dup2(0, 2)  # standard error (2)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   229
11817
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   230
    def restart_with_reloader(self, filelist_path):
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   231
        self.debug('Starting subprocess with file monitor')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   232
11817
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   233
        # Create or clear monitored files list file.
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   234
        with open(filelist_path, 'w') as f:
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   235
            pass
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   236
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   237
        while True:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   238
            args = [self.quote_first_command_arg(sys.executable)] + sys.argv
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   239
            new_environ = os.environ.copy()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   240
            new_environ[self._reloader_environ_key] = 'true'
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   241
            proc = None
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   242
            try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   243
                try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   244
                    proc = subprocess.Popen(args, env=new_environ)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   245
                    exit_code = proc.wait()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   246
                    proc = None
11663
6fb9d9276880 [ccplugin] print_function
Julien Cristau <julien.cristau@logilab.fr>
parents: 11658
diff changeset
   247
                    print("Process exited with", exit_code)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   248
                except KeyboardInterrupt:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   249
                    self.info('^C caught in monitor process')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   250
                    return 1
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   251
            finally:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   252
                if proc is not None:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   253
                    proc.terminate()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   254
                    self.info(
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   255
                        'Waiting for the server to stop. Hit CTRL-C to exit')
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   256
                    exit_code = proc.wait()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   257
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   258
            if exit_code != 3:
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   259
                with open(filelist_path) as f:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   260
                    filelist = [line.strip() for line in f]
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   261
                if filelist:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   262
                    self.info("Reloading failed. Waiting for a file to change")
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   263
                    mon = Monitor(extra_files=filelist, nomodules=True)
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   264
                    while mon.check_reload():
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   265
                        time.sleep(1)
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   266
                else:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   267
                    return exit_code
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   268
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   269
            self.info('%s %s %s' % ('-' * 20, 'Restarting', '-' * 20))
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   270
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   271
    def set_needreload(self):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   272
        self._needreload = True
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   273
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   274
    def install_reloader(self, poll_interval, extra_files, filelist_path):
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   275
        mon = Monitor(
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   276
            poll_interval=poll_interval, extra_files=extra_files,
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   277
            atexit=self.set_needreload, filelist_path=filelist_path)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   278
        mon_thread = threading.Thread(target=mon.periodic_reload)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   279
        mon_thread.daemon = True
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   280
        mon_thread.start()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   281
11647
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   282
    def configfiles(self, cwconfig):
11679
04b127f7ba4e [ccplugin] docstring clarification
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11672
diff changeset
   283
        """Generate instance configuration filenames"""
11647
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   284
        yield cwconfig.main_config_file()
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   285
        for f in (
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   286
                'sources', 'logging.conf', 'pyramid.ini', 'pyramid-debug.ini'):
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   287
            f = os.path.join(cwconfig.apphome, f)
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   288
            if os.path.exists(f):
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   289
                yield f
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   290
11639
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   291
    def i18nfiles(self, cwconfig):
11647
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   292
        """Generate instance i18n files"""
11639
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   293
        i18ndir = os.path.join(cwconfig.apphome, 'i18n')
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   294
        if os.path.exists(i18ndir):
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   295
            for lang in cwconfig.available_languages():
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   296
                f = os.path.join(i18ndir, lang, 'LC_MESSAGES', 'cubicweb.mo')
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   297
                if os.path.exists(f):
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   298
                    yield f
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   299
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   300
    def pyramid_instance(self, appid):
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   301
        self._needreload = False
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   302
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   303
        debugmode = self['debug-mode'] or self['debug']
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   304
        autoreload = self['reload'] or self['debug']
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   305
        daemonize = not (self['no-daemon'] or debugmode or autoreload)
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   306
11817
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   307
        cwconfig = cwcfg.config_for(appid, debugmode=debugmode)
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   308
        filelist_path = os.path.join(cwconfig.apphome,
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   309
                                     '.pyramid-reload-files.list')
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   310
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   311
        if autoreload and not os.environ.get(self._reloader_environ_key):
11817
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   312
            return self.restart_with_reloader(filelist_path)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   313
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   314
        if autoreload:
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   315
            _turn_sigterm_into_systemexit()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   316
            self.debug('Running reloading file monitor')
11647
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   317
            extra_files = [sys.argv[0]]
7f2cfe9f79cb Monitor more configuration files
Christophe de Vienne <christophe@unlish.com>
parents: 11645
diff changeset
   318
            extra_files.extend(self.configfiles(cwconfig))
11639
f38ec5e29de3 Watch for i18n files changes for auto-reload
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11638
diff changeset
   319
            extra_files.extend(self.i18nfiles(cwconfig))
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   320
            self.install_reloader(
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   321
                self['reload-interval'], extra_files,
11817
48f6ebd33cb9 [pyramid] Install file listing monitored files in application home
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11814
diff changeset
   322
                filelist_path=filelist_path)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   323
11645
2a949974002d --debug now activates all debug options
Christophe de Vienne <christophe@unlish.com>
parents: 11644
diff changeset
   324
        if daemonize:
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   325
            self.daemonize(cwconfig['pid-file'])
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   326
            self.record_pid(cwconfig['pid-file'])
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   327
11672
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
   328
        if self['dbglevel']:
2018cdf2909e [cc] add a dbglevel cmdline option to specify the DBG_XXX flags to set
David Douard <david.douard@logilab.fr>
parents: 11664
diff changeset
   329
            self['loglevel'] = 'debug'
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
   330
            set_debug('|'.join('DBG_' + x.upper() for x in self['dbglevel']))
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   331
        init_cmdline_log_threshold(cwconfig, self['loglevel'])
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   332
11648
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   333
        app = wsgi_application_from_cwconfig(
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   334
            cwconfig, profile=self['profile'],
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   335
            profile_output=self['profile-output'],
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   336
            profile_dump_every=self['profile-dump-every']
9a112017974a Add profiling options
Christophe de Vienne <christophe@unlish.com>
parents: 11647
diff changeset
   337
        )
11640
e45e4999dc98 Use 'wsgicors' for CORS handling.
Christophe de Vienne <christophe@unlish.com>
parents: 11639
diff changeset
   338
11652
e95725d7ce90 Allow to override config file options by cmdline arguments (closes #5724484)
David Douard <david.douard@logilab.fr>
parents: 11648
diff changeset
   339
        host = cwconfig['interface']
e95725d7ce90 Allow to override config file options by cmdline arguments (closes #5724484)
David Douard <david.douard@logilab.fr>
parents: 11648
diff changeset
   340
        port = cwconfig['port'] or 8080
11664
7567e99d6ed5 [ccplugin] get the cw repo from the wsgi app
Julien Cristau <julien.cristau@logilab.fr>
parents: 11663
diff changeset
   341
        repo = app.application.registry['cubicweb.repository']
12003
5236ce988805 [pyramid] Drop call to repository's start_looping_tasks method and warn about this
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11967
diff changeset
   342
        warnings.warn(
5236ce988805 [pyramid] Drop call to repository's start_looping_tasks method and warn about this
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11967
diff changeset
   343
            'the "pyramid" command does not start repository "looping tasks" '
5236ce988805 [pyramid] Drop call to repository's start_looping_tasks method and warn about this
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11967
diff changeset
   344
            'anymore; use the standalone "scheduler" command if needed'
5236ce988805 [pyramid] Drop call to repository's start_looping_tasks method and warn about this
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11967
diff changeset
   345
        )
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   346
        try:
11640
e45e4999dc98 Use 'wsgicors' for CORS handling.
Christophe de Vienne <christophe@unlish.com>
parents: 11639
diff changeset
   347
            waitress.serve(app, host=host, port=port)
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   348
        finally:
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   349
            repo.shutdown()
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   350
        if self._needreload:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   351
            return 3
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   352
        return 0
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   353
11821
7534b32c45e3 Fix (new) flake8 errors
Denis Laxalde <denis.laxalde@logilab.fr>
parents: 11817
diff changeset
   354
11633
ffe4040cf4a2 Implements the 'pyramid' command.
Christophe de Vienne <christophe@unlish.com>
parents:
diff changeset
   355
CWCTL.register(PyramidStartHandler)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   356
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   357
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   358
def live_pidfile(pidfile):  # pragma: no cover
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   359
    """(pidfile:str) -> int | None
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   360
    Returns an int found in the named file, if there is one,
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   361
    and if there is a running process with that process id.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   362
    Return None if no such process exists.
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   363
    """
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   364
    pid = read_pidfile(pidfile)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   365
    if pid:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   366
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   367
            os.kill(int(pid), 0)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   368
            return pid
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   369
        except OSError as e:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   370
            if e.errno == errno.EPERM:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   371
                return pid
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   372
    return None
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   373
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   374
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   375
def read_pidfile(filename):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   376
    if os.path.exists(filename):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   377
        try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   378
            with open(filename) as f:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   379
                content = f.read()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   380
            return int(content.strip())
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   381
        except (ValueError, IOError):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   382
            return None
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   383
    else:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   384
        return None
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   385
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   386
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   387
def _turn_sigterm_into_systemexit():
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
   388
    """Attempts to turn a SIGTERM exception into a SystemExit exception."""
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   389
    try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   390
        import signal
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   391
    except ImportError:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   392
        return
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   393
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   394
    def handle_term(signo, frame):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   395
        raise SystemExit
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   396
    signal.signal(signal.SIGTERM, handle_term)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   397
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   398
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   399
class Monitor(object):
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
   400
    """A file monitor and server stopper.
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   401
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   402
    It is a simplified version of pyramid pserve.Monitor, with little changes:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   403
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   404
    -   The constructor takes extra_files, atexit, nomodules and filelist_path
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   405
    -   The process is stopped by auto-kill with signal SIGTERM
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   406
    """
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
   407
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   408
    def __init__(self, poll_interval=1, extra_files=[], atexit=None,
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   409
                 nomodules=False, filelist_path=None):
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   410
        self.module_mtimes = {}
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   411
        self.keep_running = True
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   412
        self.poll_interval = poll_interval
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   413
        self.extra_files = extra_files
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   414
        self.atexit = atexit
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   415
        self.nomodules = nomodules
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   416
        self.filelist_path = filelist_path
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   417
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   418
    def _exit(self):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   419
        if self.atexit:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   420
            self.atexit()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   421
        os.kill(os.getpid(), signal.SIGTERM)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   422
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   423
    def periodic_reload(self):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   424
        while True:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   425
            if not self.check_reload():
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   426
                self._exit()
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   427
                break
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   428
            time.sleep(self.poll_interval)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   429
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   430
    def check_reload(self):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   431
        filenames = list(self.extra_files)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   432
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   433
        if not self.nomodules:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   434
            for module in list(sys.modules.values()):
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   435
                try:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   436
                    filename = module.__file__
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   437
                except (AttributeError, ImportError):
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   438
                    continue
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   439
                if filename is not None:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   440
                    filenames.append(filename)
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   441
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   442
        for filename in filenames:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   443
            try:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   444
                stat = os.stat(filename)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   445
                if stat:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   446
                    mtime = stat.st_mtime
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   447
                else:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   448
                    mtime = 0
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   449
            except (OSError, IOError):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   450
                continue
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   451
            if filename.endswith('.pyc') and os.path.exists(filename[:-1]):
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   452
                mtime = max(os.stat(filename[:-1]).st_mtime, mtime)
11680
e1caf133b81c [ccplugin] flake8
Arthur Lutz <arthur.lutz@logilab.fr>
parents: 11679
diff changeset
   453
            if filename not in self.module_mtimes:
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   454
                self.module_mtimes[filename] = mtime
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   455
            elif self.module_mtimes[filename] < mtime:
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   456
                print('%s changed; reloading...' % filename)
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   457
                return False
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   458
11638
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   459
        if self.filelist_path:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   460
            with open(self.filelist_path) as f:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   461
                filelist = set((line.strip() for line in f))
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   462
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   463
            filelist.update(filenames)
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   464
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   465
            with open(self.filelist_path, 'w') as f:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   466
                for filename in filelist:
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   467
                    f.write('%s\n' % filename)
12de153c0d0e Auto-reload now survives failed reload
Christophe de Vienne <christophe@unlish.com>
parents: 11637
diff changeset
   468
11637
a9cde6a3394c Implements auto-reload and daemon mode.
Christophe de Vienne <christophe@unlish.com>
parents: 11633
diff changeset
   469
        return True