#!/usr/bin/env python3 """Remove only this source version's installed files; never recurse directories.""" import argparse from pathlib import Path import stat def owned_files(source): files = ['lib/libxtc.a', 'lib/pkgconfig/xtc.pc', 'bin/xtc-check', 'bin/xtc', 'share/applications/xtc.desktop', 'share/licenses/xtc/LICENSE', 'share/doc/xtc/README.md'] files += ['include/xtc/' + p.name for p in sorted((source / 'include/xtc').glob('*.h'))] files += ['share/doc/xtc/' + p.name for p in sorted((source / 'docs').glob('*.md'))] files += ['share/doc/xtc/decisions/' + p.name for p in sorted((source / 'docs/decisions').glob('*.md'))] return files def uninstall(root, source): if not root.is_absolute() or root == Path('/'): raise ValueError('Installation root must be absolute and not /') files = [root / name for name in owned_files(source)] # Preflight before changing anything; never unlink a directory at a file path. for path in files: try: mode = path.lstat().st_mode except FileNotFoundError: continue if not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)): raise ValueError(f'Refusing non-file: {path}') for path in files: path.unlink(missing_ok=True) parents = {parent for path in files for parent in path.parents if parent == root or root in parent.parents} for parent in sorted(parents, key=lambda p: len(p.parts), reverse=True): try: parent.rmdir() except (FileNotFoundError, OSError): pass # Shared/nonempty directories remain untouched. if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--root', type=Path, required=True) args = parser.parse_args() uninstall(args.root, Path(__file__).resolve().parent.parent)