From 07f6347d491ccdf5a99df66f6525caa11e084489 Mon Sep 17 00:00:00 2001 From: Jacob Hinkle Date: Fri, 23 Sep 2022 20:49:00 -0400 Subject: [PATCH] Clean up color in diff cli. Fix symlink detection --- src/nancy/cli/diff.py | 65 +++++++++++++++++++++++++++++++++++-------- src/nancy/fs.py | 2 +- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/nancy/cli/diff.py b/src/nancy/cli/diff.py index d836182..7d68a09 100644 --- a/src/nancy/cli/diff.py +++ b/src/nancy/cli/diff.py @@ -8,11 +8,11 @@ import warnings def print_diff(ABdiff: fs.FSDiff, version_info='count', indent=2, - indent_level=0, use_color=True): + indent_level=0, use_color=True, show_hashes=False): """Pretty print an FSDiff object""" if use_color: try: - from colorama import Fore, Back, Style + from colorama import init, Fore, Back, Style except ImportError: warnings.warn("Could not import colorama library. Color output disabled.") use_color = False @@ -22,21 +22,52 @@ def print_diff(ABdiff: fs.FSDiff, version_info='count', indent=2, DEL=Fore.RED + 'DEL' + Style.RESET_ALL if use_color else 'DEL', MOD=Fore.YELLOW + 'MOD' + Style.RESET_ALL if use_color else 'MOD', ) + filetypecolors = dict( + DIR=Fore.BLUE if use_color else '', + REG='', + LNK=Fore.CYAN if use_color else '', + ) + reset = Style.RESET_ALL if use_color else '' + hashcolor = Fore.MAGENTA if use_color else '' + + def _print_row(tag, entry, level): + relpath = entry.relpath[2:] + + # Format relpath using filetype-based colors + dname, fname = os.path.split(relpath) + if fname == '': # root directory leads to empty fname here + dirstr = (filetypecolors['DIR'] + '' + reset) + else: + dirstr = (filetypecolors['DIR'] + dname + '/' + reset) \ + if dname != '' else '' + fname = filetypecolors.get(entry.filetype, '') + fname + reset + + if entry.filetype == 'LNK': # append symlink target + fname += ' -> ' + entry.symlink_target + + relpath = dirstr + fname + + hashchange = (hashcolor + entry.sha256.hex() + reset + + ' ' + changetags[tag]) \ + if show_hashes else changetags[tag] + + print( + hashchange, + entry.unfrozen_perms, + relpath, + ) for l, d in ABdiff.flatten_tree(): if d.A is None: assert d.B is not None - print(changetags['NEW'], d.B.unfrozen_perms, - #(indent_level + l) * indent * ' ' + d.B.filename, - d.B.relpath[2:], - ) + _print_row('NEW', d.B, l) elif d.B is None: - print(changetags['DEL'], d.A.unfrozen_perms, (indent_level + l) * indent * ' ' + d.A.filename) + _print_row('DEL', d.A, l) else: - print(changetags['MOD'], d.B.unfrozen_perms, (indent_level + l) * indent * ' ' + d.B.filename) + _print_row('MOD', d.B, l) -def diff(store, filedir_path, version_info='count'): +def diff(store, filedir_path, version_info='count', show_hashes=False, use_color=True): """Unwrapped diff command that prints a diff""" if not os.path.exists(filedir_path): raise FileNotFoundError(f"Cannot diff non-existent file or directory {filedir_path}") @@ -44,7 +75,7 @@ def diff(store, filedir_path, version_info='count'): # get the diff object fsdiff = store.diff(filedir_path) - print_diff(fsdiff, version_info=version_info) + print_diff(fsdiff, version_info=version_info, show_hashes=show_hashes, use_color=use_color) @click.command() @@ -55,7 +86,17 @@ def diff(store, filedir_path, version_info='count'): default='count', help='How much info to display about file versions.', ) -def diff_cli(path, version_info): +@click.option( + '-H', "--show-hashes", + is_flag=True, + help='If given, prepend each line in the diff with the new file hash (SHA256).', +) +@click.option( + "--no-color", + is_flag=True, + help='If given, do not print any color output.', +) +def diff_cli(path, version_info, show_hashes, no_color): """Detect and describe changes to PATH PATH is a path to a file or directory inside an existing nancy store @@ -77,7 +118,7 @@ def diff_cli(path, version_info): s = store.Store(storepath) try: - diff(store=s, filedir_path=path) + diff(store=s, filedir_path=path, show_hashes=show_hashes, use_color=not no_color) except FileNotFoundError as e: print(str(e), file=sys.stderr) sys.exit(1) diff --git a/src/nancy/fs.py b/src/nancy/fs.py index 7801f36..28a925c 100644 --- a/src/nancy/fs.py +++ b/src/nancy/fs.py @@ -113,7 +113,7 @@ class FSEntry: children = [] symlink_target = None - if stat.S_ISLNK(s): + if os.path.islink(path): # Check links first, since it is not exclusive with dir or file checks filetype = 'LNK' symlink_target = os.readlink(path)