gendiff.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. #!/usr/bin/env python3
  2. """
  3. scripts/gendiff.py:
  4. Clean up control characters and trailing whitespace in the listed source files
  5. and create a unified diff between them.
  6. If more or less than two files are listed on the command line, the cleanup is
  7. performed on all files, but no diff is created.
  8. The source files are assumed to be terminal output captured by the `script`
  9. command.
  10. The cleaned source files are saved with the .clean extension.
  11. """
  12. import sys, re
  13. from difflib import unified_diff
  14. fns = sys.argv[1:3]
  15. diff_opts = sys.argv[4:] if sys.argv[3:4] == ['--'] else None
  16. translate = {
  17. '\r': None,
  18. '\b': '[BS]',
  19. # chr(4): '', # Ctrl-D, EOT
  20. }
  21. def cleanup_file(fn):
  22. # must use binary mode to prevent conversion of DOS CR into newline
  23. with open(fn, 'rb') as fp:
  24. data = fp.read().decode()
  25. def gen_text():
  26. for line in data.split('\n'): # do not use splitlines()
  27. line = line.translate({ord(a):b for a, b in translate.items()})
  28. line = re.sub(r'\s+$', '', line) # trailing whitespace
  29. yield line
  30. ret = list(gen_text())
  31. sys.stderr.write(f'Saving cleaned file to {fn}.clean\n')
  32. with open(f'{fn}.clean', 'w') as fp:
  33. fp.write('\n'.join(ret))
  34. return ret
  35. if len(fns) != 2:
  36. sys.stderr.write(f'{len(fns)} input files. Not generating diff.\n')
  37. cleaned_texts = [cleanup_file(fn) for fn in fns]
  38. if len(fns) == 2:
  39. # chunk headers have trailing newlines, hence the rstrip()
  40. sys.stderr.write('Generating diff\n')
  41. if diff_opts:
  42. from subprocess import run
  43. run(['diff', '-u'] + [f'{fn}.clean' for fn in fns])
  44. else:
  45. print(
  46. f'diff a/{fns[0]} b/{fns[1]}\n' +
  47. '\n'.join(a.rstrip() for a in unified_diff(
  48. *cleaned_texts,
  49. fromfile = f'a/{fns[0]}',
  50. tofile = f'b/{fns[1]}'))
  51. )