Clean up color in diff cli. Fix symlink detection

This commit is contained in:
Jacob Hinkle 2022-09-23 20:49:00 -04:00
parent a750b53a10
commit 07f6347d49
2 changed files with 54 additions and 13 deletions

View File

@ -8,11 +8,11 @@ import warnings
def print_diff(ABdiff: fs.FSDiff, version_info='count', indent=2, 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""" """Pretty print an FSDiff object"""
if use_color: if use_color:
try: try:
from colorama import Fore, Back, Style from colorama import init, Fore, Back, Style
except ImportError: except ImportError:
warnings.warn("Could not import colorama library. Color output disabled.") warnings.warn("Could not import colorama library. Color output disabled.")
use_color = False 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', DEL=Fore.RED + 'DEL' + Style.RESET_ALL if use_color else 'DEL',
MOD=Fore.YELLOW + 'MOD' + Style.RESET_ALL if use_color else 'MOD', 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'] + '<root>' + 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(): for l, d in ABdiff.flatten_tree():
if d.A is None: if d.A is None:
assert d.B is not None assert d.B is not None
print(changetags['NEW'], d.B.unfrozen_perms, _print_row('NEW', d.B, l)
#(indent_level + l) * indent * ' ' + d.B.filename,
d.B.relpath[2:],
)
elif d.B is None: 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: 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""" """Unwrapped diff command that prints a diff"""
if not os.path.exists(filedir_path): if not os.path.exists(filedir_path):
raise FileNotFoundError(f"Cannot diff non-existent file or directory {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 # get the diff object
fsdiff = store.diff(filedir_path) 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() @click.command()
@ -55,7 +86,17 @@ def diff(store, filedir_path, version_info='count'):
default='count', default='count',
help='How much info to display about file versions.', 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 """Detect and describe changes to PATH
PATH is a path to a file or directory inside an existing nancy store 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) s = store.Store(storepath)
try: 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: except FileNotFoundError as e:
print(str(e), file=sys.stderr) print(str(e), file=sys.stderr)
sys.exit(1) sys.exit(1)

View File

@ -113,7 +113,7 @@ class FSEntry:
children = [] children = []
symlink_target = None 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 # Check links first, since it is not exclusive with dir or file checks
filetype = 'LNK' filetype = 'LNK'
symlink_target = os.readlink(path) symlink_target = os.readlink(path)