annotate python-daemon-2.0.5/daemon/runner.py @ 45:129ba676fd68

remove more strange xmls
author jingchunzhu <jingchunzhu@gmail.com>
date Mon, 27 Jul 2015 15:39:35 -0700
parents 7ceb967147c3
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
33
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
1 # -*- coding: utf-8 -*-
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
2
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
3 # daemon/runner.py
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
4 # Part of ‘python-daemon’, an implementation of PEP 3143.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
5 #
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
6 # Copyright © 2009–2015 Ben Finney <ben+python@benfinney.id.au>
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
7 # Copyright © 2007–2008 Robert Niederreiter, Jens Klein
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
8 # Copyright © 2003 Clark Evans
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
9 # Copyright © 2002 Noah Spurrier
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
10 # Copyright © 2001 Jürgen Hermann
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
11 #
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
12 # This is free software: you may copy, modify, and/or distribute this work
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
13 # under the terms of the Apache License, version 2.0 as published by the
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
14 # Apache Software Foundation.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
15 # No warranty expressed or implied. See the file ‘LICENSE.ASF-2’ for details.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
16
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
17 """ Daemon runner library.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
18 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
19
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
20 from __future__ import (absolute_import, unicode_literals)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
21
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
22 import sys
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
23 import os
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
24 import signal
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
25 import errno
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
26 try:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
27 # Python 3 standard library.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
28 ProcessLookupError
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
29 except NameError:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
30 # No such class in Python 2.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
31 ProcessLookupError = NotImplemented
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
32
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
33 import lockfile
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
34
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
35 from . import pidfile
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
36 from .daemon import (basestring, unicode)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
37 from .daemon import DaemonContext
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
38 from .daemon import _chain_exception_from_existing_exception_context
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
39
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
40
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
41 class DaemonRunnerError(Exception):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
42 """ Abstract base class for errors from DaemonRunner. """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
43
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
44 def __init__(self, *args, **kwargs):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
45 self._chain_from_context()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
46
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
47 super(DaemonRunnerError, self).__init__(*args, **kwargs)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
48
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
49 def _chain_from_context(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
50 _chain_exception_from_existing_exception_context(self, as_cause=True)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
51
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
52
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
53 class DaemonRunnerInvalidActionError(DaemonRunnerError, ValueError):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
54 """ Raised when specified action for DaemonRunner is invalid. """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
55
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
56 def _chain_from_context(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
57 # This exception is normally not caused by another.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
58 _chain_exception_from_existing_exception_context(self, as_cause=False)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
59
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
60
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
61 class DaemonRunnerStartFailureError(DaemonRunnerError, RuntimeError):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
62 """ Raised when failure starting DaemonRunner. """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
63
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
64
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
65 class DaemonRunnerStopFailureError(DaemonRunnerError, RuntimeError):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
66 """ Raised when failure stopping DaemonRunner. """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
67
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
68
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
69 class DaemonRunner:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
70 """ Controller for a callable running in a separate background process.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
71
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
72 The first command-line argument is the action to take:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
73
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
74 * 'start': Become a daemon and call `app.run()`.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
75 * 'stop': Exit the daemon process specified in the PID file.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
76 * 'restart': Stop, then start.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
77
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
78 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
79
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
80 __metaclass__ = type
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
81
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
82 start_message = "started with pid {pid:d}"
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
83
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
84 def __init__(self, app):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
85 """ Set up the parameters of a new runner.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
86
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
87 :param app: The application instance; see below.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
88 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
89
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
90 The `app` argument must have the following attributes:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
91
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
92 * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem paths
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
93 to open and replace the existing `sys.stdin`, `sys.stdout`,
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
94 `sys.stderr`.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
95
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
96 * `pidfile_path`: Absolute filesystem path to a file that will
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
97 be used as the PID file for the daemon. If ``None``, no PID
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
98 file will be used.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
99
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
100 * `pidfile_timeout`: Used as the default acquisition timeout
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
101 value supplied to the runner's PID lock file.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
102
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
103 * `run`: Callable that will be invoked when the daemon is
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
104 started.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
105
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
106 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
107 self.parse_args()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
108 self.app = app
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
109 self.daemon_context = DaemonContext()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
110 self.daemon_context.stdin = open(app.stdin_path, 'rt')
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
111 self.daemon_context.stdout = open(app.stdout_path, 'w+t')
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
112 self.daemon_context.stderr = open(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
113 app.stderr_path, 'w+t', buffering=0)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
114
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
115 self.pidfile = None
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
116 if app.pidfile_path is not None:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
117 self.pidfile = make_pidlockfile(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
118 app.pidfile_path, app.pidfile_timeout)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
119 self.daemon_context.pidfile = self.pidfile
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
120
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
121 def _usage_exit(self, argv):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
122 """ Emit a usage message, then exit.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
123
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
124 :param argv: The command-line arguments used to invoke the
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
125 program, as a sequence of strings.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
126 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
127
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
128 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
129 progname = os.path.basename(argv[0])
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
130 usage_exit_code = 2
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
131 action_usage = "|".join(self.action_funcs.keys())
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
132 message = "usage: {progname} {usage}".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
133 progname=progname, usage=action_usage)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
134 emit_message(message)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
135 sys.exit(usage_exit_code)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
136
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
137 def parse_args(self, argv=None):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
138 """ Parse command-line arguments.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
139
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
140 :param argv: The command-line arguments used to invoke the
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
141 program, as a sequence of strings.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
142
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
143 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
144
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
145 The parser expects the first argument as the program name, the
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
146 second argument as the action to perform.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
147
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
148 If the parser fails to parse the arguments, emit a usage
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
149 message and exit the program.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
150
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
151 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
152 if argv is None:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
153 argv = sys.argv
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
154
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
155 min_args = 2
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
156 if len(argv) < min_args:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
157 self._usage_exit(argv)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
158
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
159 self.action = unicode(argv[1])
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
160 if self.action not in self.action_funcs:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
161 self._usage_exit(argv)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
162
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
163 def _start(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
164 """ Open the daemon context and run the application.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
165
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
166 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
167 :raises DaemonRunnerStartFailureError: If the PID file cannot
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
168 be locked by this process.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
169
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
170 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
171 if is_pidfile_stale(self.pidfile):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
172 self.pidfile.break_lock()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
173
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
174 try:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
175 self.daemon_context.open()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
176 except lockfile.AlreadyLocked:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
177 error = DaemonRunnerStartFailureError(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
178 "PID file {pidfile.path!r} already locked".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
179 pidfile=self.pidfile))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
180 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
181
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
182 pid = os.getpid()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
183 message = self.start_message.format(pid=pid)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
184 emit_message(message)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
185
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
186 self.app.run()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
187
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
188 def _terminate_daemon_process(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
189 """ Terminate the daemon process specified in the current PID file.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
190
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
191 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
192 :raises DaemonRunnerStopFailureError: If terminating the daemon
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
193 fails with an OS error.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
194
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
195 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
196 pid = self.pidfile.read_pid()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
197 try:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
198 os.kill(pid, signal.SIGTERM)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
199 except OSError as exc:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
200 error = DaemonRunnerStopFailureError(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
201 "Failed to terminate {pid:d}: {exc}".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
202 pid=pid, exc=exc))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
203 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
204
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
205 def _stop(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
206 """ Exit the daemon process specified in the current PID file.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
207
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
208 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
209 :raises DaemonRunnerStopFailureError: If the PID file is not
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
210 already locked.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
211
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
212 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
213 if not self.pidfile.is_locked():
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
214 error = DaemonRunnerStopFailureError(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
215 "PID file {pidfile.path!r} not locked".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
216 pidfile=self.pidfile))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
217 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
218
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
219 if is_pidfile_stale(self.pidfile):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
220 self.pidfile.break_lock()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
221 else:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
222 self._terminate_daemon_process()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
223
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
224 def _restart(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
225 """ Stop, then start.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
226 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
227 self._stop()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
228 self._start()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
229
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
230 action_funcs = {
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
231 'start': _start,
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
232 'stop': _stop,
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
233 'restart': _restart,
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
234 }
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
235
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
236 def _get_action_func(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
237 """ Get the function for the specified action.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
238
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
239 :return: The function object corresponding to the specified
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
240 action.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
241 :raises DaemonRunnerInvalidActionError: if the action is
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
242 unknown.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
243
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
244 The action is specified by the `action` attribute, which is set
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
245 during `parse_args`.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
246
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
247 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
248 try:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
249 func = self.action_funcs[self.action]
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
250 except KeyError:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
251 error = DaemonRunnerInvalidActionError(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
252 "Unknown action: {action!r}".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
253 action=self.action))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
254 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
255 return func
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
256
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
257 def do_action(self):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
258 """ Perform the requested action.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
259
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
260 :return: ``None``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
261
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
262 The action is specified by the `action` attribute, which is set
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
263 during `parse_args`.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
264
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
265 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
266 func = self._get_action_func()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
267 func(self)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
268
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
269
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
270 def emit_message(message, stream=None):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
271 """ Emit a message to the specified stream (default `sys.stderr`). """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
272 if stream is None:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
273 stream = sys.stderr
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
274 stream.write("{message}\n".format(message=message))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
275 stream.flush()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
276
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
277
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
278 def make_pidlockfile(path, acquire_timeout):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
279 """ Make a PIDLockFile instance with the given filesystem path. """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
280 if not isinstance(path, basestring):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
281 error = ValueError("Not a filesystem path: {path!r}".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
282 path=path))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
283 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
284 if not os.path.isabs(path):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
285 error = ValueError("Not an absolute path: {path!r}".format(
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
286 path=path))
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
287 raise error
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
288 lockfile = pidfile.TimeoutPIDLockFile(path, acquire_timeout)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
289
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
290 return lockfile
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
291
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
292
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
293 def is_pidfile_stale(pidfile):
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
294 """ Determine whether a PID file is stale.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
295
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
296 :return: ``True`` iff the PID file is stale; otherwise ``False``.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
297
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
298 The PID file is “stale” if its contents are valid but do not
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
299 match the PID of a currently-running process.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
300
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
301 """
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
302 result = False
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
303
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
304 pidfile_pid = pidfile.read_pid()
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
305 if pidfile_pid is not None:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
306 try:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
307 os.kill(pidfile_pid, signal.SIG_DFL)
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
308 except ProcessLookupError:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
309 # The specified PID does not exist.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
310 result = True
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
311 except OSError as exc:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
312 if exc.errno == errno.ESRCH:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
313 # Under Python 2, process lookup error is an OSError.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
314 # The specified PID does not exist.
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
315 result = True
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
316
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
317 return result
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
318
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
319
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
320 # Local variables:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
321 # coding: utf-8
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
322 # mode: python
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
323 # End:
7ceb967147c3 start xena with no gui
jingchunzhu <jingchunzhu@gmail.com>
parents:
diff changeset
324 # vim: fileencoding=utf-8 filetype=python :