29
24
# compatability - plugins import compare_trees from diff!!!
30
25
# deprecated as of 0.10
31
26
from bzrlib.delta import compare_trees
32
27
from bzrlib.errors import BzrError
28
import bzrlib.errors as errors
33
30
from bzrlib.patiencediff import unified_diff
34
31
import bzrlib.patiencediff
35
32
from bzrlib.symbol_versioning import (deprecated_function,
94
"""Set the env var LANG=C"""
95
osutils.set_or_unset_env('LANG', 'C')
96
osutils.set_or_unset_env('LC_ALL', None)
97
osutils.set_or_unset_env('LC_CTYPE', None)
98
osutils.set_or_unset_env('LANGUAGE', None)
101
def _spawn_external_diff(diffcmd, capture_errors=True):
102
"""Spawn the externall diff process, and return the child handle.
104
:param diffcmd: The command list to spawn
105
:param capture_errors: Capture stderr as well as setting LANG=C.
106
This lets us read and understand the output of diff, and respond
108
:return: A Popen object.
111
if sys.platform == 'win32':
112
# Win32 doesn't support preexec_fn, but that is
113
# okay, because it doesn't support LANG either.
116
preexec_fn = _set_lang_C
117
stderr = subprocess.PIPE
123
pipe = subprocess.Popen(diffcmd,
124
stdin=subprocess.PIPE,
125
stdout=subprocess.PIPE,
127
preexec_fn=preexec_fn)
129
if e.errno == errno.ENOENT:
130
raise errors.NoDiff(str(e))
136
90
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
138
92
"""Display a diff by calling out to the external diff program."""
93
if hasattr(to_file, 'fileno'):
97
out_file = subprocess.PIPE
139
100
# make sure our own output is properly ordered before the diff
193
154
diffcmd.extend(diff_opts)
195
pipe = _spawn_external_diff(diffcmd, capture_errors=True)
196
out,err = pipe.communicate()
157
pipe = subprocess.Popen(diffcmd,
158
stdin=subprocess.PIPE,
161
if e.errno == errno.ENOENT:
162
raise errors.NoDiff(str(e))
167
bzrlib.osutils.pumpfile(pipe.stdout, to_file)
199
# internal_diff() adds a trailing newline, add one here for consistency
202
# 'diff' gives retcode == 2 for all sorts of errors
203
# one of those is 'Binary files differ'.
204
# Bad options could also be the problem.
205
# 'Binary files' is not a real error, so we suppress that error.
208
# Since we got here, we want to make sure to give an i18n error
209
pipe = _spawn_external_diff(diffcmd, capture_errors=False)
210
out, err = pipe.communicate()
212
# Write out the new i18n diff response
213
to_file.write(out+'\n')
214
if pipe.returncode != 2:
215
raise BzrError('external diff failed with exit code 2'
216
' when run with LANG=C, but not when run'
217
' natively: %r' % (diffcmd,))
219
first_line = lang_c_out.split('\n', 1)[0]
220
# Starting with diffutils 2.8.4 the word "binary" was dropped.
221
m = re.match('^(binary )?files.*differ$', first_line, re.I)
223
raise BzrError('external diff failed with exit code 2;'
224
' command: %r' % (diffcmd,))
226
# Binary files differ, just return
229
# If we got to here, we haven't written out the output of diff
170
if rc != 0 and rc != 1:
233
171
# returns 1 if files differ; that's OK
235
173
msg = 'signal %d' % (-rc)
237
175
msg = 'exit code %d' % rc
239
raise BzrError('external diff failed with %s; command: %r'
177
raise BzrError('external diff failed with %s; command: %r' % (rc, diffcmd))
244
179
oldtmpf.close() # and delete