Skip to content

Commit

Permalink
core: enhancements for diff mode
Browse files Browse the repository at this point in the history
Now accepts multiple paths. If >2 paths passed, it will tread first and last paths as pivots and compare the rest to them.

E.g. if you diff A B C D E, it would compare {B C D} vs {A E} -- this is useful for debugging 'multiway' comparison
  • Loading branch information
karlicoss committed Mar 13, 2024
1 parent a02a353 commit 779bdc3
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 29 deletions.
17 changes: 9 additions & 8 deletions src/bleanser/core/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def main(*, Normaliser: Type[BaseNormaliser]) -> None:
'max_content_width': 120,
'show_default': True,
}

@click.group(context_settings=context_settings)
def call_main() -> None:
pass
Expand All @@ -28,34 +29,35 @@ def call_main() -> None:
@call_main.command(name='diff', short_help='cleanup two files and diff')
@click.argument('path1' , type=str)
@click.argument('path2' , default=_DEFAULT)
@click.option ('--glob', is_flag=True, default=False, help='Treat the path as glob (in the glob.glob sense)')
@click.option ('--glob' , is_flag=True, default=False , help='Treat the path as glob (in the glob.glob sense)')
@click.option ('--vim' , is_flag=True, default=False , help='Use vimdiff')
@click.option ('--difftool' , type=str , help='Custom difftool to use')
@click.option ('--from', 'from_', type=int , default=None)
@click.option ('--to' , type=int , default=None)
@click.option ('--to' , type=int , default=None , help='non-inclusive, i.e. [from, to)')
def diff(path1: str, path2: Path, *, glob: bool, from_: Optional[int], to: Optional[int], vim: bool, difftool: str) -> None:
path1_: Path
if glob:
assert path2 is cast(Path, _DEFAULT), path2
if to is None:
assert from_ is not None
to = from_ + 2
to = from_ + 2 # by default just compare with the next adjacent element
paths = _get_paths(path=path1, from_=from_, to=to, glob=glob)
assert len(paths) == 2, paths
[path1_, path2] = paths
else:
assert cast(str, path2) is not _DEFAULT
assert from_ is None and to is None # just for sanity
path1_ = Path(path1)
path2 = Path(path2)
paths = [path1_, path2]

from .processor import compute_diff

# meh..
if vim:
difftool = 'vimdiff'
if difftool is not None:
os.environ['DIFFTOOL'] = difftool

for line in compute_diff(path1_, path2, Normaliser=Normaliser):
for line in compute_diff(paths, Normaliser=Normaliser):
print(line)

@call_main.command(name='normalised', short_help='normalise file and dump to stdout')
Expand All @@ -71,7 +73,6 @@ def normalised(path: Path, stdout: bool) -> None:
click.secho(f'You can examine normalised file: {cleaned}', fg='green')
click.pause(info="Press any key when you've finished")


@call_main.command(name='prune', short_help='process & prune files')
@click.argument('path', type=str)
@click.option('--glob', is_flag=True, default=False, help='Treat the path as glob (in the glob.glob sense)')
Expand Down Expand Up @@ -144,7 +145,7 @@ def _get_paths(*, path: str, from_: Optional[int], to: Optional[int], sort_by: s
from_ = 0
if to is None:
to = len(paths)
paths = paths[from_: to]
paths = paths[from_:to]
assert len(paths) > 0

logger.info('processing %d files (%s ... %s)', len(paths), paths[0], paths[-1])
Expand Down
66 changes: 45 additions & 21 deletions src/bleanser/core/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import re
import shutil
import sys
import subprocess
from subprocess import check_call
from tempfile import TemporaryDirectory, gettempdir, NamedTemporaryFile
from time import time
Expand Down Expand Up @@ -1238,24 +1239,47 @@ def stat() -> str:


# TODO write a test for this
def compute_diff(path1: Path, path2: Path, *, Normaliser: Type[BaseNormaliser]) -> List[str]:
with bleanser_tmp_directory() as base_tmp_dir:
n1 = Normaliser(original=path1, base_tmp_dir=base_tmp_dir)
n2 = Normaliser(original=path2, base_tmp_dir=base_tmp_dir)

with n1.do_normalise() as res1, n2.do_normalise() as res2:
# ok, I guess diff_filter=None makes more sense here?
# would mean it shows the whole thing
# meh
difftool = os.environ.get('DIFFTOOL', None)
if difftool is not None:
extras: List[str] = []
if difftool == 'vimdiff':
wrap = ['-c', 'windo set wrap']
# wrap = []
diffopts = ['-c', 'set diffopt=filler,context:0'] # show only diffs and hide identical lines
extras.extend(wrap)
extras.extend(diffopts)

os.execlp(difftool, difftool, *extras, str(res1), str(res2))
return do_diff(res1, res2, diff_filter=None)
def compute_diff(paths: List[Path], *, Normaliser: Type[BaseNormaliser]) -> List[str]:
assert len(paths) >= 2, paths

difftool = os.environ.get('DIFFTOOL', None)
difftool_args: List[str] = []
if difftool == 'vimdiff':
wrap = ['-c', 'windo set wrap']
diffopts = ['-c', 'set diffopt=filler,context:0'] # show only diffs and hide identical lines
difftool_args.extend(wrap)
difftool_args.extend(diffopts)

with bleanser_tmp_directory() as base_tmp_dir, ExitStack() as exit_stack:
results = []
for path in paths:
pn = Normaliser(original=path, base_tmp_dir=base_tmp_dir)
results.append((path, exit_stack.enter_context(pn.do_normalise())))

# if > 2 paths are passed, we're treating first and last path as 'pivots', and comparing to all the stuff in the middle
first = results[0]
last = results[-1]
rest = results[1:-1]

if len(rest) == 0:
group1 = [first]
group2 = [last]
else:
group1 = rest
group2 = [first, last]

logger.info('comparing [ %s ] vs [ %s ]', ' '.join(str(p) for p, _ in group1), ' '.join(str(p) for p, _ in group2))

fs1 = FileSet([r for _, r in group1], wdir=base_tmp_dir)
fs2 = FileSet([r for _, r in group2], wdir=base_tmp_dir)
c1 = fs1.merged
c2 = fs2.merged

if difftool is not None:
# note: we don't want to exec here, otherwise context manager won't have a chance to clean up?
subprocess.run([difftool, *difftool_args, str(c1), str(c2)])
return [] # no need to print again

return do_diff(c1, c2, diff_filter=None)

return [] # ugh, mypy complains "Missing return statement" without it? try to remove later

0 comments on commit 779bdc3

Please sign in to comment.