diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py2/twisted/application/runner | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py2/twisted/application/runner')
4 files changed, 633 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py2/twisted/application/runner/__init__.py b/contrib/python/Twisted/py2/twisted/application/runner/__init__.py new file mode 100644 index 0000000000..6da0ac04e7 --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/application/runner/__init__.py @@ -0,0 +1,7 @@ +# -*- test-case-name: twisted.application.runner.test -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Facilities for running a Twisted application. +""" diff --git a/contrib/python/Twisted/py2/twisted/application/runner/_exit.py b/contrib/python/Twisted/py2/twisted/application/runner/_exit.py new file mode 100644 index 0000000000..ffccc417bd --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/application/runner/_exit.py @@ -0,0 +1,138 @@ +# -*- test-case-name: twisted.application.runner.test.test_exit -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +System exit support. +""" + +from sys import stdout, stderr, exit as sysexit + +from constantly import Values, ValueConstant + + + +def exit(status, message=None): + """ + Exit the python interpreter with the given status and an optional message. + + @param status: An exit status. + @type status: L{int} or L{ValueConstant} from L{ExitStatus}. + + @param message: An options message to print. + @type status: L{str} + """ + if isinstance(status, ValueConstant): + code = status.value + else: + code = int(status) + + if message: + if code == 0: + out = stdout + else: + out = stderr + out.write(message) + out.write("\n") + + sysexit(code) + + + +try: + import posix as Status +except ImportError: + class Status(object): + """ + Object to hang C{EX_*} values off of as a substitute for L{posix}. + """ + EX__BASE = 64 + + EX_OK = 0 + EX_USAGE = EX__BASE + EX_DATAERR = EX__BASE + 1 + EX_NOINPUT = EX__BASE + 2 + EX_NOUSER = EX__BASE + 3 + EX_NOHOST = EX__BASE + 4 + EX_UNAVAILABLE = EX__BASE + 5 + EX_SOFTWARE = EX__BASE + 6 + EX_OSERR = EX__BASE + 7 + EX_OSFILE = EX__BASE + 8 + EX_CANTCREAT = EX__BASE + 9 + EX_IOERR = EX__BASE + 10 + EX_TEMPFAIL = EX__BASE + 11 + EX_PROTOCOL = EX__BASE + 12 + EX_NOPERM = EX__BASE + 13 + EX_CONFIG = EX__BASE + 14 + + + +class ExitStatus(Values): + """ + Standard exit status codes for system programs. + + @cvar EX_OK: Successful termination. + @type EX_OK: L{ValueConstant} + + @cvar EX_USAGE: Command line usage error. + @type EX_USAGE: L{ValueConstant} + + @cvar EX_DATAERR: Data format error. + @type EX_DATAERR: L{ValueConstant} + + @cvar EX_NOINPUT: Cannot open input. + @type EX_NOINPUT: L{ValueConstant} + + @cvar EX_NOUSER: Addressee unknown. + @type EX_NOUSER: L{ValueConstant} + + @cvar EX_NOHOST: Host name unknown. + @type EX_NOHOST: L{ValueConstant} + + @cvar EX_UNAVAILABLE: Service unavailable. + @type EX_UNAVAILABLE: L{ValueConstant} + + @cvar EX_SOFTWARE: Internal software error. + @type EX_SOFTWARE: L{ValueConstant} + + @cvar EX_OSERR: System error (e.g., can't fork). + @type EX_OSERR: L{ValueConstant} + + @cvar EX_OSFILE: Critical OS file missing. + @type EX_OSFILE: L{ValueConstant} + + @cvar EX_CANTCREAT: Can't create (user) output file. + @type EX_CANTCREAT: L{ValueConstant} + + @cvar EX_IOERR: Input/output error. + @type EX_IOERR: L{ValueConstant} + + @cvar EX_TEMPFAIL: Temporary failure; the user is invited to retry. + @type EX_TEMPFAIL: L{ValueConstant} + + @cvar EX_PROTOCOL: Remote error in protocol. + @type EX_PROTOCOL: L{ValueConstant} + + @cvar EX_NOPERM: Permission denied. + @type EX_NOPERM: L{ValueConstant} + + @cvar EX_CONFIG: Configuration error. + @type EX_CONFIG: L{ValueConstant} + """ + + EX_OK = ValueConstant(Status.EX_OK) + EX_USAGE = ValueConstant(Status.EX_USAGE) + EX_DATAERR = ValueConstant(Status.EX_DATAERR) + EX_NOINPUT = ValueConstant(Status.EX_NOINPUT) + EX_NOUSER = ValueConstant(Status.EX_NOUSER) + EX_NOHOST = ValueConstant(Status.EX_NOHOST) + EX_UNAVAILABLE = ValueConstant(Status.EX_UNAVAILABLE) + EX_SOFTWARE = ValueConstant(Status.EX_SOFTWARE) + EX_OSERR = ValueConstant(Status.EX_OSERR) + EX_OSFILE = ValueConstant(Status.EX_OSFILE) + EX_CANTCREAT = ValueConstant(Status.EX_CANTCREAT) + EX_IOERR = ValueConstant(Status.EX_IOERR) + EX_TEMPFAIL = ValueConstant(Status.EX_TEMPFAIL) + EX_PROTOCOL = ValueConstant(Status.EX_PROTOCOL) + EX_NOPERM = ValueConstant(Status.EX_NOPERM) + EX_CONFIG = ValueConstant(Status.EX_CONFIG) diff --git a/contrib/python/Twisted/py2/twisted/application/runner/_pidfile.py b/contrib/python/Twisted/py2/twisted/application/runner/_pidfile.py new file mode 100644 index 0000000000..50b8aed68d --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/application/runner/_pidfile.py @@ -0,0 +1,303 @@ +# -*- test-case-name: twisted.application.runner.test.test_pidfile -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +PID file. +""" + +import errno +from os import getpid, kill, name as SYSTEM_NAME + +from zope.interface import Interface, implementer + +from twisted.logger import Logger + + + +class IPIDFile(Interface): + """ + Manages a file that remembers a process ID. + """ + + def read(): + """ + Read the process ID stored in this PID file. + + @return: The contained process ID. + @rtype: L{int} + + @raise NoPIDFound: If this PID file does not exist. + @raise EnvironmentError: If this PID file cannot be read. + @raise ValueError: If this PID file's content is invalid. + """ + + + def writeRunningPID(): + """ + Store the PID of the current process in this PID file. + + @raise EnvironmentError: If this PID file cannot be written. + """ + + + def remove(): + """ + Remove this PID file. + + @raise EnvironmentError: If this PID file cannot be removed. + """ + + + def isRunning(): + """ + Determine whether there is a running process corresponding to the PID + in this PID file. + + @return: True if this PID file contains a PID and a process with that + PID is currently running; false otherwise. + @rtype: L{bool} + + @raise EnvironmentError: If this PID file cannot be read. + @raise InvalidPIDFileError: If this PID file's content is invalid. + @raise StalePIDFileError: If this PID file's content refers to a PID + for which there is no corresponding running process. + """ + + + def __enter__(): + """ + Enter a context using this PIDFile. + + Writes the PID file with the PID of the running process. + + @raise AlreadyRunningError: A process corresponding to the PID in this + PID file is already running. + """ + + + def __exit__(excType, excValue, traceback): + """ + Exit a context using this PIDFile. + + Removes the PID file. + """ + + + +@implementer(IPIDFile) +class PIDFile(object): + """ + Concrete implementation of L{IPIDFile} based on C{IFilePath}. + + This implementation is presently not supported on non-POSIX platforms. + Specifically, calling L{PIDFile.isRunning} will raise + L{NotImplementedError}. + """ + + _log = Logger() + + + @staticmethod + def _format(pid): + """ + Format a PID file's content. + + @param pid: A process ID. + @type pid: int + + @return: Formatted PID file contents. + @rtype: L{bytes} + """ + return u"{}\n".format(int(pid)).encode("utf-8") + + + def __init__(self, filePath): + """ + @param filePath: The path to the PID file on disk. + @type filePath: L{IFilePath} + """ + self.filePath = filePath + + + def read(self): + pidString = b"" + try: + with self.filePath.open() as fh: + for pidString in fh: + break + except OSError as e: + if e.errno == errno.ENOENT: # No such file + raise NoPIDFound("PID file does not exist") + raise + + try: + return int(pidString) + except ValueError: + raise InvalidPIDFileError( + "non-integer PID value in PID file: {!r}".format(pidString) + ) + + + def _write(self, pid): + """ + Store a PID in this PID file. + + @param pid: A PID to store. + @type pid: L{int} + + @raise EnvironmentError: If this PID file cannot be written. + """ + self.filePath.setContent(self._format(pid=pid)) + + + def writeRunningPID(self): + self._write(getpid()) + + + def remove(self): + self.filePath.remove() + + + def isRunning(self): + try: + pid = self.read() + except NoPIDFound: + return False + + if SYSTEM_NAME == "posix": + return self._pidIsRunningPOSIX(pid) + else: + raise NotImplementedError( + "isRunning is not implemented on {}".format(SYSTEM_NAME) + ) + + + @staticmethod + def _pidIsRunningPOSIX(pid): + """ + POSIX implementation for running process check. + + Determine whether there is a running process corresponding to the given + PID. + + @return: True if the given PID is currently running; false otherwise. + @rtype: L{bool} + + @raise EnvironmentError: If this PID file cannot be read. + @raise InvalidPIDFileError: If this PID file's content is invalid. + @raise StalePIDFileError: If this PID file's content refers to a PID + for which there is no corresponding running process. + """ + try: + kill(pid, 0) + except OSError as e: + if e.errno == errno.ESRCH: # No such process + raise StalePIDFileError( + "PID file refers to non-existing process" + ) + elif e.errno == errno.EPERM: # Not permitted to kill + return True + else: + raise + else: + return True + + + def __enter__(self): + try: + if self.isRunning(): + raise AlreadyRunningError() + except StalePIDFileError: + self._log.info("Replacing stale PID file: {log_source}") + self.writeRunningPID() + return self + + + def __exit__(self, excType, excValue, traceback): + self.remove() + + + +@implementer(IPIDFile) +class NonePIDFile(object): + """ + PID file implementation that does nothing. + + This is meant to be used as a "active None" object in place of a PID file + when no PID file is desired. + """ + + def __init__(self): + pass + + + def read(self): + raise NoPIDFound("PID file does not exist") + + + def _write(self, pid): + """ + Store a PID in this PID file. + + @param pid: A PID to store. + @type pid: L{int} + + @raise EnvironmentError: If this PID file cannot be written. + + @note: This implementation always raises an L{EnvironmentError}. + """ + raise OSError(errno.EPERM, "Operation not permitted") + + + def writeRunningPID(self): + self._write(0) + + + def remove(self): + raise OSError(errno.ENOENT, "No such file or directory") + + + def isRunning(self): + return False + + + def __enter__(self): + return self + + + def __exit__(self, excType, excValue, traceback): + pass + + + +nonePIDFile = NonePIDFile() + + + +class AlreadyRunningError(Exception): + """ + Process is already running. + """ + + + +class InvalidPIDFileError(Exception): + """ + PID file contents are invalid. + """ + + + +class StalePIDFileError(Exception): + """ + PID file contents are valid, but there is no process with the referenced + PID. + """ + + + +class NoPIDFound(Exception): + """ + No PID found in PID file. + """ diff --git a/contrib/python/Twisted/py2/twisted/application/runner/_runner.py b/contrib/python/Twisted/py2/twisted/application/runner/_runner.py new file mode 100644 index 0000000000..7542a5b9a9 --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/application/runner/_runner.py @@ -0,0 +1,185 @@ +# -*- test-case-name: twisted.application.runner.test.test_runner -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Twisted application runner. +""" + +from sys import stderr +from signal import SIGTERM +from os import kill + +from attr import attrib, attrs, Factory + +from twisted.logger import ( + globalLogBeginner, textFileLogObserver, + FilteringLogObserver, LogLevelFilterPredicate, + LogLevel, Logger, +) + +from ._exit import exit, ExitStatus +from ._pidfile import nonePIDFile, AlreadyRunningError, InvalidPIDFileError + + + +@attrs(frozen=True) +class Runner(object): + """ + Twisted application runner. + + @cvar _log: The logger attached to this class. + @type _log: L{Logger} + + @ivar _reactor: The reactor to start and run the application in. + @type _reactor: L{IReactorCore} + + @ivar _pidFile: The file to store the running process ID in. + @type _pidFile: L{IPIDFile} + + @ivar _kill: Whether this runner should kill an existing running + instance of the application. + @type _kill: L{bool} + + @ivar _defaultLogLevel: The default log level to start the logging + system with. + @type _defaultLogLevel: L{constantly.NamedConstant} from L{LogLevel} + + @ivar _logFile: A file stream to write logging output to. + @type _logFile: writable file-like object + + @ivar _fileLogObserverFactory: A factory for the file log observer to + use when starting the logging system. + @type _pidFile: callable that takes a single writable file-like object + argument and returns a L{twisted.logger.FileLogObserver} + + @ivar _whenRunning: Hook to call after the reactor is running; + this is where the application code that relies on the reactor gets + called. + @type _whenRunning: callable that takes the keyword arguments specified + by C{whenRunningArguments} + + @ivar _whenRunningArguments: Keyword arguments to pass to + C{whenRunning} when it is called. + @type _whenRunningArguments: L{dict} + + @ivar _reactorExited: Hook to call after the reactor exits. + @type _reactorExited: callable that takes the keyword arguments + specified by C{reactorExitedArguments} + + @ivar _reactorExitedArguments: Keyword arguments to pass to + C{reactorExited} when it is called. + @type _reactorExitedArguments: L{dict} + """ + + _log = Logger() + + _reactor = attrib() + _pidFile = attrib(default=nonePIDFile) + _kill = attrib(default=False) + _defaultLogLevel = attrib(default=LogLevel.info) + _logFile = attrib(default=stderr) + _fileLogObserverFactory = attrib(default=textFileLogObserver) + _whenRunning = attrib(default=lambda **_: None) + _whenRunningArguments = attrib(default=Factory(dict)) + _reactorExited = attrib(default=lambda **_: None) + _reactorExitedArguments = attrib(default=Factory(dict)) + + + def run(self): + """ + Run this command. + """ + pidFile = self._pidFile + + self.killIfRequested() + + try: + with pidFile: + self.startLogging() + self.startReactor() + self.reactorExited() + + except AlreadyRunningError: + exit(ExitStatus.EX_CONFIG, "Already running.") + return # When testing, patched exit doesn't exit + + + def killIfRequested(self): + """ + If C{self._kill} is true, attempt to kill a running instance of the + application. + """ + pidFile = self._pidFile + + if self._kill: + if pidFile is nonePIDFile: + exit(ExitStatus.EX_USAGE, "No PID file specified.") + return # When testing, patched exit doesn't exit + + try: + pid = pidFile.read() + except EnvironmentError: + exit(ExitStatus.EX_IOERR, "Unable to read PID file.") + return # When testing, patched exit doesn't exit + except InvalidPIDFileError: + exit(ExitStatus.EX_DATAERR, "Invalid PID file.") + return # When testing, patched exit doesn't exit + + self.startLogging() + self._log.info("Terminating process: {pid}", pid=pid) + + kill(pid, SIGTERM) + + exit(ExitStatus.EX_OK) + return # When testing, patched exit doesn't exit + + + def startLogging(self): + """ + Start the L{twisted.logger} logging system. + """ + logFile = self._logFile + + fileLogObserverFactory = self._fileLogObserverFactory + + fileLogObserver = fileLogObserverFactory(logFile) + + logLevelPredicate = LogLevelFilterPredicate( + defaultLogLevel=self._defaultLogLevel + ) + + filteringObserver = FilteringLogObserver( + fileLogObserver, [logLevelPredicate] + ) + + globalLogBeginner.beginLoggingTo([filteringObserver]) + + + def startReactor(self): + """ + Register C{self._whenRunning} with the reactor so that it is called + once the reactor is running, then start the reactor. + """ + self._reactor.callWhenRunning(self.whenRunning) + + self._log.info("Starting reactor...") + self._reactor.run() + + + def whenRunning(self): + """ + Call C{self._whenRunning} with C{self._whenRunningArguments}. + + @note: This method is called after the reactor starts running. + """ + self._whenRunning(**self._whenRunningArguments) + + + def reactorExited(self): + """ + Call C{self._reactorExited} with C{self._reactorExitedArguments}. + + @note: This method is called after the reactor exits. + """ + self._reactorExited(**self._reactorExitedArguments) |