aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/application/twist/_options.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/twist/_options.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py3/twisted/application/twist/_options.py')
-rw-r--r--contrib/python/Twisted/py3/twisted/application/twist/_options.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py3/twisted/application/twist/_options.py b/contrib/python/Twisted/py3/twisted/application/twist/_options.py
new file mode 100644
index 0000000000..2bcd207bf4
--- /dev/null
+++ b/contrib/python/Twisted/py3/twisted/application/twist/_options.py
@@ -0,0 +1,207 @@
+# -*- test-case-name: twisted.application.twist.test.test_options -*-
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Command line options for C{twist}.
+"""
+
+import typing
+from sys import stderr, stdout
+from textwrap import dedent
+from typing import Callable, Iterable, Mapping, Optional, Sequence, Tuple, cast
+
+from twisted.copyright import version
+from twisted.internet.interfaces import IReactorCore
+from twisted.logger import (
+ InvalidLogLevelError,
+ LogLevel,
+ jsonFileLogObserver,
+ textFileLogObserver,
+)
+from twisted.plugin import getPlugins
+from twisted.python.usage import Options, UsageError
+from ..reactors import NoSuchReactor, getReactorTypes, installReactor
+from ..runner._exit import ExitStatus, exit
+from ..service import IServiceMaker
+
+openFile = open
+
+
+def _update_doc(opt: Callable[["TwistOptions", str], None], **kwargs: str) -> None:
+ """
+ Update the docstring of a method that implements an option.
+ The string is dedented and the given keyword arguments are substituted.
+ """
+ opt.__doc__ = dedent(opt.__doc__ or "").format(**kwargs)
+
+
+class TwistOptions(Options):
+ """
+ Command line options for C{twist}.
+ """
+
+ defaultReactorName = "default"
+ defaultLogLevel = LogLevel.info
+
+ def __init__(self) -> None:
+ Options.__init__(self)
+
+ self["reactorName"] = self.defaultReactorName
+ self["logLevel"] = self.defaultLogLevel
+ self["logFile"] = stdout
+ # An empty long description is explicitly set here as otherwise
+ # when executing from distributed trial twisted.python.usage will
+ # pull the description from `__main__` which is another entry point.
+ self.longdesc = ""
+
+ def getSynopsis(self) -> str:
+ return f"{Options.getSynopsis(self)} plugin [plugin_options]"
+
+ def opt_version(self) -> "typing.NoReturn":
+ """
+ Print version and exit.
+ """
+ exit(ExitStatus.EX_OK, f"{version}")
+
+ def opt_reactor(self, name: str) -> None:
+ """
+ The name of the reactor to use.
+ (options: {options})
+ """
+ # Actually actually actually install the reactor right at this very
+ # moment, before any other code (for example, a sub-command plugin)
+ # runs and accidentally imports and installs the default reactor.
+ try:
+ self["reactor"] = self.installReactor(name)
+ except NoSuchReactor:
+ raise UsageError(f"Unknown reactor: {name}")
+ else:
+ self["reactorName"] = name
+
+ _update_doc(
+ opt_reactor,
+ options=", ".join(f'"{rt.shortName}"' for rt in getReactorTypes()),
+ )
+
+ def installReactor(self, name: str) -> IReactorCore:
+ """
+ Install the reactor.
+ """
+ if name == self.defaultReactorName:
+ from twisted.internet import reactor
+
+ return cast(IReactorCore, reactor)
+ else:
+ return installReactor(name)
+
+ def opt_log_level(self, levelName: str) -> None:
+ """
+ Set default log level.
+ (options: {options}; default: "{default}")
+ """
+ try:
+ self["logLevel"] = LogLevel.levelWithName(levelName)
+ except InvalidLogLevelError:
+ raise UsageError(f"Invalid log level: {levelName}")
+
+ _update_doc(
+ opt_log_level,
+ options=", ".join(
+ f'"{constant.name}"' for constant in LogLevel.iterconstants()
+ ),
+ default=defaultLogLevel.name,
+ )
+
+ def opt_log_file(self, fileName: str) -> None:
+ """
+ Log to file. ("-" for stdout, "+" for stderr; default: "-")
+ """
+ if fileName == "-":
+ self["logFile"] = stdout
+ return
+
+ if fileName == "+":
+ self["logFile"] = stderr
+ return
+
+ try:
+ self["logFile"] = openFile(fileName, "a")
+ except OSError as e:
+ exit(
+ ExitStatus.EX_IOERR,
+ f"Unable to open log file {fileName!r}: {e}",
+ )
+
+ def opt_log_format(self, format: str) -> None:
+ """
+ Log file format.
+ (options: "text", "json"; default: "text" if the log file is a tty,
+ otherwise "json")
+ """
+ format = format.lower()
+
+ if format == "text":
+ self["fileLogObserverFactory"] = textFileLogObserver
+ elif format == "json":
+ self["fileLogObserverFactory"] = jsonFileLogObserver
+ else:
+ raise UsageError(f"Invalid log format: {format}")
+ self["logFormat"] = format
+
+ _update_doc(opt_log_format)
+
+ def selectDefaultLogObserver(self) -> None:
+ """
+ Set C{fileLogObserverFactory} to the default appropriate for the
+ chosen C{logFile}.
+ """
+ if "fileLogObserverFactory" not in self:
+ logFile = self["logFile"]
+
+ if hasattr(logFile, "isatty") and logFile.isatty():
+ self["fileLogObserverFactory"] = textFileLogObserver
+ self["logFormat"] = "text"
+ else:
+ self["fileLogObserverFactory"] = jsonFileLogObserver
+ self["logFormat"] = "json"
+
+ def parseOptions(self, options: Optional[Sequence[str]] = None) -> None:
+ self.selectDefaultLogObserver()
+
+ Options.parseOptions(self, options=options)
+
+ if "reactor" not in self:
+ self["reactor"] = self.installReactor(self["reactorName"])
+
+ @property
+ def plugins(self) -> Mapping[str, IServiceMaker]:
+ if "plugins" not in self:
+ plugins = {}
+ for plugin in getPlugins(IServiceMaker):
+ plugins[plugin.tapname] = plugin
+ self["plugins"] = plugins
+
+ return cast(Mapping[str, IServiceMaker], self["plugins"])
+
+ @property
+ def subCommands(
+ self,
+ ) -> Iterable[Tuple[str, None, Callable[[IServiceMaker], Options], str]]:
+ plugins = self.plugins
+ for name in sorted(plugins):
+ plugin = plugins[name]
+
+ # Don't pass plugin.options along in order to avoid resolving the
+ # options attribute right away, in case it's a property with a
+ # non-trivial getter (eg, one which imports modules).
+ def options(plugin: IServiceMaker = plugin) -> Options:
+ return cast(Options, plugin.options())
+
+ yield (plugin.tapname, None, options, plugin.description)
+
+ def postOptions(self) -> None:
+ Options.postOptions(self)
+
+ if self.subCommand is None:
+ raise UsageError("No plugin specified.")