aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py')
-rw-r--r--contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py282
1 files changed, 282 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py b/contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py
new file mode 100644
index 0000000000..b6aab1499f
--- /dev/null
+++ b/contrib/python/Twisted/py3/twisted/application/runner/_pidfile.py
@@ -0,0 +1,282 @@
+# -*- test-case-name: twisted.application.runner.test.test_pidfile -*-
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+PID file.
+"""
+from __future__ import annotations
+
+import errno
+from os import getpid, kill, name as SYSTEM_NAME
+from types import TracebackType
+from typing import Any, Optional, Type
+
+from zope.interface import Interface, implementer
+
+from twisted.logger import Logger
+from twisted.python.filepath import FilePath
+
+
+class IPIDFile(Interface):
+ """
+ Manages a file that remembers a process ID.
+ """
+
+ def read() -> int:
+ """
+ Read the process ID stored in this PID file.
+
+ @return: The contained process ID.
+
+ @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() -> None:
+ """
+ Store the PID of the current process in this PID file.
+
+ @raise EnvironmentError: If this PID file cannot be written.
+ """
+
+ def remove() -> None:
+ """
+ Remove this PID file.
+
+ @raise EnvironmentError: If this PID file cannot be removed.
+ """
+
+ def isRunning() -> bool:
+ """
+ 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.
+
+ @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__() -> "IPIDFile":
+ """
+ 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: Optional[Type[BaseException]],
+ excValue: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> Optional[bool]:
+ """
+ Exit a context using this PIDFile.
+
+ Removes the PID file.
+ """
+
+
+@implementer(IPIDFile)
+class PIDFile:
+ """
+ Concrete implementation of L{IPIDFile}.
+
+ 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: int) -> bytes:
+ """
+ Format a PID file's content.
+
+ @param pid: A process ID.
+
+ @return: Formatted PID file contents.
+ """
+ return f"{int(pid)}\n".encode()
+
+ def __init__(self, filePath: FilePath[Any]) -> None:
+ """
+ @param filePath: The path to the PID file on disk.
+ """
+ self.filePath = filePath
+
+ def read(self) -> int:
+ 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(
+ f"non-integer PID value in PID file: {pidString!r}"
+ )
+
+ def _write(self, pid: int) -> None:
+ """
+ Store a PID in this PID file.
+
+ @param pid: A PID to store.
+
+ @raise EnvironmentError: If this PID file cannot be written.
+ """
+ self.filePath.setContent(self._format(pid=pid))
+
+ def writeRunningPID(self) -> None:
+ self._write(getpid())
+
+ def remove(self) -> None:
+ self.filePath.remove()
+
+ def isRunning(self) -> bool:
+ try:
+ pid = self.read()
+ except NoPIDFound:
+ return False
+
+ if SYSTEM_NAME == "posix":
+ return self._pidIsRunningPOSIX(pid)
+ else:
+ raise NotImplementedError(f"isRunning is not implemented on {SYSTEM_NAME}")
+
+ @staticmethod
+ def _pidIsRunningPOSIX(pid: int) -> bool:
+ """
+ POSIX implementation for running process check.
+
+ Determine whether there is a running process corresponding to the given
+ PID.
+
+ @param pid: The PID to check.
+
+ @return: True if the given PID is currently running; false otherwise.
+
+ @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) -> "PIDFile":
+ 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: Optional[Type[BaseException]],
+ excValue: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
+ self.remove()
+ return None
+
+
+@implementer(IPIDFile)
+class NonePIDFile:
+ """
+ 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) -> None:
+ pass
+
+ def read(self) -> int:
+ raise NoPIDFound("PID file does not exist")
+
+ def _write(self, pid: int) -> None:
+ """
+ Store a PID in this PID file.
+
+ @param pid: A PID to store.
+
+ @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) -> None:
+ self._write(0)
+
+ def remove(self) -> None:
+ raise OSError(errno.ENOENT, "No such file or directory")
+
+ def isRunning(self) -> bool:
+ return False
+
+ def __enter__(self) -> "NonePIDFile":
+ return self
+
+ def __exit__(
+ self,
+ excType: Optional[Type[BaseException]],
+ excValue: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
+ return None
+
+
+nonePIDFile: IPIDFile = 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.
+ """