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