For now, move the definiions of Result, Input and InputMode from ExecContext into lib.base. Having to import them from the ExecContect module is too heavy-handed for those simple types.
Add wrapper methods get() and put(), plus their wrapped methods _get() and _put(). The wrapped methods have default implementations, using POSIX utilities on the target machine over _run().
ExecContext.create() relies on properly formed URLs with a schema for deciding which backend gets created. Create a Local instance if an URL doesn't have schema.
The Input instance passed as cmd_input to ExecContext.run() and .sudo() currently may be of type str. Allow to pass bytes, too.
At the same time, disallow None to be passed as cmd_input. Force the caller to be more explicit how it wants input to be handled, notably with respect to interactivity.
Along the way fix a bug: Content in cmd_input should result in CallContext.interactive == False but doesn't. Fix that.
To have a pattern in lib.ExecContext and avoid future churn: If a
public wrapper calls a protected method, define the protected
method above the respective wrapper.
- sudo(): Make cmd_input default equal to run(): InputMode.OptInteractive
- CallContext: Expose parameters throw, wd, cmd as properties for
later use
lib.ExecContext.log_delim() logs a header not designed for enclosing command output, and, hence, no footer should be output. This commit suppresses it.
This commit introduces two new types, Input and InputMode. They replace the more error-prone special strings cmd_input could be used with. InputMode is an Enum, and Input can be either IntputMode, a string or None.
Whether or not the CallContext.interactive property should be True or False, and hence, a call should be processed interactively, depends on multiple factors, constituting matrix of options with multiple preferences.
--interactive is the application default and can be true, false,
or auto
- A call can be explicitly invoked as interactive, non-interactive
or auto via the cmd_input parameter to ExecContext.run()
This commit adds more "mode:" options to make the latter more explicit. It takes preference over the global --interactive parameter: Global --interactive is only given a chance to decide if cmd_input is None (default) or mode:opt-interactive.
This commit also fixes a bug: --interactive is ignored because the interactive argument passed to ExecContext's constructor is ignored later on in calls to the wrapped _run() and _sudo() methods.
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.
Take a positional uri argument to the constructor of ExecContext, forcing SSHClient to follow suit. The latter was instantiated with a hostname as only argument up to now, which still works as a special case of an uri.
Add the --verbose global option, which is made available as the App.verbose property.
Some functions still take a verbose parameter, but the type of these parameters is converted from bool to bool|None. The idea is that, if they are None, their verbosity falls back to the global default.
Allow to specify the ExecContext in a call to run_cmd(). This effectively makes run_cmd() an thin wrapper around ExecContext.run(), which is what's going to be used in the future. The wrapper is for backwards-compatibility.
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.