cmds.pkg.CmdVerify: Add command
All checks were successful
CI / Packaging - Kali Linux (pull_request) Successful in 4m24s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Successful in 4m43s
CI / Packaging test (pull_request) Successful in 0s
CI / Packaging - Kali Linux (push) Successful in 4m48s
CI / Packaging - OpenSUSE Tumbleweed (push) Successful in 4m38s
CI / Packaging test (push) Successful in 0s
All checks were successful
CI / Packaging - Kali Linux (pull_request) Successful in 4m24s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Successful in 4m43s
CI / Packaging test (pull_request) Successful in 0s
CI / Packaging - Kali Linux (push) Successful in 4m48s
CI / Packaging - OpenSUSE Tumbleweed (push) Successful in 4m38s
CI / Packaging test (push) Successful in 0s
Add the "packages verify" command: it runs Distro.verify() with the app's package filter and prints one line per flagged file. Signed-off-by: Jan Lindemann <jan@janware.com> Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v1.2.0
This commit is contained in:
parent
cae983479c
commit
8106d4a7b0
5 changed files with 173 additions and 1 deletions
29
src/python/jw/pkg/cmds/pkg/CmdVerify.py
Normal file
29
src/python/jw/pkg/cmds/pkg/CmdVerify.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, override
|
||||||
|
|
||||||
|
from .Cmd import Cmd, Parent
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from argparse import ArgumentParser, Namespace
|
||||||
|
|
||||||
|
class CmdVerify(Cmd): # export
|
||||||
|
|
||||||
|
def __init__(self, parent: Parent) -> None:
|
||||||
|
super().__init__(
|
||||||
|
parent,
|
||||||
|
'verify',
|
||||||
|
help = (
|
||||||
|
'Verify the integrity of installed packages: report files'
|
||||||
|
' modified or deleted outside of the package manager'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||||
|
super().add_arguments(parser)
|
||||||
|
|
||||||
|
@override
|
||||||
|
async def _run(self, args: Namespace) -> None:
|
||||||
|
for file in await self.distro.verify():
|
||||||
|
print(file)
|
||||||
|
|
@ -66,6 +66,8 @@ Available subcommands of packages:
|
||||||
reboot-required Check whether the machine needs rebooting
|
reboot-required Check whether the machine needs rebooting
|
||||||
refresh Refresh the distribution's notion of available packages
|
refresh Refresh the distribution's notion of available packages
|
||||||
select Select packages by filter
|
select Select packages by filter
|
||||||
|
verify Verify the integrity of installed packages: report files
|
||||||
|
modified or deleted outside of the package manager
|
||||||
============= Running: jw-pkg.py -t ../../../.. --log-level info packages delete --help
|
============= Running: jw-pkg.py -t ../../../.. --log-level info packages delete --help
|
||||||
usage: jw-pkg.py packages delete [-h] [names ...]
|
usage: jw-pkg.py packages delete [-h] [names ...]
|
||||||
|
|
||||||
|
|
@ -140,6 +142,14 @@ Select packages by filter
|
||||||
positional arguments:
|
positional arguments:
|
||||||
filter Package filter string
|
filter Package filter string
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
============= Running: jw-pkg.py -t ../../../.. --log-level info packages verify --help
|
||||||
|
usage: jw-pkg.py packages verify [-h]
|
||||||
|
|
||||||
|
Verify the integrity of installed packages: report files modified or deleted
|
||||||
|
outside of the package manager
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
============= Running: jw-pkg.py -t ../../../.. --log-level info platform --help
|
============= Running: jw-pkg.py -t ../../../.. --log-level info platform --help
|
||||||
|
|
|
||||||
7
test/unit/python/jw/pkg/lib/pm/dpkg/Makefile
Normal file
7
test/unit/python/jw/pkg/lib/pm/dpkg/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
TOPDIR = ../../../../../../../..
|
||||||
|
|
||||||
|
include $(TOPDIR)/make/proj.mk
|
||||||
|
include $(JWBDIR)/make/py-run.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
test: run
|
||||||
81
test/unit/python/jw/pkg/lib/pm/dpkg/test.py
Normal file
81
test/unit/python/jw/pkg/lib/pm/dpkg/test.py
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from typing import override
|
||||||
|
|
||||||
|
from jw.pkg.lib.ec.Local import Local
|
||||||
|
from jw.pkg.lib.pm.dpkg import list_files
|
||||||
|
from jw.pkg.lib.Result import Result
|
||||||
|
|
||||||
|
class CannedLocal(Local):
|
||||||
|
|
||||||
|
def __init__(self, stdout: str) -> None:
|
||||||
|
super().__init__('local')
|
||||||
|
self.stdout = stdout
|
||||||
|
self.cmds: list[list[str]] = []
|
||||||
|
|
||||||
|
@override
|
||||||
|
async def _run(
|
||||||
|
self,
|
||||||
|
cmd: list[str],
|
||||||
|
wd: str | None,
|
||||||
|
verbose: bool,
|
||||||
|
cmd_input: bytes | None,
|
||||||
|
mod_env: dict[str, str] | None,
|
||||||
|
interactive: bool,
|
||||||
|
log_prefix: str,
|
||||||
|
) -> Result:
|
||||||
|
self.cmds.append(cmd)
|
||||||
|
return Result(stdout = self.stdout.encode(), status = 0)
|
||||||
|
|
||||||
|
# -- One listing over several packages
|
||||||
|
cl = CannedLocal('/usr/bin/b\n/etc/b/b.conf.jw-tmpl\n')
|
||||||
|
assert asyncio.run(list_files(['a', 'b'], ec = cl)) == \
|
||||||
|
['/usr/bin/b', '/etc/b/b.conf.jw-tmpl']
|
||||||
|
assert cl.cmds[-1] == [
|
||||||
|
'/usr/bin/dpkg',
|
||||||
|
'-L',
|
||||||
|
'a',
|
||||||
|
'b',
|
||||||
|
]
|
||||||
|
|
||||||
|
# -- The unfiltered selection is the standard interface, two
|
||||||
|
# queries: select the installed packages, then list their files
|
||||||
|
# in one command; the list output carries a package-name header
|
||||||
|
# and a blank line per package, both dropped
|
||||||
|
class CannedTwoStage(Local):
|
||||||
|
|
||||||
|
def __init__(self, query: str, listing: str) -> None:
|
||||||
|
super().__init__('local')
|
||||||
|
self.query = query
|
||||||
|
self.listing = listing
|
||||||
|
self.cmds: list[list[str]] = []
|
||||||
|
|
||||||
|
@override
|
||||||
|
async def _run(
|
||||||
|
self,
|
||||||
|
cmd: list[str],
|
||||||
|
wd: str | None,
|
||||||
|
verbose: bool,
|
||||||
|
cmd_input: bytes | None,
|
||||||
|
mod_env: dict[str, str] | None,
|
||||||
|
interactive: bool,
|
||||||
|
log_prefix: str,
|
||||||
|
) -> Result:
|
||||||
|
self.cmds.append(cmd)
|
||||||
|
out = self.query if '-W' in cmd else self.listing
|
||||||
|
return Result(stdout = out.encode(), status = 0)
|
||||||
|
|
||||||
|
cl2 = CannedTwoStage('a\nb\n', 'a:\n/usr/bin/a\n\nb:\n/etc/b/b.conf.jw-tmpl\n')
|
||||||
|
assert asyncio.run(list_files(None, ec = cl2)) == \
|
||||||
|
['/usr/bin/a', '/etc/b/b.conf.jw-tmpl']
|
||||||
|
assert cl2.cmds == [
|
||||||
|
['/usr/bin/dpkg-query', '-W', '-f=${?installed:binary:Package}\n'],
|
||||||
|
['/usr/bin/dpkg-query', '-L', 'a', 'b'],
|
||||||
|
]
|
||||||
|
|
||||||
|
# -- An empty selection lists nothing and runs no query
|
||||||
|
cl3 = CannedTwoStage('', '')
|
||||||
|
assert asyncio.run(list_files([], ec = cl3)) == []
|
||||||
|
assert cl3.cmds == []
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from typing import override
|
||||||
|
|
||||||
|
from jw.pkg.lib.ec.Local import Local
|
||||||
from jw.pkg.lib.FlaggedFile import FlaggedFile
|
from jw.pkg.lib.FlaggedFile import FlaggedFile
|
||||||
from jw.pkg.lib.pm.rpm import _parse_verify_output
|
from jw.pkg.lib.pm.rpm import _parse_verify_output, list_files
|
||||||
|
from jw.pkg.lib.Result import Result
|
||||||
|
|
||||||
# -- _parse_verify_output --
|
# -- _parse_verify_output --
|
||||||
|
|
||||||
|
|
@ -56,3 +62,42 @@ f = FlaggedFile('pkg', '/etc/foo', 'SM5....T.')
|
||||||
assert repr(f) == 'pkg /etc/foo SM5....T.'
|
assert repr(f) == 'pkg /etc/foo SM5....T.'
|
||||||
|
|
||||||
print('All rpm pm tests passed')
|
print('All rpm pm tests passed')
|
||||||
|
|
||||||
|
# -- list_files --
|
||||||
|
|
||||||
|
class CannedLocal(Local):
|
||||||
|
|
||||||
|
def __init__(self, stdout: str) -> None:
|
||||||
|
super().__init__('local')
|
||||||
|
self.stdout = stdout
|
||||||
|
self.cmds: list[list[str]] = []
|
||||||
|
|
||||||
|
@override
|
||||||
|
async def _run(
|
||||||
|
self,
|
||||||
|
cmd: list[str],
|
||||||
|
wd: str | None,
|
||||||
|
verbose: bool,
|
||||||
|
cmd_input: bytes | None,
|
||||||
|
mod_env: dict[str, str] | None,
|
||||||
|
interactive: bool,
|
||||||
|
log_prefix: str,
|
||||||
|
) -> Result:
|
||||||
|
self.cmds.append(cmd)
|
||||||
|
return Result(stdout = self.stdout.encode(), status = 0)
|
||||||
|
|
||||||
|
# -- One query over several packages, the output split into lines
|
||||||
|
cl = CannedLocal('/usr/bin/a\n/etc/a/a.conf.jw-tmpl\n')
|
||||||
|
assert asyncio.run(list_files(['a', 'b'], ec = cl)) == \
|
||||||
|
['/usr/bin/a', '/etc/a/a.conf.jw-tmpl']
|
||||||
|
assert cl.cmds[-1] == ['/usr/bin/rpm', '-ql', 'a', 'b']
|
||||||
|
|
||||||
|
# -- The unfiltered selection is one query without package names
|
||||||
|
cl = CannedLocal('/usr/bin/a\n/etc/a/a.conf.jw-tmpl\n')
|
||||||
|
assert asyncio.run(list_files(None, ec = cl)) == ['/usr/bin/a', '/etc/a/a.conf.jw-tmpl']
|
||||||
|
assert cl.cmds[-1] == ['/usr/bin/rpm', '-qal']
|
||||||
|
|
||||||
|
# -- An empty selection lists nothing and runs no query
|
||||||
|
cl = CannedLocal('')
|
||||||
|
assert asyncio.run(list_files([], ec = cl)) == []
|
||||||
|
assert cl.cmds == []
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue