92
"""Set the env var LANG=C"""
93
os.environ['LANG'] = 'C'
96
def _spawn_external_diff(diffcmd, capture_errors=True):
97
"""Spawn the externall diff process, and return the child handle.
99
:param diffcmd: The command list to spawn
100
:param capture_errors: Capture stderr as well as setting LANG=C.
101
This lets us read and understand the output of diff, and respond
103
:return: A Popen object.
106
preexec_fn = _set_lang_C
107
stderr = subprocess.PIPE
113
pipe = subprocess.Popen(diffcmd,
114
stdin=subprocess.PIPE,
115
stdout=subprocess.PIPE,
117
preexec_fn=preexec_fn)
119
if e.errno == errno.ENOENT:
120
raise errors.NoDiff(str(e))
126
90
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
128
92
"""Display a diff by calling out to the external diff program."""
93
if hasattr(to_file, 'fileno'):
97
out_file = subprocess.PIPE
129
100
# make sure our own output is properly ordered before the diff
183
154
diffcmd.extend(diff_opts)
185
pipe = _spawn_external_diff(diffcmd, capture_errors=True)
186
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)
189
# internal_diff() adds a trailing newline, add one here for consistency
192
# 'diff' gives retcode == 2 for all sorts of errors
193
# one of those is 'Binary files differ'.
194
# Bad options could also be the problem.
195
# 'Binary files' is not a real error, so we suppress that error.
198
# Since we got here, we want to make sure to give an i18n error
199
pipe = _spawn_external_diff(diffcmd, capture_errors=False)
200
out, err = pipe.communicate()
202
# Write out the new i18n diff response
203
to_file.write(out+'\n')
204
if pipe.returncode != 2:
205
raise BzrError('external diff failed with exit code 2'
206
' when run with LANG=C, but not when run'
207
' natively: %r' % (diffcmd,))
209
first_line = lang_c_out.split('\n', 1)[0]
210
# Starting with diffutils 2.8.4 the word "binary" was dropped.
211
m = re.match('^(binary )?files.*differ$', first_line, re.I)
213
raise BzrError('external diff failed with exit code 2;'
214
' command: %r' % (diffcmd,))
216
# Binary files differ, just return
219
# If we got to here, we haven't written out the output of diff
170
if rc != 0 and rc != 1:
223
171
# returns 1 if files differ; that's OK
225
173
msg = 'signal %d' % (-rc)
227
175
msg = 'exit code %d' % rc
229
raise BzrError('external diff failed with %s; command: %r'
177
raise BzrError('external diff failed with %s; command: %r' % (rc, diffcmd))
234
179
oldtmpf.close() # and delete