~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2005-05-11 04:18:51 UTC
  • Revision ID: mbp@sourcefrog.net-20050511041851-a0a7480c958ef86c
- new testing command compare-trees
- change operation of TreeDelta object a bit
  to specify which renamed files also have modified text
- new TreeDelta.show() factored out
- new compare_trees similar to compare_inventories
  but handling WorkingTrees that don't have a SHA-1 
  in the inventory but can get it from cache
- new Inventory.get_file_kind

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
    They may be in different branches and may be working or historical
28
28
    trees.
29
29
 
 
30
    This only compares the versioned files, paying no attention to
 
31
    files which are ignored or unknown.  Those can only be present in
 
32
    working trees and can be reported on separately.
 
33
 
30
34
    Yields a sequence of (state, id, old_name, new_name, kind).
31
35
    Each filename and each id is listed only once.
32
36
    """
33
 
 
34
 
    ## TODO: Compare files before diffing; only mention those that have changed
35
 
 
36
 
    ## TODO: Set nice names in the headers, maybe include diffstat
37
 
 
38
 
    ## TODO: Perhaps make this a generator rather than using
39
 
    ## a callback object?
40
 
 
41
37
    ## TODO: Allow specifying a list of files to compare, rather than
42
38
    ## doing the whole tree?  (Not urgent.)
43
39
 
46
42
    ## stores to look for the files if diffing two branches.  That
47
43
    ## might imply this shouldn't be primarily a Branch method.
48
44
 
49
 
    ## XXX: This doesn't report on unknown files; that can be done
50
 
    ## from a separate method.
51
 
 
52
45
    sha_match_cnt = modified_cnt = 0
53
46
 
54
47
    old_it = old_tree.list_files()
263
256
    removed
264
257
        (path, id)
265
258
    renamed
266
 
        (oldpath, newpath, id)
 
259
        (oldpath, newpath, id, text_modified)
267
260
    modified
268
261
        (path, id)
269
262
 
270
 
    A path may occur in more than one list if it was e.g. deleted
271
 
    under an old id and renamed into place in a new id.
 
263
    Each id is listed only once.
272
264
 
273
 
    Files are listed in either modified or renamed, not both.  In
274
 
    other words, renamed files may also be modified.
 
265
    Files that are both modified and renamed are listed only in
 
266
    renamed, with the text_modified flag true.
275
267
    """
276
268
    def __init__(self):
277
269
        self.added = []
279
271
        self.renamed = []
280
272
        self.modified = []
281
273
 
 
274
    def show(self, to_file, show_ids):
 
275
        if self.removed:
 
276
            print >>to_file, 'removed files:'
 
277
            for path, fid in self.removed:
 
278
                if show_ids:
 
279
                    print >>to_file, '  %-30s %s' % (path, fid)
 
280
                else:
 
281
                    print >>to_file, ' ', path
 
282
        if self.added:
 
283
            print >>to_file, 'added files:'
 
284
            for path, fid in self.added:
 
285
                if show_ids:
 
286
                    print >>to_file, '  %-30s %s' % (path, fid)
 
287
                else:
 
288
                    print >>to_file, '  ' + path
 
289
        if self.renamed:
 
290
            print >>to_file, 'renamed files:'
 
291
            for oldpath, newpath, fid, text_modified in self.renamed:
 
292
                if show_ids:
 
293
                    print >>to_file, '  %s => %s %s' % (oldpath, newpath, fid)
 
294
                else:
 
295
                    print >>to_file, '  %s => %s' % (oldpath, newpath)
 
296
        if self.modified:
 
297
            print >>to_file, 'modified files:'
 
298
            for path, fid in self.modified:
 
299
                if show_ids:
 
300
                    print >>to_file, '  %-30s %s' % (path, fid)
 
301
                else:
 
302
                    print >>to_file, '  ' + path
 
303
 
 
304
        
282
305
 
283
306
def compare_inventories(old_inv, new_inv):
284
307
    """Return a TreeDelta object describing changes between inventories.
305
328
        old_path = old_inv.id2path(fid)
306
329
        new_path = new_inv.id2path(fid)
307
330
 
 
331
        text_modified = (old_ie.text_sha1 != new_ie.text_sha1)
 
332
 
308
333
        if old_path != new_path:
309
 
            delta.renamed.append((old_path, new_path, fid))
310
 
        elif old_ie.text_sha1 != new_ie.text_sha1:
 
334
            delta.renamed.append((old_path, new_path, fid, text_modified))
 
335
        elif text_modified:
311
336
            delta.modified.append((new_path, fid))
312
337
 
313
338
    delta.modified.sort()
314
339
    delta.renamed.sort()    
315
340
 
316
341
    return delta
 
342
 
 
343
 
 
344
 
 
345
 
 
346
def compare_trees(old_tree, new_tree):
 
347
    old_inv = old_tree.inventory
 
348
    new_inv = new_tree.inventory
 
349
    delta = TreeDelta()
 
350
    for file_id in old_inv:
 
351
        if file_id in new_inv:
 
352
            old_path = old_inv.id2path(file_id)
 
353
            new_path = new_inv.id2path(file_id)
 
354
 
 
355
            kind = old_inv.get_file_kind(file_id)
 
356
            assert kind in ('file', 'directory', 'symlink', 'root_directory'), \
 
357
                   'invalid file kind %r' % kind
 
358
            if kind == 'file':
 
359
                old_sha1 = old_tree.get_file_sha1(file_id)
 
360
                new_sha1 = new_tree.get_file_sha1(file_id)
 
361
                text_modified = (old_sha1 != new_sha1)
 
362
            else:
 
363
                ## mutter("no text to check for %r %r" % (file_id, kind))
 
364
                text_modified = False
 
365
            
 
366
            if old_path != new_path:
 
367
                delta.renamed.append((old_path, new_path, file_id, text_modified))
 
368
            elif text_modified:
 
369
                delta.modified.append((new_path, file_id))
 
370
        else:
 
371
            delta.removed.append((old_inv.id2path(file_id), file_id))
 
372
    for file_id in new_inv:
 
373
        if file_id in old_inv:
 
374
            continue
 
375
        delta.added.append((new_inv.id2path(file_id), file_id))
 
376
            
 
377
    delta.removed.sort()
 
378
    delta.added.sort()
 
379
    delta.renamed.sort()
 
380
    delta.modified.sort()
 
381
 
 
382
    return delta