[actions] allow using actions as 'signals-actions' target
This commit is contained in:
@@ -1057,8 +1057,8 @@ Description
|
|||||||
extractor.*.actions
|
extractor.*.actions
|
||||||
-------------------
|
-------------------
|
||||||
Type
|
Type
|
||||||
* ``object`` (`pattern` -> `action(s)`)
|
* ``object`` (`pattern` -> `Action(s)`_)
|
||||||
* ``list`` of ``lists`` with `pattern` -> `action(s)` pairs as elements
|
* ``list`` of ``lists`` with `pattern` -> `Action(s)`_ pairs as elements
|
||||||
Example
|
Example
|
||||||
.. code:: json
|
.. code:: json
|
||||||
|
|
||||||
@@ -1085,51 +1085,17 @@ Example
|
|||||||
]
|
]
|
||||||
|
|
||||||
Description
|
Description
|
||||||
Perform an ``action`` when logging a message matched by ``pattern``.
|
Perform an Action_ when logging a message matched by ``pattern``.
|
||||||
|
|
||||||
``pattern`` is parsed as severity level (``debug``, ``info``, ``warning``, ``error``, or integer value)
|
``pattern`` is parsed as severity level (``debug``, ``info``, ``warning``, ``error``, or integer value)
|
||||||
followed by an optional `Python Regular Expression <https://docs.python.org/3/library/re.html#regular-expression-syntax>`__
|
followed by an optional
|
||||||
separated by a colon ``:``.
|
`Python Regular Expression <https://docs.python.org/3/library/re.html#regular-expression-syntax>`__
|
||||||
|
separated by a colon ``:``
|
||||||
|
|
||||||
Using ``*`` as `level` or leaving it empty
|
Using ``*`` as `level` or leaving it empty
|
||||||
matches logging messages of all levels
|
matches logging messages of all levels
|
||||||
(e.g. ``*:<re>`` or ``:<re>``).
|
(e.g. ``*:<re>`` or ``:<re>``).
|
||||||
|
|
||||||
``action`` is parsed as action type
|
|
||||||
followed by (optional) arguments.
|
|
||||||
|
|
||||||
It is possible to specify more than one ``action`` per ``pattern``
|
|
||||||
by providing them as a ``list``: ``["<action1>", "<action2>", …]``
|
|
||||||
|
|
||||||
Supported Action Types:
|
|
||||||
|
|
||||||
``status``:
|
|
||||||
| Modify job exit status.
|
|
||||||
| Expected syntax is ``<operator> <value>`` (e.g. ``= 100``).
|
|
||||||
|
|
||||||
Supported operators are
|
|
||||||
``=`` (assignment),
|
|
||||||
``&`` (bitwise AND),
|
|
||||||
``|`` (bitwise OR),
|
|
||||||
``^`` (bitwise XOR).
|
|
||||||
``level``:
|
|
||||||
| Modify severity level of the current logging message.
|
|
||||||
| Can be one of ``debug``, ``info``, ``warning``, ``error`` or an integer value.
|
|
||||||
``print``:
|
|
||||||
Write argument to stdout.
|
|
||||||
``exec``:
|
|
||||||
Run a shell command.
|
|
||||||
``abort``:
|
|
||||||
Stop the current extractor run.
|
|
||||||
``terminate``:
|
|
||||||
Stop the current extractor run, including parent extractors.
|
|
||||||
``restart``:
|
|
||||||
Restart the current extractor run.
|
|
||||||
``wait``:
|
|
||||||
| Sleep for a given Duration_ or
|
|
||||||
| wait until Enter is pressed when no argument was given.
|
|
||||||
``exit``:
|
|
||||||
Exit the program with the given argument as exit status.
|
|
||||||
|
|
||||||
|
|
||||||
extractor.*.postprocessors
|
extractor.*.postprocessors
|
||||||
--------------------------
|
--------------------------
|
||||||
@@ -7942,6 +7908,27 @@ Description
|
|||||||
as signal handler for.
|
as signal handler for.
|
||||||
|
|
||||||
|
|
||||||
|
signals-actions
|
||||||
|
---------------
|
||||||
|
Type
|
||||||
|
``object`` (`signal` -> `Action(s)`_)
|
||||||
|
Example
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"SIGINT" : "flag download = stop",
|
||||||
|
"SIGUSR1": [
|
||||||
|
"print Received SIGUSR1",
|
||||||
|
"exec notify.sh",
|
||||||
|
"exit 127"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Description
|
||||||
|
`Action(s)`_ to perform when a
|
||||||
|
`signal <https://docs.python.org/3/library/signal.html>`__
|
||||||
|
is received.
|
||||||
|
|
||||||
|
|
||||||
subconfigs
|
subconfigs
|
||||||
----------
|
----------
|
||||||
Type
|
Type
|
||||||
@@ -8279,6 +8266,67 @@ Description
|
|||||||
Store files in a ZIP archive
|
Store files in a ZIP archive
|
||||||
|
|
||||||
|
|
||||||
|
Action
|
||||||
|
------
|
||||||
|
Type
|
||||||
|
``string``
|
||||||
|
Example
|
||||||
|
* ``"exit"``
|
||||||
|
* ``"print Hello World"``
|
||||||
|
* ``"raise AbortExtraction an error occured"``
|
||||||
|
* ``"flag file = terminate"``
|
||||||
|
Description
|
||||||
|
An Action_ is parsed as `Action Type`
|
||||||
|
followed by (optional) arguments.
|
||||||
|
|
||||||
|
It is possible to specify more than one ``action``
|
||||||
|
by providing them as a ``list``: ``["<action1>", "<action2>", …]``
|
||||||
|
|
||||||
|
Supported `Action Types`:
|
||||||
|
|
||||||
|
``status``:
|
||||||
|
| Modify job exit status.
|
||||||
|
| Expected syntax is ``<operator> <value>`` (e.g. ``= 100``).
|
||||||
|
|
||||||
|
Supported operators are
|
||||||
|
``=`` (assignment),
|
||||||
|
``&`` (bitwise AND),
|
||||||
|
``|`` (bitwise OR),
|
||||||
|
``^`` (bitwise XOR).
|
||||||
|
``level``:
|
||||||
|
| Modify severity level of the current logging message.
|
||||||
|
| Can be one of ``debug``, ``info``, ``warning``, ``error`` or an integer value.
|
||||||
|
``print``:
|
||||||
|
Write argument to stdout.
|
||||||
|
``exec``:
|
||||||
|
Run a shell command.
|
||||||
|
``abort``:
|
||||||
|
Stop the current extractor run.
|
||||||
|
``terminate``:
|
||||||
|
Stop the current extractor run, including parent extractors.
|
||||||
|
``restart``:
|
||||||
|
Restart the current extractor run.
|
||||||
|
``raise``:
|
||||||
|
Raise an exception.
|
||||||
|
|
||||||
|
This can be an exception defined in
|
||||||
|
`exception.py <https://github.com/mikf/gallery-dl/blob/master/gallery_dl/exception.py>`_
|
||||||
|
or a
|
||||||
|
`built-in exception <https://docs.python.org/3/library/exceptions.html#exception-hierarchy>`_
|
||||||
|
(e.g. ``ZeroDivisionError``)
|
||||||
|
``flag``:
|
||||||
|
Set a ``flag``.
|
||||||
|
|
||||||
|
| Expected syntax is ``<flag>[ = <value>]`` (e.g. ``post = stop``)
|
||||||
|
| ``<flag>`` can be one of ``file``, ``post``, ``child``, ``download``
|
||||||
|
| ``<value>`` can be one of ``stop``, ``abort``, ``terminate``, ``restart`` (default ``stop``)
|
||||||
|
``wait``:
|
||||||
|
| Sleep for a given Duration_ or
|
||||||
|
| wait until Enter is pressed when no argument was given.
|
||||||
|
``exit``:
|
||||||
|
Exit the program with the given argument as exit status.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. |ytdl| replace:: `yt-dlp`_/`youtube-dl`_
|
.. |ytdl| replace:: `yt-dlp`_/`youtube-dl`_
|
||||||
.. |ytdl's| replace:: yt-dlp's/youtube-dl's
|
.. |ytdl's| replace:: yt-dlp's/youtube-dl's
|
||||||
@@ -8311,6 +8359,7 @@ Description
|
|||||||
.. _deviantart.comments: `extractor.deviantart.comments`_
|
.. _deviantart.comments: `extractor.deviantart.comments`_
|
||||||
.. _postprocessors: `extractor.*.postprocessors`_
|
.. _postprocessors: `extractor.*.postprocessors`_
|
||||||
.. _download archive: `extractor.*.archive`_
|
.. _download archive: `extractor.*.archive`_
|
||||||
|
.. _Action(s): Action_
|
||||||
|
|
||||||
.. _.netrc: https://stackoverflow.com/tags/.netrc/info
|
.. _.netrc: https://stackoverflow.com/tags/.netrc/info
|
||||||
.. _Last-Modified: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29
|
.. _Last-Modified: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29
|
||||||
|
|||||||
@@ -90,23 +90,8 @@ def main():
|
|||||||
signal.signal(signal_num, signal.SIG_IGN)
|
signal.signal(signal_num, signal.SIG_IGN)
|
||||||
|
|
||||||
if signals := config.get((), "signals-actions"):
|
if signals := config.get((), "signals-actions"):
|
||||||
import signal
|
from . import actions
|
||||||
|
actions.parse_signals(signals)
|
||||||
def signals_handler(event, action):
|
|
||||||
def handler(signal_num, frame):
|
|
||||||
signal_name = signal.Signals(signal_num).name
|
|
||||||
output.stderr_write(f"{signal_name} received\n")
|
|
||||||
util.FLAGS.__dict__[event] = action
|
|
||||||
return handler
|
|
||||||
|
|
||||||
for signal_name, action in signals.items():
|
|
||||||
signal_num = getattr(signal, signal_name, None)
|
|
||||||
if signal_num is None:
|
|
||||||
log.warning("signal '%s' is not defined", signal_name)
|
|
||||||
else:
|
|
||||||
event, _, action = action.rpartition(":")
|
|
||||||
signal.signal(signal_num, signals_handler(
|
|
||||||
event.upper() if event else "FILE", action.lower()))
|
|
||||||
|
|
||||||
# enable ANSI escape sequences on Windows
|
# enable ANSI escape sequences on Windows
|
||||||
if util.WINDOWS and config.get(("output",), "ansi", output.COLORS):
|
if util.WINDOWS and config.get(("output",), "ansi", output.COLORS):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import functools
|
|||||||
from . import util, exception
|
from . import util, exception
|
||||||
|
|
||||||
|
|
||||||
def parse(actionspec):
|
def parse_logging(actionspec):
|
||||||
if isinstance(actionspec, dict):
|
if isinstance(actionspec, dict):
|
||||||
actionspec = actionspec.items()
|
actionspec = actionspec.items()
|
||||||
|
|
||||||
@@ -73,6 +73,41 @@ def parse(actionspec):
|
|||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
def parse_signals(actionspec):
|
||||||
|
import signal
|
||||||
|
|
||||||
|
if isinstance(actionspec, dict):
|
||||||
|
actionspec = actionspec.items()
|
||||||
|
|
||||||
|
for signal_name, spec in actionspec:
|
||||||
|
signal_num = getattr(signal, signal_name, None)
|
||||||
|
if signal_num is None:
|
||||||
|
log = logging.getLogger("gallery-dl")
|
||||||
|
log.warning("signal '%s' is not defined", signal_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(spec, str):
|
||||||
|
type, _, args = spec.partition(" ")
|
||||||
|
before, after = ACTIONS[type](args)
|
||||||
|
action = before if after is None else after
|
||||||
|
else:
|
||||||
|
actions_before = []
|
||||||
|
actions_after = []
|
||||||
|
for s in spec:
|
||||||
|
type, _, args = s.partition(" ")
|
||||||
|
before, after = ACTIONS[type](args)
|
||||||
|
if before is not None:
|
||||||
|
actions_before.append(before)
|
||||||
|
if after is not None:
|
||||||
|
actions_after.append(after)
|
||||||
|
|
||||||
|
actions = actions_before
|
||||||
|
actions.extend(actions_after)
|
||||||
|
action = _chain_actions(actions)
|
||||||
|
|
||||||
|
signal.signal(signal_num, signals_handler(action))
|
||||||
|
|
||||||
|
|
||||||
class LoggerAdapter():
|
class LoggerAdapter():
|
||||||
|
|
||||||
def __init__(self, logger, job):
|
def __init__(self, logger, job):
|
||||||
@@ -128,6 +163,12 @@ def _chain_actions(actions):
|
|||||||
return _chain
|
return _chain
|
||||||
|
|
||||||
|
|
||||||
|
def signals_handler(action, args={}):
|
||||||
|
def handler(signal_num, frame):
|
||||||
|
action(args)
|
||||||
|
return handler
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
def action_print(opts):
|
def action_print(opts):
|
||||||
|
|||||||
Reference in New Issue
Block a user