Commit graph

36 commits

Author SHA1 Message Date
6df4c86fc5 lib.App: Add property cmdline
Add the property App.cmdline, containing the invoking command line as
a string.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 20:00:30 +01:00
bd38700f67 lib.Distro: Add .id
Allow to query the distribution ID a Distro was instantiated with via
the .id property.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-07 14:35:54 +01:00
67a2931f5e App: Support --verbose
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.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 19:02:22 +01:00
525fa34387 lib.pm: Add parameter ec: ExecContext to functions
Functions in lib.pm (i.e. run_dpkg(), run_rpm() and friends) also get
an ExecContext-type parameter. Use them in lib/distros/*/Distro.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 19:02:22 +01:00
1325222fbd lib.ExecContext,Local: Remove callback default params
Remove defaults from protected callback function parameters. They
have to be decided by the base class's public API.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 19:02:22 +01:00
7fdba1b5db lib.util: Add ec: ExecContext to all subprocesses
Allow to pass an optional execution context to all functions spawning
a subprocess defined in lib.util.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 15:14:13 +01:00
fadf1bca49 lib.util.run_cmd(): Add parameter ec: ExecContext
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.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 15:14:13 +01:00
3e897f4df8 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-06 14:56:46 +01:00
7e7cee6d11 cmds.distro: Move all modules to lib
Functions abstracting the distribution are not only needed in the
context of the distro subcommand, but also by other code, so make the
bulk of the code abstracting the distribution available in some place
more universally useful than below cmds.distro.

This commit leaves the source files mostly unchanged. They are only
patched to fix import paths, so that functionality is preserved.
Refactoring the code from command-line API to library API will be
done by the next commit.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 12:06:28 +01:00
ae902250bd jw/pkg/lib/util.run_cmd(): Chunked read_stream()
jw-pkg distro dup got hung in a chroot environment. strace shows that
write(2) into a pipe is the hanging syscall, with the write buffer
hinting at zypper dup output.

I strongly suspect that run_cmd() tries to write stdout into the pipe
which read_stream() fails to empty. So, make read_stream() more
resilient by using read(4096) instead of readline(), which I suspect
to be prone to hang on overlong lines.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-05 06:42:57 +00:00
0c1c2b9351 lib.util.run_cmd(): Reduce interactive logging
run_cmd() with cmd_input == mode:interactive  and verbose == true
logs output too often. First, __log() is called, then pty.spawn()
writes everything it reads from the PTY master to the terminal.

The fix it to not call __log() from _read() for the PTY reader.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:02:07 +00:00
8bc22a3a68 lib.util.run_cmd(): Fix docstring
The docstring of run_cmd()'s signature documents a wrong return
value, fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:48:26 +01:00
7fcb031795 jw.pkg.lib.App.__run(): Use return value as exit status
If a Cmd-classes's _run() method returns an integer between 0 and
255, use that as the program's exit status.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:23:32 +01:00
565946643b jw.pkg.*.run_xxx(): Return exit status
Most run_xxx() return stdout and stderr. There's no way, really, for
the caller to get hold of the exit code of the spawned executable. It
can pass throw=true, catch, and assume a non-zero exit status. But
that's not semantically clean, since the spawned function can well be
a test function which is expected to return a non-zero status code,
and the caller might be interested in what code that was, exactly.

The clearest way to solve this is to return the exit code as well.
This commit does that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:23:30 +01:00
afc77ab61d jw.pkg.lib.util.run_curl(): Beautify logging
Make some incomprensible parser error messages if run_curl() returns
nothing slightly less incomprehensible.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-27 17:03:26 +01:00
b81406e11a run_cmd() and friends: Make args a list[str]
This is a code maintenance commit: some run_xxx() helper functions
take a string, some a list, and some just digest all arguments and
pass them on as a list to exec() to be executed. That's highly
inconsistent. This commit changes that to list-only.

Except for the run_cmd() method of SSHClient, which is still run as a
shell method, because, erm, it's a shell. Might be changed in the
future for consistency reasons.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-27 09:09:10 +01:00
2906c697de jw.pkg.lib.util.run_cmd(): Add stderr to exception
If an error happens, append stderr to the exception thrown.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-24 14:53:17 +01:00
c8036ad216 jw-pkg.sh: Print help for missing subcommands
Print a help message if no subcommand is specified for one of the
comamnds "distro" and "projects".

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-24 14:52:25 +01:00
e5e0cf9930 jw.pkg.lib.Cmd._run(): Call parent._run()
jw.pkg.lib.Cmd._run() is abstract, but it's nice to give it a default
implementation which calls self.parent._run() in case parent is also
a command class. That allows for some default processing in _run()
for each node up the parent chain.

The children / derived classes just need to make sure all classes in
the hierarchy do:

    async def _run(self, args):
      return await super()._run(args)
      ... add main command logic here ..

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-20 19:30:22 +01:00
6916d7edc8 jw.pkg.lib.util.run_sudo(): Add parameter verbose
Add parameter verbose to run_sudo() and pass it on to run_cmd().

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-20 19:30:22 +01:00
b3fd624a3f jw.pkg.lib.util.get_profile_env(): add -> keep
Replace the boolean parameter "add" with the richer "keep":

  - False            -> Don't keep anything
  - True             -> Keep what's in the current environment
  - List of strings  -> Keep those variables

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-19 07:52:53 +01:00
2d1beeebb0 jw.pkg.lib.util.get_profile_env(): Add function
Add a function get_profile_env(), a function returning environment
variables from /etc/profile. Pass add=True to add its contents to the
existing environment dictionary, overwriting old entries, or pass
False to get the pristine content.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 14:18:46 +01:00
e104fa2e46 jw.pkg.lib.util.run_cmd(): Add output_encoding
Add a parameter "output_encoding" to run_cmd(). The parameter allows
the caller to specify if the output encoding should be detected as is
by passing None (the default), if the output should be returned as
undecoded bytes by passing the special string "bytes", or if the
output should be treated as the encoding with the specified name and
decoded to strings.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 13:38:12 +01:00
82c6a44ad6 jw.pkg.lib.util.run_cmd(): Fix mode:auto
In cmd_input == "mode:auto", the interactive variable is currently
not set due to a typo. Fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 13:31:26 +01:00
f8dc8ee6d1 jw.pkg.lib.util.run_cmd(): Honour env in PTY mode
The evironment passed to run_cmd() via env is currently not honoured
with mode:interactive. Fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 13:29:48 +01:00
75faf02232 jw.pkg.lib.util.run_cmd(): Add title parameter
Allow the caller to choose which title should be used for the
command's logging output box.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 11:31:53 +01:00
7eb15f2477 jw.pkg.lib: Don't log {e}
Don't log an Exception as {e} but as str(e) producing nicer output.
Or as repr(e) if a backtrace is requested, because to people who can
read backtraces, type info might be of interest. Also, remove
pointless time stamps, those belong into the logging framework.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 11:31:13 +01:00
b1d4e20295 jw.pkg.util: Add sudo()
Move the body of BackendCmd.sudo() into a function. The rationale
behind that is that its functionality is independent of the calling
object for the most part, so having it in a function instead of a
method is the more modular pattern.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 01:20:25 +01:00
d50a33d9ab jw.pkg.cmds.lib.Cmd: Define run()
Define run(), which calls _run() in the abstract base class Cmd, not
in lib.Cmd. Otherwise lib.Cmd is not abstract, which will predictably
confuse including code outside of jw-pkg.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-10 10:00:46 +01:00
53ba9e6fbe lib.App: Stay functional without autocomplete
If Python's autocomplete is not installed, jw-pkg.py fails to run
commands. Fix that in order stay compatible with minimal excecution
environments.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-02 12:15:41 +01:00
4274a71c62 lib.util.run_cmd(): Rewrite it to be async
run_cmd() is synchronous. Now that all commands are asynchronous, we
can await it, so rewrite it to be asynchronous, too.

Other changes:

  - Make it return stderr as well in case its needed

  - Drop into a pseuto-tty if
    - cmd_input == "mode:interactive" or
    - cmd_input == "mode:auto" and stdin is a TTY

  - Add argument env, defaulting to None. If it's a dict, it will be
    the environment the command is run in

This entails making all functions using run_cmd() async, too,
including run_curl(), get_username() and get_password().

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-28 17:41:40 +01:00
f175f9d5c9 lib.Cmd: Add argument "parent" to __init__()
During __init__(), commands have no idea of their parent. This is not
a problem as of now, but is easy to fix, and it's architecturally
desirable to be prepared just in case, so add the parent argument to
the ctor before more commands are added.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-28 15:24:24 +01:00
0be02c7154 lib.App, .Cmd: Add modules
Add App and Cmd as generic base classes for multi-command
applications. The code is taken from jw-python: The exising
jw.pkg.App is very similar to the more capable jwutils.Cmds class,
so, to avoid code duplication, add it here to allow for jwutils.Cmds
and jw.pkg.App to derive from it at some point in the future.

Both had to be slightly modified to work within jw-pkg's less
equipped context, and will need futher code cleanup.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-26 17:58:23 +01:00
18467a6500 lib.Types: Add module
Types is a container for types, notably classes, which are
dynamically loaded from other modules. Which modules are loaded is
based on the following criteria passed to its constructor:

  - mod_names: A list of modules to load and investigate

  - type_name_filter: A regular filter expression or None (default).
    If it's None, all types pass this filter.

  - type_filter: A list of types the returned types must match.
    Defaults to [], in which case all types pass this filter

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-26 17:58:23 +01:00
f7cc364be2 lib.log: Add module
A dedicated logging module is currently provided by jw-python, but
since it's often needed also in jw-pkg, and it's relatively small and
maintainable, it seems justified to move it into jw-pkg.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-26 17:58:23 +01:00
2e69639362 jw.pkg.build.lib: Move to jw.pkg.lib
In preparation of reorganizing the tree below cmds, move the lib
subdirectory a level up.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-01-26 17:58:23 +01:00