first commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from .base import Script
|
||||
from .base import ScriptDirectory
|
||||
|
||||
__all__ = ["ScriptDirectory", "Script"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
# mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
|
||||
# mypy: no-warn-return-any, allow-any-generics
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Mapping
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
from .. import util
|
||||
from ..util import compat
|
||||
|
||||
|
||||
REVISION_SCRIPT_TOKEN = "REVISION_SCRIPT_FILENAME"
|
||||
|
||||
_registry: dict = {}
|
||||
|
||||
|
||||
def register(name: str) -> Callable:
|
||||
"""A function decorator that will register that function as a write hook.
|
||||
|
||||
See the documentation linked below for an example.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`post_write_hooks_custom`
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def decorate(fn):
|
||||
_registry[name] = fn
|
||||
return fn
|
||||
|
||||
return decorate
|
||||
|
||||
|
||||
def _invoke(
|
||||
name: str, revision: str, options: Mapping[str, Union[str, int]]
|
||||
) -> Any:
|
||||
"""Invokes the formatter registered for the given name.
|
||||
|
||||
:param name: The name of a formatter in the registry
|
||||
:param revision: A :class:`.MigrationRevision` instance
|
||||
:param options: A dict containing kwargs passed to the
|
||||
specified formatter.
|
||||
:raises: :class:`alembic.util.CommandError`
|
||||
"""
|
||||
try:
|
||||
hook = _registry[name]
|
||||
except KeyError as ke:
|
||||
raise util.CommandError(
|
||||
f"No formatter with name '{name}' registered"
|
||||
) from ke
|
||||
else:
|
||||
return hook(revision, options)
|
||||
|
||||
|
||||
def _run_hooks(path: str, hook_config: Mapping[str, str]) -> None:
|
||||
"""Invoke hooks for a generated revision."""
|
||||
|
||||
from .base import _split_on_space_comma
|
||||
|
||||
names = _split_on_space_comma.split(hook_config.get("hooks", ""))
|
||||
|
||||
for name in names:
|
||||
if not name:
|
||||
continue
|
||||
opts = {
|
||||
key[len(name) + 1 :]: hook_config[key]
|
||||
for key in hook_config
|
||||
if key.startswith(name + ".")
|
||||
}
|
||||
opts["_hook_name"] = name
|
||||
try:
|
||||
type_ = opts["type"]
|
||||
except KeyError as ke:
|
||||
raise util.CommandError(
|
||||
f"Key {name}.type is required for post write hook {name!r}"
|
||||
) from ke
|
||||
else:
|
||||
with util.status(
|
||||
f"Running post write hook {name!r}", newline=True
|
||||
):
|
||||
_invoke(type_, path, opts)
|
||||
|
||||
|
||||
def _parse_cmdline_options(cmdline_options_str: str, path: str) -> List[str]:
|
||||
"""Parse options from a string into a list.
|
||||
|
||||
Also substitutes the revision script token with the actual filename of
|
||||
the revision script.
|
||||
|
||||
If the revision script token doesn't occur in the options string, it is
|
||||
automatically prepended.
|
||||
"""
|
||||
if REVISION_SCRIPT_TOKEN not in cmdline_options_str:
|
||||
cmdline_options_str = REVISION_SCRIPT_TOKEN + " " + cmdline_options_str
|
||||
cmdline_options_list = shlex.split(
|
||||
cmdline_options_str, posix=compat.is_posix
|
||||
)
|
||||
cmdline_options_list = [
|
||||
option.replace(REVISION_SCRIPT_TOKEN, path)
|
||||
for option in cmdline_options_list
|
||||
]
|
||||
return cmdline_options_list
|
||||
|
||||
|
||||
@register("console_scripts")
|
||||
def console_scripts(
|
||||
path: str, options: dict, ignore_output: bool = False
|
||||
) -> None:
|
||||
try:
|
||||
entrypoint_name = options["entrypoint"]
|
||||
except KeyError as ke:
|
||||
raise util.CommandError(
|
||||
f"Key {options['_hook_name']}.entrypoint is required for post "
|
||||
f"write hook {options['_hook_name']!r}"
|
||||
) from ke
|
||||
for entry in compat.importlib_metadata_get("console_scripts"):
|
||||
if entry.name == entrypoint_name:
|
||||
impl: Any = entry
|
||||
break
|
||||
else:
|
||||
raise util.CommandError(
|
||||
f"Could not find entrypoint console_scripts.{entrypoint_name}"
|
||||
)
|
||||
cwd: Optional[str] = options.get("cwd", None)
|
||||
cmdline_options_str = options.get("options", "")
|
||||
cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
|
||||
|
||||
kw: Dict[str, Any] = {}
|
||||
if ignore_output:
|
||||
kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
"-c",
|
||||
f"import {impl.module}; {impl.module}.{impl.attr}()",
|
||||
]
|
||||
+ cmdline_options_list,
|
||||
cwd=cwd,
|
||||
**kw,
|
||||
)
|
||||
|
||||
|
||||
@register("exec")
|
||||
def exec_(path: str, options: dict, ignore_output: bool = False) -> None:
|
||||
try:
|
||||
executable = options["executable"]
|
||||
except KeyError as ke:
|
||||
raise util.CommandError(
|
||||
f"Key {options['_hook_name']}.executable is required for post "
|
||||
f"write hook {options['_hook_name']!r}"
|
||||
) from ke
|
||||
cwd: Optional[str] = options.get("cwd", None)
|
||||
cmdline_options_str = options.get("options", "")
|
||||
cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
|
||||
|
||||
kw: Dict[str, Any] = {}
|
||||
if ignore_output:
|
||||
kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
executable,
|
||||
*cmdline_options_list,
|
||||
],
|
||||
cwd=cwd,
|
||||
**kw,
|
||||
)
|
||||
Reference in New Issue
Block a user