Commit graph

178 commits

Author SHA1 Message Date
5bd1f3378b App.get_value(): Beautify logging
"getting value xxx for project" is a prominent debug log message but
ugly. Beautify to e.g.:

  Lookup jw-fail2ban -> jw-pkg / version

Meaning project "jw-fail2ban" looks up the value for key "version" in
project "jw-pkg".

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-15 10:42:35 +01:00
b2847809c1 lib.Types: Make debug logging optional
lib.Types class detection is too chatty. Make that a ctor option.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-15 10:42:24 +01:00
2e1115e722 cmds.projects.CmdRequiredOsPkg: Select devel with release
The output of

  jw.pkg.py projects required-os-pkg --flavours release

should include all packages required by flavour devel, because during
the release process, -devel and -run packages are both installed, and
installing the -devel package is only possible if its dependencies
are installed.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-14 12:09:42 +01:00
72bd5e3555 lib.Local.run(): Be less dramatic about exit != 0
Don't mention "error" in log message for exit codes > 0 from spawned
processes, because sometimes they don't mean an error.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 20:03:01 +01:00
281e6e2440 cmds.secrets.CompileTemplates: Log missing secrets
Log the number of secrets missing to fully compile all templates.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 20:01:26 +01:00
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
f3c4a51b85 cmds.secrets.CmdCompileTemplates: Support -ogm
Add support for the -o (--owner) -g (--group) -m (--mode) options.
They allow to specify a default for compiling templates, but _don't_
override what's in the #conf: specification line in .jw-tmpl or
.jw-secret files.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 19:58:28 +01:00
1ffac7b365 cmds.secrets.CmdXX: Add option --all
Support option --all to jw-pkg.py secrets list-compilation-output and
list-secrets (CmdListCompilationOutput & CmdSecrets). This allows
them to also report non-existent files.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 19:58:02 +01:00
699980c32e cmds.secrets.Cmd: Fix errors on Kali 2026.1
Fix errors dug up by testing on Kali Linux 2026.1:

  - Nested class Cmds.Attrs is constructed without scope

  - "replace" falls back to empty list, not empty dictionary

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-09 19:57:56 +01:00
18de6f2cf2 cmds.CmdSecrets: Add command class + subcommands
jw-pkg.py secrets [sub-command] [packages] is a set of utility
commands designed to manage configuration files containing secrets.

To keep secrets from leaking via version control or packages, a
_template_ should be packaged for every sensitive configuration file.
Then, during post-install, configuration files can be generated from
packaged templates via

  jw-pkg.py secrets compile-templates <package> <package> ...

During post-uninstall

  jw-pkg.py secrets rm-compilation-output <package> <package> ...

removes them.

Not specifying any packages will compile or remove all templates on
the system.

To identify which files to consider and generate or remove, the
compilation scans <package> for files ending in .jw-tmpl. For each
match, e.g.

  /path/to/some.conf.jw-tmpl

it will read key-value pairs from

  /path/to/some.conf.jw-secret

and generate

  /path/to/some.conf

from it, replacing all keys by their respective values. The file
attributes of the generated file can be determined by the first line:
of some.conf.jw-tmpl or some.conf.jw-secret:

  # conf: owner=mysql; group=mysql; mode=0640

There are other commands for managing all secrets on the system at
once, see jw-pkg.py secrets --help:

    compile-templates   Compile package template files
    list-compilation-output
                        List package compilation output files
    list-secrets        List package secret files
    list-templates      List package template files
    rm-compilation-output
                        Remove package compilation output files

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-07 21:51:17 +01:00
18c16917b2 App, .cmds.Cmd: Add .distro property
DistroBase's option --id is now redundant to the new global option
--distro-id in the App class, so remove --id. The only added value
DistroBase then brings to the table is its .distro property, which
can be provided by App just fine at this point, given that App has
all it needs to construct a Distro object, so add .distro to App and
remove the entire DistroBase class.

For convenience, also make App.distro available as a newly added
cmds.Cmd.distro property. This also obviates the need for the
distro-related properties in the .distro.Cmd class, remove all that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-07 14:35:54 +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
f24541dbe4 pkg.App: Add options --distro-id, --interactive
Add the global options --distro-id and --interactive, and expose them
as properties App.distro_id and App.interactive, respectively.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-06 12:06:28 +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
f94a2ac037 cmds.DistroBase: Add class
Move most of CmdDistro into the new class DistroBase, meant to serve
as base class for distro-aware commands other than "distro".

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
404901bcff cmds.distro.backend.debian.Util: Remove --fix-broken
--fix-broken is added to apt-get options in non-interactive mode, but
seems to work only with apt-get install, not with apt-get update.
Don't add it at all for now.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:39:39 +00:00
a25701991d distro.backend.debian.Refresh.run(): Fix apt_get()
Fix call to apt_get(), needs to be a list, not a string.
2026-03-04 16:30:43 +00:00
4eeb12c12e cmds.distro.backend.debian.Util.apt_get(): Fix -yes
Fix a typo in the non-interactive command-line option (--yes) passed
to apt_get().

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:16:20 +00:00
8ca8df859b cmds.distro.backend.debian.Delete: Add class
Add Debian supoort for single-package deletion.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:04:27 +00:00
a7293e0ac9 cmds.distro.backend.debian.Util.py: Add dpkg()
Add utility method .dpkg() to the backend.debian.Utils class, saving
the need to import it, saving the need to import it.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:04:27 +00:00
7e85076b44 cmds.distro.backend.debian.Install|Dup: Fix .apt_get()
.apt_get() is called on self, should be called on self.util instead,
fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:04:27 +00:00
9e8f5e3d2e cmds.distro.backend.debian.Util.apt_get(): Take list
apt_get(), like all other functions and methods spawning processes
should take a list instead of a starred *args array. Implement that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:04:27 +00:00
39ab1885e6 cmds.distro.backend.suse.Util.rpm(): Relay args
Relay *args and **kwargs unchanged to run_rpm(), no need to limit
them so far.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:02:44 +00:00
770920ef91 cmds.distro.CmdDelete: args.packages -> args.names
Rename the "packages" argument to "names" to be a little more
consistent with the pkg subcommand argument nomenclature.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 16:02:38 +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
0317f46a01 cmds.distro.pkg.CmdMeta: Add class
Support distro pkg meta <package names ...>, returning meta
information for the specified package names.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:56:11 +01:00
f55d3045e0 cmds.distro.backend.debian.Pkg: Add module
Add Debian support for the "pkg"-command.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:55:06 +01:00
2897ba849f cmds.distro.backend.debian.Select: Add class
Add Select for Debian backends.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:54:33 +01:00
7f72d17f7a cmds.distro.lib.dpkg: Add module
As with cmds.distro.lib.rpm, the dpkg module is a place for Python
abstractions of the Debian package manager tools dpkg and friends.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:53:14 +01:00
1bb3c166d6 cmds.distro.lib.rpm.query_packages(): Add function
Replace all_installed_packages() by query_packages(). The function
takes an optional list of packages to be queried. If it's empty, a
list of all installed packages are returned.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:52:14 +01:00
3e9ec1f6c5 cmds.distro.lib.Package: Add more methods
Add more methods, to make Package more useful:

  - __repr__()

  - Class-mMethods to help with parsing of strings gathered from the
    OS-tools' output:

      parse_spec_str()
      parse_specs_str()
      order_tags()

  - Add field maintainer

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:49:11 +01:00
ecd077c93d cmds.distro.CmdPkg: args.name -> names
Make all pkg commands take a "names" argument (plural) instead of
"name", and make it a non-option-argument, to be passed to the
subcomand instead.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-04 14:48:46 +01: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
888ea9979a jw.pkg.cmds.distro.CmdDup: Support --donwload-only
Add --download-only to the options of jw-pkg.py distro dup, which
makes the command only download packages from the repositories
without installing them.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:49 +01:00
6af16d2dca jw.pkg.cmds.distro.CmdInstall: Support --only-update
Passing --only-update should keep "jw-pkg.py distro install" from
installing packages that are not already installed on the the system.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:43 +01:00
79d40af558 jw.pkg.cmds.distro.CmdRebootRequired: Add class
Add the command distro.CmdRebootRequired, adding support for "distro
reboot-required". The command exits with status code 1 if a reboot is
required and 0 otherwise.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:22 +01:00
5d95ca01ca jw.pkg.cmds.distro.backend.suse.Util.zypper(): Add verbose
Add boolean parameter verbose to zypper(), causing the obvious.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:19 +01:00
fc1431ec48 jw.pkg.cmds.distro.backend.suse.Util.zypper(): Add sudo
Add boolean parameter sudo to zypper(), doing the obvious.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:15 +01:00
0b3f12866c jw.pkg.cmds.distro.backend.*._sudo(): Pass *args on
Pass *args and **kwargs on unchanged to run_sudo().

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 11:24:10 +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
03fca61248 jw.pkg.App.distro_id: Don't return opensuse
get-os.sh returned "suse" for SuSE-like distros, and that seems more
appropriate since SLES is not OpenSUSE but should share and ID with
other SuSE variants.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 05:11:59 +01:00
d22074abf9 jw.pkg.cmds.distro.Cmd._backend_path: Fix suse mapping
App.distro_id used to return "opensuse-tumbleweed", analogous to
what's in ID@/etc/os-release, but now returns "opensuse", and the
"tumbleweed" goes into "codename". That matches more what Debian-like
distributions do, but it confuses _backend_path. Adapt it to map the
new distro_id correctly.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-03 04:27:50 +01:00