lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
2026-03-18 07:09:36 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
2026-03-18 10:22:21 +01:00
|
|
|
import abc, re, sys
|
2026-03-23 12:39:57 +01:00
|
|
|
from enum import Enum, auto
|
|
|
|
|
from typing import NamedTuple, TypeAlias, TYPE_CHECKING
|
2026-03-18 07:09:36 +01:00
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
from typing import Self, Type
|
|
|
|
|
from types import TracebackType
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
|
2026-03-18 10:22:21 +01:00
|
|
|
from .log import *
|
|
|
|
|
|
2026-03-23 12:39:57 +01:00
|
|
|
class InputMode(Enum):
|
|
|
|
|
Interactive = auto()
|
|
|
|
|
NonInteractive = auto()
|
|
|
|
|
OptInteractive = auto()
|
|
|
|
|
Auto = auto()
|
|
|
|
|
|
|
|
|
|
Input: TypeAlias = InputMode | None | str
|
|
|
|
|
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
class Result(NamedTuple):
|
|
|
|
|
|
|
|
|
|
stdout: str|None
|
|
|
|
|
stderr: str|None
|
|
|
|
|
status: int|None
|
|
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
def decode(self, encoding='UTF-8', errors='replace') -> Result:
|
|
|
|
|
return Result(
|
|
|
|
|
self.stdout.decode(encoding, errors=errors) if self.stdout is not None else None,
|
|
|
|
|
self.stderr.decode(encoding, errors=errors) if self.stderr is not None else None,
|
|
|
|
|
self.status
|
|
|
|
|
)
|
|
|
|
|
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
class ExecContext(abc.ABC):
|
|
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
class CallContext:
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
parent: ExecContext,
|
|
|
|
|
title: str,
|
|
|
|
|
cmd: list[str],
|
2026-03-23 12:39:57 +01:00
|
|
|
cmd_input: Input,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
wd: str|None,
|
|
|
|
|
log_prefix: str,
|
|
|
|
|
throw: bool,
|
|
|
|
|
verbose: bool
|
|
|
|
|
) -> None:
|
|
|
|
|
self.__cmd = cmd
|
|
|
|
|
self.__wd = wd
|
|
|
|
|
self.__log_prefix = log_prefix
|
2026-04-14 20:39:11 +02:00
|
|
|
self.__parent = parent
|
|
|
|
|
self.__title = title
|
|
|
|
|
self.__pretty_cmd: str|None = None
|
|
|
|
|
self.__delim = title if title is not None else f'---- {parent.uri}: Running {self.pretty_cmd} -'
|
|
|
|
|
delim_len = 120
|
|
|
|
|
self.__delim += '-' * max(0, delim_len - len(self.__delim))
|
2026-03-21 10:40:37 +01:00
|
|
|
|
|
|
|
|
# -- At the end of this dance, interactive needs to be either True
|
|
|
|
|
# or False
|
|
|
|
|
interactive: bool|None = None
|
|
|
|
|
match cmd_input:
|
2026-03-23 12:39:57 +01:00
|
|
|
case InputMode.Interactive:
|
2026-03-21 10:40:37 +01:00
|
|
|
interactive = True
|
2026-03-23 12:39:57 +01:00
|
|
|
case InputMode.NonInteractive:
|
2026-03-21 10:40:37 +01:00
|
|
|
interactive = False
|
2026-03-23 12:39:57 +01:00
|
|
|
case InputMode.OptInteractive:
|
2026-03-21 10:40:37 +01:00
|
|
|
interactive = parent.interactive
|
2026-03-23 12:39:57 +01:00
|
|
|
case InputMode.Auto:
|
2026-03-21 10:40:37 +01:00
|
|
|
interactive = sys.stdin.isatty()
|
|
|
|
|
if interactive is None:
|
|
|
|
|
interactive = parent.interactive
|
|
|
|
|
if interactive is None:
|
|
|
|
|
interactive = sys.stdin.isatty()
|
|
|
|
|
assert interactive in [ True, False ]
|
|
|
|
|
self.__interactive = interactive
|
|
|
|
|
|
2026-03-23 12:39:57 +01:00
|
|
|
self.__cmd_input = cmd_input if not isinstance(cmd_input, InputMode) else None
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
self.__throw = throw
|
|
|
|
|
self.__verbose = verbose if verbose is not None else parent.verbose_default
|
|
|
|
|
|
|
|
|
|
def __enter__(self) -> CallContext:
|
|
|
|
|
self.log_delim(start=True)
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
def __exit__(
|
|
|
|
|
self,
|
|
|
|
|
exc_type: Type[BaseException]|None,
|
|
|
|
|
exc_value: BaseException|None,
|
|
|
|
|
traceback: TracebackType|None
|
|
|
|
|
) -> bool:
|
|
|
|
|
self.log_delim(start=False)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def log_prefix(self) -> str:
|
|
|
|
|
return self.__log_prefix
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def interactive(self) -> bool:
|
|
|
|
|
return self.__interactive
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def verbose(self) -> bool:
|
|
|
|
|
return self.__verbose
|
|
|
|
|
|
2026-03-23 12:39:57 +01:00
|
|
|
@property
|
|
|
|
|
def cmd_input(self) -> bool:
|
|
|
|
|
return self.__cmd_input
|
|
|
|
|
|
2026-04-14 20:39:11 +02:00
|
|
|
@property
|
|
|
|
|
def throw(self) -> bool:
|
|
|
|
|
return self.__throw
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def wd(self) -> str|None:
|
|
|
|
|
return self.__wd
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def cmd(self) -> list[str]:
|
|
|
|
|
return self.__cmd
|
|
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
@property
|
|
|
|
|
def pretty_cmd(self) -> str:
|
|
|
|
|
if self.__pretty_cmd is None:
|
2026-04-14 20:39:11 +02:00
|
|
|
from .util import pretty_cmd
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
self.__pretty_cmd = pretty_cmd(self.__cmd, self.__wd)
|
|
|
|
|
return self.__pretty_cmd
|
|
|
|
|
|
|
|
|
|
def log(prio: int, *args, **kwargs) -> None:
|
|
|
|
|
log(prio, self.__log_prefix, *args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def log_delim(self, start: bool) -> None:
|
|
|
|
|
if not self.__verbose:
|
|
|
|
|
return None
|
2026-03-27 05:58:50 +01:00
|
|
|
if self.__interactive: # Don't log footer in interative mode
|
|
|
|
|
if start:
|
|
|
|
|
log(NOTICE, self.__delim)
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
return
|
|
|
|
|
delim = ',' + self.__delim + ' >' if start else '`' + self.__delim + ' <'
|
|
|
|
|
log(NOTICE, delim)
|
|
|
|
|
|
|
|
|
|
def check_exit_code(self, result: Result) -> None:
|
|
|
|
|
if result.status == 0:
|
|
|
|
|
return
|
|
|
|
|
if (self.__throw or self.__verbose):
|
|
|
|
|
msg = f'Command exited with status {result.status}: {self.pretty_cmd}'
|
|
|
|
|
if result.stderr:
|
|
|
|
|
msg += ': ' + result.decode().stderr.strip()
|
|
|
|
|
if self.__throw:
|
|
|
|
|
raise RuntimeError(msg)
|
|
|
|
|
|
|
|
|
|
def exception(self, result: Result, e: Exception) -> Result:
|
|
|
|
|
log(ERR, self.__log_prefix, f'Failed to run {self.pretty_cmd}')
|
|
|
|
|
if self.__throw:
|
|
|
|
|
raise e
|
|
|
|
|
return result
|
|
|
|
|
|
2026-03-21 10:40:37 +01:00
|
|
|
def __init__(self, uri: str, interactive: bool|None=None, verbose_default=False):
|
2026-03-18 07:09:01 +01:00
|
|
|
self.__uri = uri
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
self.__interactive = interactive
|
2026-03-06 17:01:05 +01:00
|
|
|
self.__verbose_default = verbose_default
|
|
|
|
|
assert verbose_default is not None
|
|
|
|
|
|
2026-03-18 07:09:01 +01:00
|
|
|
@property
|
|
|
|
|
def uri(self) -> str:
|
|
|
|
|
return self.__uri
|
|
|
|
|
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
@property
|
2026-03-21 10:40:37 +01:00
|
|
|
def interactive(self) -> bool|None:
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
return self.__interactive
|
|
|
|
|
|
2026-03-06 16:50:27 +01:00
|
|
|
@property
|
|
|
|
|
def verbose_default(self) -> bool:
|
|
|
|
|
return self.__verbose_default
|
|
|
|
|
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
@abc.abstractmethod
|
|
|
|
|
async def _run(self, *args, **kwargs) -> Result:
|
|
|
|
|
pass
|
|
|
|
|
|
2026-03-06 11:45:15 +01:00
|
|
|
async def run(
|
|
|
|
|
self,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
cmd: list[str],
|
2026-03-06 11:45:15 +01:00
|
|
|
wd: str|None = None,
|
|
|
|
|
throw: bool = True,
|
2026-03-18 10:22:21 +01:00
|
|
|
verbose: bool|None = None,
|
2026-03-23 12:39:57 +01:00
|
|
|
cmd_input: Input = InputMode.OptInteractive,
|
2026-03-06 11:45:15 +01:00
|
|
|
env: dict[str, str]|None = None,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
title: str=None
|
2026-03-06 11:45:15 +01:00
|
|
|
) -> Result:
|
|
|
|
|
"""
|
|
|
|
|
Run a command asynchronously and return its output
|
|
|
|
|
|
|
|
|
|
Args:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
cmd: Command and arguments
|
2026-03-06 11:45:15 +01:00
|
|
|
wd: Optional working directory
|
|
|
|
|
throw: Raise an exception on non-zero exit status if True
|
|
|
|
|
verbose: Emit log output while the command runs
|
|
|
|
|
cmd_input:
|
2026-03-23 12:39:57 +01:00
|
|
|
- "InputMode.OptInteractive" -> Let --interactive govern how to handle interactivity (default)
|
|
|
|
|
- "InputMode.Interactive" -> Inherit terminal stdin
|
|
|
|
|
- "InputMode.Auto" -> Inherit terminal stdin if it is a TTY
|
|
|
|
|
- "InputMode.NonInteractive" -> stdin from /dev/null
|
|
|
|
|
- None -> Alias for InputMode.NonInteractive
|
|
|
|
|
- otherwise -> Feed cmd_input to stdin
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
env: The environment the command should be run in
|
2026-03-06 11:45:15 +01:00
|
|
|
|
|
|
|
|
Returns:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
A Result instance
|
2026-03-06 11:45:15 +01:00
|
|
|
In PTY mode stderr is always None because PTY merges stdout/stderr.
|
|
|
|
|
"""
|
2026-03-06 17:01:05 +01:00
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
ret = Result(None, None, 1)
|
|
|
|
|
with self.CallContext(self, title=title, cmd=cmd, cmd_input=cmd_input, wd=wd,
|
2026-03-21 10:40:37 +01:00
|
|
|
log_prefix='|', throw=throw, verbose=verbose) as cc:
|
2026-03-18 10:22:21 +01:00
|
|
|
try:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
ret = await self._run(
|
2026-04-14 20:39:11 +02:00
|
|
|
cmd=cc.cmd,
|
2026-03-18 10:22:21 +01:00
|
|
|
wd=wd,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
verbose=cc.verbose,
|
2026-03-23 12:39:57 +01:00
|
|
|
cmd_input=cc.cmd_input,
|
2026-03-18 10:22:21 +01:00
|
|
|
env=env,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
interactive=cc.interactive,
|
2026-04-14 20:39:11 +02:00
|
|
|
log_prefix=cc.log_prefix
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
)
|
2026-03-18 10:22:21 +01:00
|
|
|
except Exception as e:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
return cc.exception(ret, e)
|
|
|
|
|
cc.check_exit_code(ret)
|
|
|
|
|
return ret
|
2026-03-18 10:22:21 +01:00
|
|
|
|
2026-04-14 20:39:11 +02:00
|
|
|
@abc.abstractmethod
|
|
|
|
|
async def _sudo(self, *args, **kwargs) -> Result:
|
|
|
|
|
pass
|
|
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
async def sudo(
|
|
|
|
|
self,
|
|
|
|
|
cmd: list[str],
|
|
|
|
|
mod_env: dict[str, str]|None=None,
|
|
|
|
|
opts: list[str]|None=None,
|
|
|
|
|
wd: str|None = None,
|
|
|
|
|
throw: bool = True,
|
|
|
|
|
verbose: bool|None = None,
|
2026-04-14 20:39:11 +02:00
|
|
|
cmd_input: Input = InputMode.OptInteractive,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
env: dict[str, str]|None = None,
|
|
|
|
|
title: str=None,
|
|
|
|
|
) -> Result:
|
2026-03-18 10:22:21 +01:00
|
|
|
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
ret = Result(None, None, 1)
|
|
|
|
|
if opts is None:
|
|
|
|
|
opts = {}
|
2026-03-21 10:41:21 +01:00
|
|
|
if mod_env is None:
|
|
|
|
|
mod_env = {}
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
with self.CallContext(self, title=title, cmd=cmd, cmd_input=cmd_input, wd=wd,
|
2026-03-21 10:40:37 +01:00
|
|
|
log_prefix='|', throw=throw, verbose=verbose) as cc:
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
try:
|
|
|
|
|
ret = await self._sudo(
|
2026-04-14 20:39:11 +02:00
|
|
|
cmd=cc.cmd,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
mod_env=mod_env,
|
|
|
|
|
opts=opts,
|
|
|
|
|
wd=wd,
|
|
|
|
|
verbose=cc.verbose,
|
2026-03-23 12:39:57 +01:00
|
|
|
cmd_input=cc.cmd_input,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
env=env,
|
|
|
|
|
interactive=cc.interactive,
|
2026-04-14 20:39:11 +02:00
|
|
|
log_prefix=cc.log_prefix,
|
lib.ExecContext: Align .sudo() prototype to .run()
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-19 11:38:16 +01:00
|
|
|
)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return cc.exception(ret, e)
|
|
|
|
|
cc.check_exit_code(ret)
|
|
|
|
|
return ret
|
lib.Distro, ExecContext: Add classes, refactor lib.distro
The code below lib.distro, as left behind by the previous commit, is
geared towards being directly used as a command-line API. This commit
introduces the abstract base class Distro, a proxy for
distribution-specific interactions. The proxy abstracts distro
specifics into an API with proper method prototypes, not
argparse.Namespace contents, and can thus be more easily driven by
arbitrary code.
The Distro class is initialized with a member variable of type
ExecContext, another new class introduced by this commit. It is
designed to abstract the communication channel to the distribution
instance. Currently only one specialization exists, Local, which
interacts with the distribution and root file system it is running
in, but is planned to be subclassed to support interaction via SSH,
serial, chroot, or chains thereof.
Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 17:33:52 +01:00
|
|
|
|
2026-03-18 07:09:36 +01:00
|
|
|
@classmethod
|
|
|
|
|
def create(cls, uri: str, *args, **kwargs) -> Self:
|
|
|
|
|
tokens = re.split(r'://', uri)
|
|
|
|
|
schema = tokens[0]
|
|
|
|
|
match schema:
|
|
|
|
|
case 'local':
|
|
|
|
|
from .ec.Local import Local
|
|
|
|
|
return Local(uri, *args, **kwargs)
|
|
|
|
|
case 'ssh':
|
2026-03-20 12:53:07 +01:00
|
|
|
from .ec.SSHClient import ssh_client
|
2026-03-18 07:09:36 +01:00
|
|
|
return ssh_client(uri, *args, **kwargs)
|
|
|
|
|
case _:
|
|
|
|
|
pass
|
|
|
|
|
raise Exception(f'Can\'t create execution context for {uri} with unknown schema "{schema}"')
|