/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2005-06-02 02:41:33 UTC
  • Revision ID: mbp@sourcefrog.net-20050602024133-bb6271c689b3034a
- Improved bash completion script
  contributed by Sven Wilhelm

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
 
from bzrlib.trace import mutter
19
 
from bzrlib.errors import BzrError
20
 
from bzrlib.delta import compare_trees
 
18
from trace import mutter
 
19
from errors import BzrError
21
20
 
22
 
# TODO: Rather than building a changeset object, we should probably
23
 
# invoke callbacks on an object.  That object can either accumulate a
24
 
# list, write them out directly, etc etc.
25
21
 
26
22
def internal_diff(old_label, oldlines, new_label, newlines, to_file):
27
23
    import difflib
42
38
    if not oldlines and not newlines:
43
39
        return
44
40
 
 
41
    nonl = False
 
42
 
 
43
    if oldlines and (oldlines[-1][-1] != '\n'):
 
44
        oldlines[-1] += '\n'
 
45
        nonl = True
 
46
    if newlines and (newlines[-1][-1] != '\n'):
 
47
        newlines[-1] += '\n'
 
48
        nonl = True
 
49
 
45
50
    ud = difflib.unified_diff(oldlines, newlines,
46
51
                              fromfile=old_label, tofile=new_label)
47
52
 
54
59
        ud = list(ud)
55
60
        ud[2] = ud[2].replace('+1,0', '+0,0')
56
61
 
57
 
    for line in ud:
58
 
        to_file.write(line)
59
 
        if not line.endswith('\n'):
60
 
            to_file.write("\n\\ No newline at end of file\n")
 
62
    to_file.writelines(ud)
 
63
    if nonl:
 
64
        print >>to_file, "\\ No newline at end of file"
61
65
    print >>to_file
62
66
 
63
67
 
205
209
                          specific_files=specific_files)
206
210
 
207
211
    for path, file_id, kind in delta.removed:
208
 
        print >>to_file, '*** removed %s %r' % (kind, path)
 
212
        print '*** removed %s %r' % (kind, path)
209
213
        if kind == 'file':
210
214
            diff_file(old_label + path,
211
215
                      old_tree.get_file(file_id).readlines(),
214
218
                      to_file)
215
219
 
216
220
    for path, file_id, kind in delta.added:
217
 
        print >>to_file, '*** added %s %r' % (kind, path)
 
221
        print '*** added %s %r' % (kind, path)
218
222
        if kind == 'file':
219
223
            diff_file(DEVNULL,
220
224
                      [],
223
227
                      to_file)
224
228
 
225
229
    for old_path, new_path, file_id, kind, text_modified in delta.renamed:
226
 
        print >>to_file, '*** renamed %s %r => %r' % (kind, old_path, new_path)
 
230
        print '*** renamed %s %r => %r' % (kind, old_path, new_path)
227
231
        if text_modified:
228
232
            diff_file(old_label + old_path,
229
233
                      old_tree.get_file(file_id).readlines(),
232
236
                      to_file)
233
237
 
234
238
    for path, file_id, kind in delta.modified:
235
 
        print >>to_file, '*** modified %s %r' % (kind, path)
 
239
        print '*** modified %s %r' % (kind, path)
236
240
        if kind == 'file':
237
241
            diff_file(old_label + path,
238
242
                      old_tree.get_file(file_id).readlines(),
242
246
 
243
247
 
244
248
 
245
 
 
246
 
 
 
249
class TreeDelta(object):
 
250
    """Describes changes from one tree to another.
 
251
 
 
252
    Contains four lists:
 
253
 
 
254
    added
 
255
        (path, id, kind)
 
256
    removed
 
257
        (path, id, kind)
 
258
    renamed
 
259
        (oldpath, newpath, id, kind, text_modified)
 
260
    modified
 
261
        (path, id, kind)
 
262
    unchanged
 
263
        (path, id, kind)
 
264
 
 
265
    Each id is listed only once.
 
266
 
 
267
    Files that are both modified and renamed are listed only in
 
268
    renamed, with the text_modified flag true.
 
269
 
 
270
    The lists are normally sorted when the delta is created.
 
271
    """
 
272
    def __init__(self):
 
273
        self.added = []
 
274
        self.removed = []
 
275
        self.renamed = []
 
276
        self.modified = []
 
277
        self.unchanged = []
 
278
 
 
279
 
 
280
    def touches_file_id(self, file_id):
 
281
        """Return True if file_id is modified by this delta."""
 
282
        for l in self.added, self.removed, self.modified:
 
283
            for v in l:
 
284
                if v[1] == file_id:
 
285
                    return True
 
286
        for v in self.renamed:
 
287
            if v[2] == file_id:
 
288
                return True
 
289
        return False
 
290
            
 
291
 
 
292
    def show(self, to_file, show_ids=False, show_unchanged=False):
 
293
        def show_list(files):
 
294
            for path, fid, kind in files:
 
295
                if kind == 'directory':
 
296
                    path += '/'
 
297
                elif kind == 'symlink':
 
298
                    path += '@'
 
299
                    
 
300
                if show_ids:
 
301
                    print >>to_file, '  %-30s %s' % (path, fid)
 
302
                else:
 
303
                    print >>to_file, ' ', path
 
304
            
 
305
        if self.removed:
 
306
            print >>to_file, 'removed:'
 
307
            show_list(self.removed)
 
308
                
 
309
        if self.added:
 
310
            print >>to_file, 'added:'
 
311
            show_list(self.added)
 
312
 
 
313
        if self.renamed:
 
314
            print >>to_file, 'renamed:'
 
315
            for oldpath, newpath, fid, kind, text_modified in self.renamed:
 
316
                if show_ids:
 
317
                    print >>to_file, '  %s => %s %s' % (oldpath, newpath, fid)
 
318
                else:
 
319
                    print >>to_file, '  %s => %s' % (oldpath, newpath)
 
320
                    
 
321
        if self.modified:
 
322
            print >>to_file, 'modified:'
 
323
            show_list(self.modified)
 
324
            
 
325
        if show_unchanged and self.unchanged:
 
326
            print >>to_file, 'unchanged:'
 
327
            show_list(self.unchanged)
 
328
 
 
329
 
 
330
 
 
331
def compare_trees(old_tree, new_tree, want_unchanged, specific_files=None):
 
332
    """Describe changes from one tree to another.
 
333
 
 
334
    Returns a TreeDelta with details of added, modified, renamed, and
 
335
    deleted entries.
 
336
 
 
337
    The root entry is specifically exempt.
 
338
 
 
339
    This only considers versioned files.
 
340
 
 
341
    want_unchanged
 
342
        If true, also list files unchanged from one version to
 
343
        the next.
 
344
 
 
345
    specific_files
 
346
        If true, only check for changes to specified names or
 
347
        files within them.
 
348
    """
 
349
 
 
350
    from osutils import is_inside_any
 
351
    
 
352
    old_inv = old_tree.inventory
 
353
    new_inv = new_tree.inventory
 
354
    delta = TreeDelta()
 
355
    mutter('start compare_trees')
 
356
 
 
357
    # TODO: match for specific files can be rather smarter by finding
 
358
    # the IDs of those files up front and then considering only that.
 
359
 
 
360
    for file_id in old_tree:
 
361
        if file_id in new_tree:
 
362
            kind = old_inv.get_file_kind(file_id)
 
363
            assert kind == new_inv.get_file_kind(file_id)
 
364
            
 
365
            assert kind in ('file', 'directory', 'symlink', 'root_directory'), \
 
366
                   'invalid file kind %r' % kind
 
367
 
 
368
            if kind == 'root_directory':
 
369
                continue
 
370
            
 
371
            old_path = old_inv.id2path(file_id)
 
372
            new_path = new_inv.id2path(file_id)
 
373
 
 
374
            if specific_files:
 
375
                if (not is_inside_any(specific_files, old_path) 
 
376
                    and not is_inside_any(specific_files, new_path)):
 
377
                    continue
 
378
 
 
379
            if kind == 'file':
 
380
                old_sha1 = old_tree.get_file_sha1(file_id)
 
381
                new_sha1 = new_tree.get_file_sha1(file_id)
 
382
                text_modified = (old_sha1 != new_sha1)
 
383
            else:
 
384
                ## mutter("no text to check for %r %r" % (file_id, kind))
 
385
                text_modified = False
 
386
 
 
387
            # TODO: Can possibly avoid calculating path strings if the
 
388
            # two files are unchanged and their names and parents are
 
389
            # the same and the parents are unchanged all the way up.
 
390
            # May not be worthwhile.
 
391
            
 
392
            if old_path != new_path:
 
393
                delta.renamed.append((old_path, new_path, file_id, kind,
 
394
                                      text_modified))
 
395
            elif text_modified:
 
396
                delta.modified.append((new_path, file_id, kind))
 
397
            elif want_unchanged:
 
398
                delta.unchanged.append((new_path, file_id, kind))
 
399
        else:
 
400
            kind = old_inv.get_file_kind(file_id)
 
401
            old_path = old_inv.id2path(file_id)
 
402
            if specific_files:
 
403
                if not is_inside_any(specific_files, old_path):
 
404
                    continue
 
405
            delta.removed.append((old_path, file_id, kind))
 
406
 
 
407
    mutter('start looking for new files')
 
408
    for file_id in new_inv:
 
409
        if file_id in old_inv:
 
410
            continue
 
411
        new_path = new_inv.id2path(file_id)
 
412
        if specific_files:
 
413
            if not is_inside_any(specific_files, new_path):
 
414
                continue
 
415
        kind = new_inv.get_file_kind(file_id)
 
416
        delta.added.append((new_path, file_id, kind))
 
417
            
 
418
    delta.removed.sort()
 
419
    delta.added.sort()
 
420
    delta.renamed.sort()
 
421
    delta.modified.sort()
 
422
    delta.unchanged.sort()
 
423
 
 
424
    return delta