1#!/usr/bin/env python3
2"""Run old and new zstream dump -v on streams, producing dump outputs."""
3
4#
5# SPDX-License-Identifier: CDDL-1.0
6#
7# CDDL HEADER START
8#
9# This file and its contents are supplied under the terms of the Common
10# Development and Distribution License ("CDDL"), version 1.0. You may only use
11# this file in accordance with the terms of version 1.0 of the CDDL.
12#
13# A full copy of the text of the CDDL should have accompanied this source. A
14# copy of the CDDL is also available via the Internet at
15# http://www.illumos.org/license/CDDL.
16#
17# CDDL HEADER END
18#
19
20#
21# Copyright (c) 2026 by Garth Snyder. All rights reserved.
22#
23
24import argparse
25import subprocess
26import sys
27from pathlib import Path
28
29
30def abbreviate(filename: str) -> str:
31    """Split filename at dashes, take first letter of each segment, lc."""
32    stem = Path(filename).stem
33    # Strip common compression suffixes to get the logical stem
34    for ext in (".zfs", ".gz", ".bz2", ".xz", ".zst", ".lz4"):
35        if stem.endswith(ext):
36            stem = stem[: -len(ext)]
37    return "".join(seg[0] for seg in stem.split("-") if seg).lower()
38
39
40def run_dump(zstream: Path, stream: Path, output: Path) -> bool:
41    """Run `zstream dump -v < stream > output`.  Returns True on success."""
42    try:
43        with open(stream, "rb") as inf, open(output, "w") as outf:
44            proc = subprocess.run(
45                [str(zstream), "dump", "-v"],
46                stdin=inf,
47                stdout=outf,
48                stderr=outf,
49            )
50        if proc.returncode != 0:
51            print(
52                f"  WARNING: {zstream} exited {proc.returncode} for "
53                f"{stream.name}", file=sys.stderr
54            )
55        return True
56    except Exception as e:
57        print(f"  ERROR: {e}", file=sys.stderr)
58        return False
59
60
61def main():
62    parser = argparse.ArgumentParser(
63        description="Run old and new zstream dump -v on stream files."
64    )
65    parser.add_argument("old_zstream", type=Path, help="Path to old zstream")
66    parser.add_argument("new_zstream", type=Path, help="Path to new zstream")
67    parser.add_argument(
68        "streams", nargs="+", type=Path, help="Streams to process"
69    )
70    args = parser.parse_args()
71
72    for zs in (args.old_zstream, args.new_zstream):
73        if not zs.is_file():
74            parser.error(f"zstream binary not found: {zs}")
75
76    for stream in args.streams:
77        if not stream.is_file():
78            print(f"Skipping missing file: {stream}", file=sys.stderr)
79            continue
80
81        abbrev = abbreviate(stream.name)
82        out_dir = stream.parent
83
84        old_out = out_dir / f"{abbrev}-old.dump"
85        new_out = out_dir / f"{abbrev}-new.dump"
86
87        print(f"{stream.name} -> {abbrev}")
88
89        print(f"  old: {old_out}")
90        run_dump(args.old_zstream, stream, old_out)
91
92        print(f"  new: {new_out}")
93        run_dump(args.new_zstream, stream, new_out)
94
95
96if __name__ == "__main__":
97    main()
98