Skip to content

Commit 10114cb

Browse files
Merge pull request #14 from source-foundry/external-diff
Add support for external diff tools as the source of TTX diff output
2 parents 792f5a8 + 7d72026 commit 10114cb

10 files changed

+1067
-175
lines changed

lib/fdiff/__main__.py

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from fdiff import __version__
88
from fdiff.color import color_unified_diff_line
9-
from fdiff.diff import u_diff
9+
from fdiff.diff import external_diff, u_diff
1010
from fdiff.textiter import head, tail
1111
from fdiff.utils import file_exists, get_tables_argument_list
1212

@@ -62,6 +62,7 @@ def run(argv):
6262
parser.add_argument(
6363
"--nomp", action="store_true", help="Do not use multi process optimizations"
6464
)
65+
parser.add_argument("--external", type=str, help="Run external diff tool command")
6566
parser.add_argument("PREFILE", help="Font file path/URL 1")
6667
parser.add_argument("POSTFILE", help="Font file path/URL 2")
6768

@@ -105,10 +106,6 @@ def run(argv):
105106
#
106107
# /////////////////////////////////////////////////////////
107108

108-
# ---------------
109-
# Unified diff
110-
# ---------------
111-
112109
# parse explicitly included or excluded tables in
113110
# the command line arguments
114111
# set as a Python list if it was defined on the command line
@@ -117,44 +114,88 @@ def run(argv):
117114
exclude_list = get_tables_argument_list(args.exclude)
118115

119116
# flip logic of the command line flag for multi process
120-
# optimizations for use as a u_diff function argument
117+
# optimization use
121118
use_mp = not args.nomp
122119

123-
# perform the unified diff analysis
124-
try:
125-
diff = u_diff(
126-
args.PREFILE,
127-
args.POSTFILE,
128-
context_lines=args.lines,
129-
include_tables=include_list,
130-
exclude_tables=exclude_list,
131-
use_multiprocess=use_mp,
132-
)
133-
except Exception as e:
134-
sys.stderr.write(f"[*] ERROR: {e}{os.linesep}")
135-
sys.exit(1)
136-
137-
# re-define the line contents of the diff iterable
138-
# if head or tail is requested
139-
if args.head:
140-
iterable = head(diff, args.head)
141-
elif args.tail:
142-
iterable = tail(diff, args.tail)
143-
else:
144-
iterable = diff
145-
146-
# print unified diff results to standard output stream
147-
has_diff = False
148-
if args.color:
149-
for line in iterable:
150-
has_diff = True
151-
sys.stdout.write(color_unified_diff_line(line))
120+
if args.external:
121+
# ------------------------------
122+
# External executable tool diff
123+
# ------------------------------
124+
# head and tail are not supported when external diff tool is called
125+
if args.head or args.tail:
126+
sys.stderr.write(
127+
f"[ERROR] The head and tail options are not supported with external diff executable calls.{os.linesep}"
128+
)
129+
sys.exit(1)
130+
131+
# lines of context filter is not supported when external diff tool is called
132+
if args.lines != 3:
133+
sys.stderr.write(
134+
f"[ERROR] The lines option is not supported with external diff executable calls.{os.linesep}"
135+
)
136+
sys.exit(1)
137+
138+
try:
139+
diff = external_diff(
140+
args.external,
141+
args.PREFILE,
142+
args.POSTFILE,
143+
include_tables=include_list,
144+
exclude_tables=exclude_list,
145+
use_multiprocess=use_mp,
146+
)
147+
148+
# write stdout from external tool
149+
for line, exit_code in diff:
150+
# format with color if color flag is entered on command line
151+
if args.color:
152+
sys.stdout.write(color_unified_diff_line(line))
153+
else:
154+
sys.stdout.write(line)
155+
if exit_code is not None:
156+
sys.exit(exit_code)
157+
except Exception as e:
158+
sys.stderr.write(f"[*] ERROR: {e}{os.linesep}")
159+
sys.exit(1)
152160
else:
153-
for line in iterable:
154-
has_diff = True
155-
sys.stdout.write(line)
156-
157-
# if no difference was found, tell the user instead of
158-
# simply closing with zero exit status code.
159-
if not has_diff:
160-
print("[*] There is no difference between the files.")
161+
# ---------------
162+
# Unified diff
163+
# ---------------
164+
# perform the unified diff analysis
165+
try:
166+
diff = u_diff(
167+
args.PREFILE,
168+
args.POSTFILE,
169+
context_lines=args.lines,
170+
include_tables=include_list,
171+
exclude_tables=exclude_list,
172+
use_multiprocess=use_mp,
173+
)
174+
except Exception as e:
175+
sys.stderr.write(f"[*] ERROR: {e}{os.linesep}")
176+
sys.exit(1)
177+
178+
# re-define the line contents of the diff iterable
179+
# if head or tail is requested
180+
if args.head:
181+
iterable = head(diff, args.head)
182+
elif args.tail:
183+
iterable = tail(diff, args.tail)
184+
else:
185+
iterable = diff
186+
187+
# print unified diff results to standard output stream
188+
has_diff = False
189+
if args.color:
190+
for line in iterable:
191+
has_diff = True
192+
sys.stdout.write(color_unified_diff_line(line))
193+
else:
194+
for line in iterable:
195+
has_diff = True
196+
sys.stdout.write(line)
197+
198+
# if no difference was found, tell the user instead of
199+
# simply closing with zero exit status code.
200+
if not has_diff:
201+
print("[*] There is no difference between the files.")

lib/fdiff/color.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,16 @@ def color_unified_diff_line(line):
2222
on the unified diff line type."""
2323
if line[0:2] == "+ ":
2424
return f"{green_start}{line}{reset}"
25+
elif line == "+\n":
26+
# some lines are formatted as hyphen only with no other characters
27+
# this indicates an added empty line
28+
return f"{green_start}{line}{reset}"
2529
elif line[0:2] == "- ":
2630
return f"{red_start}{line}{reset}"
31+
elif line == "-\n":
32+
# some lines are formatted as hyphen only with no other characters
33+
# this indicates a deleted empty line
34+
return f"{red_start}{line}{reset}"
2735
elif line[0:3] == "@@ ":
2836
return f"{cyan_start}{line}{reset}"
2937
elif line[0:4] == "--- ":

0 commit comments

Comments
 (0)