14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
from bzrlib.lazy_import import lazy_import
22
lazy_import(globals(), """
36
# compatability - plugins import compare_trees from diff!!!
37
# deprecated as of 0.10
24
38
from bzrlib.delta import compare_trees
25
from bzrlib.errors import BzrError
26
import bzrlib.errors as errors
28
from bzrlib.patiencediff import unified_diff
29
import bzrlib.patiencediff
30
from bzrlib.symbol_versioning import (deprecated_function,
32
from bzrlib.textfile import check_text_lines
39
from bzrlib.symbol_versioning import (
33
43
from bzrlib.trace import mutter, warning
59
69
if allow_binary is False:
60
check_text_lines(oldlines)
61
check_text_lines(newlines)
70
textfile.check_text_lines(oldlines)
71
textfile.check_text_lines(newlines)
63
73
if sequence_matcher is None:
64
sequence_matcher = bzrlib.patiencediff.PatienceSequenceMatcher
65
ud = unified_diff(oldlines, newlines,
74
sequence_matcher = patiencediff.PatienceSequenceMatcher
75
ud = patiencediff.unified_diff(oldlines, newlines,
66
76
fromfile=old_filename.encode(path_encoding),
67
77
tofile=new_filename.encode(path_encoding),
68
78
sequencematcher=sequence_matcher)
99
"""Set the env var LANG=C"""
100
osutils.set_or_unset_env('LANG', 'C')
101
osutils.set_or_unset_env('LC_ALL', None)
102
osutils.set_or_unset_env('LC_CTYPE', None)
103
osutils.set_or_unset_env('LANGUAGE', None)
106
def _spawn_external_diff(diffcmd, capture_errors=True):
107
"""Spawn the externall diff process, and return the child handle.
109
:param diffcmd: The command list to spawn
110
:param capture_errors: Capture stderr as well as setting LANG=C.
111
This lets us read and understand the output of diff, and respond
113
:return: A Popen object.
116
if sys.platform == 'win32':
117
# Win32 doesn't support preexec_fn, but that is
118
# okay, because it doesn't support LANG either.
121
preexec_fn = _set_lang_C
122
stderr = subprocess.PIPE
128
pipe = subprocess.Popen(diffcmd,
129
stdin=subprocess.PIPE,
130
stdout=subprocess.PIPE,
132
preexec_fn=preexec_fn)
134
if e.errno == errno.ENOENT:
135
raise errors.NoDiff(str(e))
88
141
def external_diff(old_filename, oldlines, new_filename, newlines, to_file,
90
143
"""Display a diff by calling out to the external diff program."""
91
if hasattr(to_file, 'fileno'):
95
out_file = subprocess.PIPE
98
144
# make sure our own output is properly ordered before the diff
152
198
diffcmd.extend(diff_opts)
155
pipe = subprocess.Popen(diffcmd,
156
stdin=subprocess.PIPE,
159
if e.errno == errno.ENOENT:
160
raise errors.NoDiff(str(e))
165
bzrlib.osutils.pumpfile(pipe.stdout, to_file)
200
pipe = _spawn_external_diff(diffcmd, capture_errors=True)
201
out,err = pipe.communicate()
168
if rc != 0 and rc != 1:
204
# internal_diff() adds a trailing newline, add one here for consistency
207
# 'diff' gives retcode == 2 for all sorts of errors
208
# one of those is 'Binary files differ'.
209
# Bad options could also be the problem.
210
# 'Binary files' is not a real error, so we suppress that error.
213
# Since we got here, we want to make sure to give an i18n error
214
pipe = _spawn_external_diff(diffcmd, capture_errors=False)
215
out, err = pipe.communicate()
217
# Write out the new i18n diff response
218
to_file.write(out+'\n')
219
if pipe.returncode != 2:
220
raise errors.BzrError(
221
'external diff failed with exit code 2'
222
' when run with LANG=C, but not when run'
223
' natively: %r' % (diffcmd,))
225
first_line = lang_c_out.split('\n', 1)[0]
226
# Starting with diffutils 2.8.4 the word "binary" was dropped.
227
m = re.match('^(binary )?files.*differ$', first_line, re.I)
229
raise errors.BzrError('external diff failed with exit code 2;'
230
' command: %r' % (diffcmd,))
232
# Binary files differ, just return
235
# If we got to here, we haven't written out the output of diff
169
239
# returns 1 if files differ; that's OK
171
241
msg = 'signal %d' % (-rc)
173
243
msg = 'exit code %d' % rc
175
raise BzrError('external diff failed with %s; command: %r' % (rc, diffcmd))
245
raise errors.BzrError('external diff failed with %s; command: %r'
177
250
oldtmpf.close() # and delete
333
406
diff_file = internal_diff
335
delta = compare_trees(old_tree, new_tree, want_unchanged=False,
336
specific_files=specific_files,
337
extra_trees=extra_trees, require_versioned=True)
408
delta = new_tree.changes_from(old_tree,
409
specific_files=specific_files,
410
extra_trees=extra_trees, require_versioned=True)
340
413
for path, file_id, kind in delta.removed: