mirror of
https://gitlab.com/khumba/nvd.git
synced 2024-11-10 06:59:29 +01:00
Implement separate list command for listing matching packages (closes #5).
This commit is contained in:
parent
2c2fa1fbc9
commit
95c7ab7070
3 changed files with 196 additions and 36 deletions
|
@ -2,6 +2,10 @@
|
|||
|
||||
## 0.1.0
|
||||
|
||||
- Add a mandatory action argument to the CLI. The existing diff functionality
|
||||
is under the `diff` command. A new `list` command is now implemented as well
|
||||
(issue #5).
|
||||
|
||||
- Optimized first level dependency calculation to read depenencies from
|
||||
`nix-store` rather than walking a directory tree manually (issue #4). This
|
||||
also fixes nvd's support for things other than simple `buildEnv`s, e.g. file
|
||||
|
|
138
src/nvd
138
src/nvd
|
@ -19,6 +19,7 @@
|
|||
# See the nvd(1) man page for user-facing docs.
|
||||
|
||||
# Package install state (by pname):
|
||||
# I: Installed (unchanged)
|
||||
# A: Added to closure
|
||||
# R: Removed from closure
|
||||
# U: Upgrade
|
||||
|
@ -36,6 +37,7 @@
|
|||
# R: Package manifest only available on the right; selected there.
|
||||
|
||||
import argparse
|
||||
import fnmatch
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
|
@ -46,24 +48,7 @@ from pathlib import Path
|
|||
from subprocess import PIPE
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Nix/NixOS package version diff tool",
|
||||
epilog="See the nvd(1) manual page for more information.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--color",
|
||||
default="auto",
|
||||
help="Controls use of colour; one of 'auto', 'never', 'always'.")
|
||||
parser.add_argument(
|
||||
"root1",
|
||||
help="The first Nix store ptah to compare.")
|
||||
parser.add_argument(
|
||||
"root2",
|
||||
help="The second Nix store path to compare.")
|
||||
|
||||
ARGS = parser.parse_args()
|
||||
|
||||
USE_COLOUR = ARGS.color == "always" or (ARGS.color == "auto" and sys.stdout.isatty())
|
||||
USE_COLOUR = False
|
||||
|
||||
SGR_RESET = 0
|
||||
SGR_BOLD = 1
|
||||
|
@ -85,6 +70,7 @@ def sgr(*args):
|
|||
return ""
|
||||
return "\x1b[" + ";".join(str(arg) for arg in args) + "m"
|
||||
|
||||
INST_INSTALLED = "I"
|
||||
INST_ADDED = sgr(SGR_FG + SGR_BRIGHT + SGR_GREEN) + "A"
|
||||
INST_REMOVED = sgr(SGR_FG + SGR_BRIGHT + SGR_RED) + "R"
|
||||
INST_UPGRADED = sgr(SGR_FG + SGR_BRIGHT + SGR_CYAN) + "U"
|
||||
|
@ -257,6 +243,9 @@ class PackageManifest:
|
|||
def contains_pname(self, pname: str) -> bool:
|
||||
return pname in self._packages_by_pname
|
||||
|
||||
def all_pnames(self):
|
||||
return self._packages_by_pname.keys()
|
||||
|
||||
class PackageManifestPair:
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -378,6 +367,10 @@ def print_package_list(
|
|||
"Expect either one versions map, or a fixed install state."
|
||||
have_single_version = right_versions_map is None
|
||||
|
||||
if not pnames:
|
||||
print("No packages to display.")
|
||||
return
|
||||
|
||||
count = 1
|
||||
count_width = len(str(len(pnames)))
|
||||
count_format_str = "#{:0" + str(count_width) + "d}"
|
||||
|
@ -430,9 +423,51 @@ def print_package_list(
|
|||
))
|
||||
count += 1
|
||||
|
||||
def main():
|
||||
left_path = Path(ARGS.root1)
|
||||
right_path = Path(ARGS.root2)
|
||||
def run_list(*, root, only_selected, name_patterns):
|
||||
path = Path(root)
|
||||
|
||||
if not path.exists():
|
||||
sys.stderr.write(f"Path does not exist: {path}\n")
|
||||
sys.exit(1)
|
||||
|
||||
path = path.resolve()
|
||||
if (path / "sw").is_dir():
|
||||
manifest = PackageManifest.parse_tree((path / "sw").resolve())
|
||||
else:
|
||||
manifest = PackageManifest.parse_tree(path / "sw")
|
||||
|
||||
closure_paths: List[str] = subprocess.run(
|
||||
["nix-store", "-qR", str(path)],
|
||||
stdout=PIPE,
|
||||
text=True,
|
||||
).stdout.rstrip("\n").split("\n")
|
||||
|
||||
closure_map: Dict[str, List[str]] = closure_paths_to_map(closure_paths)
|
||||
|
||||
if only_selected:
|
||||
target_pnames = list(manifest.all_pnames())
|
||||
else:
|
||||
target_pnames = list(closure_map.keys())
|
||||
|
||||
target_pnames = [
|
||||
pname
|
||||
for pname in target_pnames
|
||||
if all(fnmatch.fnmatch(pname, pattern) for pattern in name_patterns)
|
||||
]
|
||||
|
||||
target_pnames.sort()
|
||||
|
||||
print_package_list(
|
||||
pnames=target_pnames,
|
||||
manifest_pair=PackageManifestPair(manifest, manifest),
|
||||
left_versions_map=closure_map,
|
||||
right_versions_map=None,
|
||||
fixed_install_state=INST_INSTALLED,
|
||||
)
|
||||
|
||||
def run_diff(*, root1, root2):
|
||||
left_path = Path(root1)
|
||||
right_path = Path(root2)
|
||||
|
||||
if not left_path.exists():
|
||||
sys.stderr.write(f"Path does not exist: {left_path}\n")
|
||||
|
@ -547,6 +582,67 @@ def main():
|
|||
f"delta {right_only_paths_count - left_only_paths_count:+d})."
|
||||
)
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Nix/NixOS package version diff tool",
|
||||
epilog="See the nvd(1) manual page for more information.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--color",
|
||||
default="auto",
|
||||
help="Controls use of colour; one of 'auto', 'never', 'always'.")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="action")
|
||||
|
||||
diff_parser = subparsers.add_parser(
|
||||
"diff",
|
||||
help="Diff two Nix store paths and their closures.")
|
||||
diff_parser.add_argument(
|
||||
"root1",
|
||||
help="The first Nix store path to compare.")
|
||||
diff_parser.add_argument(
|
||||
"root2",
|
||||
help="The second Nix store path to compare.")
|
||||
|
||||
list_parser = subparsers.add_parser(
|
||||
"list",
|
||||
help="List packages in the closure of a Nix store path.")
|
||||
list_parser.add_argument(
|
||||
"-r", "--root",
|
||||
default="/run/current-system",
|
||||
help="The The Nix store path to work with.")
|
||||
list_parser.add_argument(
|
||||
"-s", "--selected",
|
||||
dest="only_selected",
|
||||
action="store_true",
|
||||
help="Only show selected packages (direct dependencies).")
|
||||
list_parser.add_argument(
|
||||
nargs="*",
|
||||
default=[],
|
||||
dest="name_patterns",
|
||||
help="Patterns (globs) that must all match package names.")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
global USE_COLOUR
|
||||
|
||||
args = parse_args()
|
||||
action = args.action
|
||||
USE_COLOUR = args.color == "always" or (args.color == "auto" and sys.stdout.isatty())
|
||||
del args.action
|
||||
del args.color
|
||||
|
||||
if action is None:
|
||||
print("nvd: Subcommand required, see 'nvd --help'.")
|
||||
sys.exit(1)
|
||||
|
||||
{
|
||||
"list": run_list,
|
||||
"diff": run_diff,
|
||||
}[action](**vars(args))
|
||||
|
||||
# Importing this module is kinda broken because of the constant initializations
|
||||
# at the top.
|
||||
if __name__ == "__main__":
|
||||
|
|
90
src/nvd.1
90
src/nvd.1
|
@ -1,28 +1,52 @@
|
|||
.TH nvd 1 2021-04-09 nvd "User Commands"
|
||||
.TH nvd 1 2021-05-16 nvd "User Commands"
|
||||
.SH NAME
|
||||
nvd \- Nix/NixOS package version diff tool
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
.B nvd [ -h | --help ]
|
||||
.P
|
||||
.B nvd [ --color=(auto|always|never) ] root1 root2
|
||||
.B nvd [ --color=(auto|always|never) ] diff
|
||||
.I root1
|
||||
.I root2
|
||||
.P
|
||||
.B nvd [ --color=(auto|always|never) ] list
|
||||
.RS
|
||||
.B [ -r|--root
|
||||
.I store-path
|
||||
.B ]
|
||||
.br
|
||||
.B [ -s|--selected ]
|
||||
.br
|
||||
.B [
|
||||
.I name-pattern
|
||||
.B ]*
|
||||
.RE
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
.B nvd
|
||||
is a tool for diffing the versions of all store paths in the closures of two Nix
|
||||
store paths, neatly summarizing the differences. This is mainly intended for
|
||||
comparing two system configurations and is inspired by the output of
|
||||
is a tool for working with Nix store paths and their closures, grouped by
|
||||
package name, with nice presentation for package versions. This is mainly
|
||||
intended for listing installed packages and comparing two system configurations,
|
||||
and is inspired by the output of
|
||||
.B emerge -pv
|
||||
from Gentoo's Portage package manager.
|
||||
.B nvd
|
||||
could also be likened to the output of Debian's
|
||||
.B apt list -i
|
||||
and
|
||||
.B apt upgrade -V,
|
||||
or any equivalent from other distributions' package managers.
|
||||
.B nvd
|
||||
isn't limited to comparing system configurations though, and can work with any
|
||||
two store paths.
|
||||
.P The
|
||||
.B diff
|
||||
command compares the packages and package versions included in two closures.
|
||||
The
|
||||
.B list
|
||||
command displays the list of packages included in a closure, optionally filtered
|
||||
to some criteria.
|
||||
.P
|
||||
When given two system configurations,
|
||||
.B nvd
|
||||
distinguishes between packages that are explicitly included in
|
||||
.B environment.systemPackages,
|
||||
|
@ -88,14 +112,41 @@ detects whether stdout is a terminal and only uses colour if it is. Passing
|
|||
forces colour to always be used, and passing
|
||||
.B never
|
||||
forces colour to never be used.
|
||||
.TP
|
||||
-r|--root <store-path>
|
||||
For the
|
||||
.B list
|
||||
command, this is the root store path to use, or a link to the store path to use.
|
||||
.TP
|
||||
-s|--selected
|
||||
For the
|
||||
.B list
|
||||
command, only print out selected packages (direct dependencies).
|
||||
.TP
|
||||
<name-pattern>
|
||||
For the
|
||||
.B list
|
||||
command, only print out names matching all of the given patterns. The character
|
||||
.B ?
|
||||
matches exactly one of any character, and the character
|
||||
.B *
|
||||
matches zero or more of any character.
|
||||
.SH OUTPUT
|
||||
.P
|
||||
The output of
|
||||
If the
|
||||
.B diff
|
||||
command is requested, then the output of
|
||||
.B nvd
|
||||
displays the given names of the two store paths being compared on the first two
|
||||
lines, then changed packages on subsequent lines, one line per package, grouped
|
||||
by the type of change. Newly added or removed packages, packages with version
|
||||
or count changes, and packages with selection state changes are displayed. Hash changes are
|
||||
lines. After this, for both the
|
||||
.B diff
|
||||
and
|
||||
.B list
|
||||
commands, package names, versions, and other information is printed out, with
|
||||
one line per package name, in lexicographic order. When producing a diff,
|
||||
packages are grouped by the type of change: newly added or removed packages,
|
||||
packages with version or count changes, and packages with selection state
|
||||
changes. Hash changes are
|
||||
.B not
|
||||
considered important, and will not cause a package to be displayed, however
|
||||
changes in the number of times a package
|
||||
|
@ -132,6 +183,7 @@ removed, upgraded or downgraded. The possibilities here are:
|
|||
.P
|
||||
.RS
|
||||
.EX
|
||||
I: Installed (no change).
|
||||
A: Package is newly added to the closure.
|
||||
R: All versions of the package are being removed the closure.
|
||||
U: The package is being upgraded.
|
||||
|
@ -140,7 +192,15 @@ C: None of the above apply; unspecified changes.
|
|||
.EE
|
||||
.RE
|
||||
.P
|
||||
Packages can be displayed with
|
||||
The
|
||||
.B list
|
||||
command displays only the
|
||||
.B I
|
||||
state, and the
|
||||
.B diff
|
||||
command can display all states but the
|
||||
.B I
|
||||
state. Packages can be displayed with
|
||||
.B C
|
||||
install state for a few different reasons, including the number of copies of an
|
||||
existing version in the closure changing, or due to the selection state changing
|
||||
|
@ -200,7 +260,7 @@ plus additional versions of some existing packages:
|
|||
.P
|
||||
.RS
|
||||
.EX
|
||||
$ nvd /nix/var/nix/profiles/system-{29,30}-link
|
||||
$ nvd diff /nix/var/nix/profiles/system-{29,30}-link
|
||||
<<< /nix/var/nix/profiles/system-29-link
|
||||
>>> /nix/var/nix/profiles/system-30-link
|
||||
Version changes:
|
||||
|
@ -232,7 +292,7 @@ have been installed.
|
|||
.P
|
||||
.RS
|
||||
.EX
|
||||
$ nvd /nix/var/nix/profiles/system-{33,34}-link
|
||||
$ nvd diff /nix/var/nix/profiles/system-{33,34}-link
|
||||
<<< /nix/var/nix/profiles/system/system-33-link
|
||||
>>> /nix/var/nix/profiles/system/system-34-link
|
||||
Version changes:
|
||||
|
@ -263,7 +323,7 @@ one, despite this actually being a newer commit than the old one:
|
|||
.P
|
||||
.RS
|
||||
.EX
|
||||
$ nvd /nix/var/nix/profiles/system-{43,44}-link
|
||||
$ nvd diff /nix/var/nix/profiles/system-{43,44}-link
|
||||
<<< /nix/var/nix/profiles/system/system-43-link
|
||||
>>> /nix/var/nix/profiles/system/system-44-link
|
||||
Version changes:
|
||||
|
@ -278,7 +338,7 @@ to output no packages at all if no versions have changed:
|
|||
.P
|
||||
.RS
|
||||
.EX
|
||||
$ nvd /nix/var/nix/profiles/system-{23,24}-link
|
||||
$ nvd diff /nix/var/nix/profiles/system-{23,24}-link
|
||||
<<< /nix/var/nix/profiles/system/system-23-link
|
||||
>>> /nix/var/nix/profiles/system/system-24-link
|
||||
No version or selection state changes.
|
||||
|
|
Loading…
Reference in a new issue