From b6c11ecdfb00707d96cff924498134089c18c552 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Sat, 12 Sep 2020 15:47:36 +0100 Subject: [PATCH] Add cmake-uninstall script --- .conduit.yaml | 1 + cmake-uninstall | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100755 cmake-uninstall diff --git a/.conduit.yaml b/.conduit.yaml index f875265..4ced70c 100644 --- a/.conduit.yaml +++ b/.conduit.yaml @@ -38,6 +38,7 @@ - symlink: - {src: fzf/bin/fzf, dst: ~/.local/bin/fzf} - {src: fzf/bin/fzf-tmux, dst: ~/.local/bin/fzf-tmux} + - {src: cmake-uninstall, dst: ~/.local/bin/cmake-uninstall} - command: - zsh update-completion-links.zsh - message: zsh will be the default prompt after next login diff --git a/cmake-uninstall b/cmake-uninstall new file mode 100755 index 0000000..ab59301 --- /dev/null +++ b/cmake-uninstall @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Uninstall a previously installed CMake installation. + +Read the ``install_manifest.txt`` file from a CMake build directory +which has been installed then delete the files, and optionally the empty +subdirectories of the install prefix, specified within. +""" + +from argparse import ArgumentParser, RawDescriptionHelpFormatter +from os import listdir, path, remove, rmdir +from sys import stderr + + +def uninstall(build_dir, recursive=False): + """Uninstall a previoulsy installed CMake installation. + + Arguments: + :build_dir: Path to the build directory containing the + ``install_manifest.txt`` of files to uninstall. + :recursive: Boolean flag to enable recursively uninstall empty + directories up to the install prefix specified in ``CMakeCache.txt``. + """ + # Get the list of installed files from the install_manifest.txt + install_manifest_path = path.join(build_dir, 'install_manifest.txt') + with open(install_manifest_path, 'r') as install_manifest_file: + install_manifest = sorted(install_manifest_file.read().splitlines()) + # Delete files from the filesystem + removed = [] + directories = [] + for entry in install_manifest: + directories.append(path.dirname(entry)) + if path.isfile(entry): + remove(entry) + removed.append(entry) + if recursive: + # Get the install prefix from CMakeCache.txt + cmakecache_path = path.join(build_dir, 'CMakeCache.txt') + with open(cmakecache_path, 'r') as cmakecache_file: + for line in cmakecache_file.read().splitlines(): + if line.startswith('CMAKE_INSTALL_PREFIX'): + prefix = path.normpath(line.split('=')[1]) + break + while True: + # Remove duplicates from list + directories = list(dict.fromkeys(directories)) + # Find directories in list which are not empty + not_empty = [] + for index, entry in enumerate(directories): + if listdir(entry): + not_empty.append(index) + # Remove directories which are not empty from list + for index in reversed(not_empty): + del directories[index] + # Delete directories from the filesystem + to_del = [] + to_append = [] + for index, entry in enumerate(directories): + rmdir(entry) + removed.append(entry) + to_del.append(index) + parent = path.dirname(entry) + # Add parent directory to the list when not the install prefix + if path.normpath(parent) != prefix: + to_append.append(parent) + # Remove deleted directories from list + for index in reversed(to_del): + del directories[index] + directories += to_append + # Exit loop when no more directories in list + if not directories: + break + return removed + + +def main(): + """Command line entry point.""" + cli = ArgumentParser(description=__doc__, + formatter_class=RawDescriptionHelpFormatter) + cli.add_argument('--version', action='version', version='%(prog)s 0.1.0') + cli.add_argument('-q', + '--quiet', + action='store_true', + help="don't print removed entries to stdout") + cli.add_argument('-r', + '--recursive', + action='store_true', + help='recursively remove empty directories') + cli.add_argument('build_dir', + help='path to the installed CMake build directory') + args = cli.parse_args() + try: + removed = uninstall(args.build_dir, recursive=args.recursive) + if not args.quiet: + for entry in removed: + print(f'-- Uninstalling: {entry}') + except FileNotFoundError as error: + print(f'error: file not found: {error.filename}', file=stderr) + exit(1) + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + exit(130)