17
17
from bzrlib.delta import compare_trees
18
18
from bzrlib.errors import BzrError
19
import bzrlib.errors as errors
19
20
from bzrlib.symbol_versioning import *
21
from bzrlib.textfile import check_text_lines
20
22
from bzrlib.trace import mutter
22
24
# TODO: Rather than building a changeset object, we should probably
24
26
# list, write them out directly, etc etc.
26
28
def internal_diff(old_filename, oldlines, new_filename, newlines, to_file,
27
sequence_matcher=None):
29
allow_binary=False, sequence_matcher=None):
28
30
from bzrlib.cdv.cdvdifflib import unified_diff
29
31
from bzrlib.cdv.cdvdifflib import SequenceMatcher
190
196
def diff_cmd_helper(tree, specific_files, external_diff_options,
191
old_revision_spec=None, new_revision_spec=None):
197
old_revision_spec=None, new_revision_spec=None,
198
old_label='a/', new_label='b/'):
192
199
"""Helper for cmd_diff.
227
234
new_tree = spec_tree(new_revision_spec)
229
236
return show_diff_trees(old_tree, new_tree, sys.stdout, specific_files,
230
external_diff_options)
237
external_diff_options,
238
old_label=old_label, new_label=new_label)
233
241
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
234
external_diff_options=None):
242
external_diff_options=None,
243
old_label='a/', new_label='b/'):
235
244
"""Show in text form the changes from one tree to another.
240
249
external_diff_options
241
250
If set, use an external GNU diff and pass these options.
244
252
old_tree.lock_read()
246
254
new_tree.lock_read()
248
256
return _show_diff_trees(old_tree, new_tree, to_file,
249
specific_files, external_diff_options)
257
specific_files, external_diff_options,
258
old_label=old_label, new_label=new_label)
251
260
new_tree.unlock()
256
265
def _show_diff_trees(old_tree, new_tree, to_file,
257
specific_files, external_diff_options):
259
# TODO: Options to control putting on a prefix or suffix, perhaps
260
# as a format string?
266
specific_files, external_diff_options,
267
old_label='a/', new_label='b/' ):
264
269
DEVNULL = '/dev/null'
265
270
# Windows users, don't panic about this filename -- it is a
269
274
# TODO: Generation of pseudo-diffs for added/deleted files could
270
275
# be usefully made into a much faster special case.
277
_raise_if_doubly_unversioned(specific_files, old_tree, new_tree)
272
279
if external_diff_options:
273
280
assert isinstance(external_diff_options, basestring)
274
281
opts = external_diff_options.split()
278
285
diff_file = internal_diff
281
287
delta = compare_trees(old_tree, new_tree, want_unchanged=False,
282
288
specific_files=specific_files)
285
291
for path, file_id, kind in delta.removed:
287
print >>to_file, '=== removed %s %r' % (kind, old_label + path)
293
print >>to_file, '=== removed %s %r' % (kind, path)
288
294
old_tree.inventory[file_id].diff(diff_file, old_label + path, old_tree,
289
295
DEVNULL, None, None, to_file)
290
296
for path, file_id, kind in delta.added:
292
print >>to_file, '=== added %s %r' % (kind, new_label + path)
298
print >>to_file, '=== added %s %r' % (kind, path)
293
299
new_tree.inventory[file_id].diff(diff_file, new_label + path, new_tree,
294
300
DEVNULL, None, None, to_file,
299
305
prop_str = get_prop_change(meta_modified)
300
306
print >>to_file, '=== renamed %s %r => %r%s' % (
301
kind, old_label + old_path, new_label + new_path, prop_str)
307
kind, old_path, new_path, prop_str)
302
308
_maybe_diff_file_or_symlink(old_label, old_path, old_tree, file_id,
303
309
new_label, new_path, new_tree,
304
310
text_modified, kind, to_file, diff_file)
305
311
for path, file_id, kind, text_modified, meta_modified in delta.modified:
307
313
prop_str = get_prop_change(meta_modified)
308
print >>to_file, '=== modified %s %r%s' % (kind, old_label + path,
314
print >>to_file, '=== modified %s %r%s' % (kind, path, prop_str)
310
315
if text_modified:
311
316
_maybe_diff_file_or_symlink(old_label, path, old_tree, file_id,
312
317
new_label, path, new_tree,
313
318
True, kind, to_file, diff_file)
314
320
return has_changes
323
def _raise_if_doubly_unversioned(specific_files, old_tree, new_tree):
324
"""Complain if paths are not versioned in either tree."""
325
if not specific_files:
327
old_unversioned = old_tree.filter_unversioned_files(specific_files)
328
new_unversioned = new_tree.filter_unversioned_files(specific_files)
329
unversioned = old_unversioned.intersection(new_unversioned)
331
raise errors.PathsNotVersionedError(sorted(unversioned))
334
def _raise_if_nonexistent(paths, old_tree, new_tree):
335
"""Complain if paths are not in either inventory or tree.
337
It's OK with the files exist in either tree's inventory, or
338
if they exist in the tree but are not versioned.
340
This can be used by operations such as bzr status that can accept
341
unknown or ignored files.
343
mutter("check paths: %r", paths)
346
s = old_tree.filter_unversioned_files(paths)
347
s = new_tree.filter_unversioned_files(s)
348
s = [path for path in s if not new_tree.has_filename(path)]
350
raise errors.PathsDoNotExist(sorted(s))
317
353
def get_prop_change(meta_modified):
318
354
if meta_modified: