/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: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 Canonical Ltd.
 
1
# Copyright (C) 2005-2010 Canonical Ltd.
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
import difflib
18
18
import os
19
19
import re
20
 
import shutil
21
20
import string
22
21
import sys
23
22
 
31
30
from bzrlib import (
32
31
    branch as _mod_branch,
33
32
    bzrdir,
34
 
    commands,
 
33
    cmdline,
 
34
    cleanup,
35
35
    errors,
36
36
    osutils,
37
37
    patiencediff,
43
43
from bzrlib.workingtree import WorkingTree
44
44
""")
45
45
 
 
46
from bzrlib.registry import (
 
47
    Registry,
 
48
    )
46
49
from bzrlib.symbol_versioning import (
47
50
    deprecated_function,
 
51
    deprecated_in,
48
52
    )
49
53
from bzrlib.trace import mutter, note, warning
50
54
 
286
290
                        new_abspath, e)
287
291
 
288
292
 
 
293
@deprecated_function(deprecated_in((2, 2, 0)))
289
294
def get_trees_and_branches_to_diff(path_list, revision_specs, old_url, new_url,
290
295
                                   apply_view=True):
291
296
    """Get the trees and specific files to diff given a list of paths.
310
315
    :returns:
311
316
        a tuple of (old_tree, new_tree, old_branch, new_branch,
312
317
        specific_files, extra_trees) where extra_trees is a sequence of
313
 
        additional trees to search in for file-ids.
 
318
        additional trees to search in for file-ids.  The trees and branches
 
319
        are not locked.
 
320
    """
 
321
    op = cleanup.OperationWithCleanups(get_trees_and_branches_to_diff_locked)
 
322
    return op.run_simple(path_list, revision_specs, old_url, new_url,
 
323
            op.add_cleanup, apply_view=apply_view)
 
324
    
 
325
 
 
326
def get_trees_and_branches_to_diff_locked(
 
327
    path_list, revision_specs, old_url, new_url, add_cleanup, apply_view=True):
 
328
    """Get the trees and specific files to diff given a list of paths.
 
329
 
 
330
    This method works out the trees to be diff'ed and the files of
 
331
    interest within those trees.
 
332
 
 
333
    :param path_list:
 
334
        the list of arguments passed to the diff command
 
335
    :param revision_specs:
 
336
        Zero, one or two RevisionSpecs from the diff command line,
 
337
        saying what revisions to compare.
 
338
    :param old_url:
 
339
        The url of the old branch or tree. If None, the tree to use is
 
340
        taken from the first path, if any, or the current working tree.
 
341
    :param new_url:
 
342
        The url of the new branch or tree. If None, the tree to use is
 
343
        taken from the first path, if any, or the current working tree.
 
344
    :param add_cleanup:
 
345
        a callable like Command.add_cleanup.  get_trees_and_branches_to_diff
 
346
        will register cleanups that must be run to unlock the trees, etc.
 
347
    :param apply_view:
 
348
        if True and a view is set, apply the view or check that the paths
 
349
        are within it
 
350
    :returns:
 
351
        a tuple of (old_tree, new_tree, old_branch, new_branch,
 
352
        specific_files, extra_trees) where extra_trees is a sequence of
 
353
        additional trees to search in for file-ids.  The trees and branches
 
354
        will be read-locked until the cleanups registered via the add_cleanup
 
355
        param are run.
314
356
    """
315
357
    # Get the old and new revision specs
316
358
    old_revision_spec = None
339
381
        default_location = path_list[0]
340
382
        other_paths = path_list[1:]
341
383
 
 
384
    def lock_tree_or_branch(wt, br):
 
385
        if wt is not None:
 
386
            wt.lock_read()
 
387
            add_cleanup(wt.unlock)
 
388
        elif br is not None:
 
389
            br.lock_read()
 
390
            add_cleanup(br.unlock)
 
391
 
342
392
    # Get the old location
343
393
    specific_files = []
344
394
    if old_url is None:
345
395
        old_url = default_location
346
396
    working_tree, branch, relpath = \
347
397
        bzrdir.BzrDir.open_containing_tree_or_branch(old_url)
 
398
    lock_tree_or_branch(working_tree, branch)
348
399
    if consider_relpath and relpath != '':
349
400
        if working_tree is not None and apply_view:
350
401
            views.check_path_in_view(working_tree, relpath)
358
409
    if new_url != old_url:
359
410
        working_tree, branch, relpath = \
360
411
            bzrdir.BzrDir.open_containing_tree_or_branch(new_url)
 
412
        lock_tree_or_branch(working_tree, branch)
361
413
        if consider_relpath and relpath != '':
362
414
            if working_tree is not None and apply_view:
363
415
                views.check_path_in_view(working_tree, relpath)
411
463
                    old_label='a/', new_label='b/',
412
464
                    extra_trees=None,
413
465
                    path_encoding='utf8',
414
 
                    using=None):
 
466
                    using=None,
 
467
                    format_cls=None):
415
468
    """Show in text form the changes from one tree to another.
416
469
 
417
 
    to_file
418
 
        The output stream.
419
 
 
420
 
    specific_files
421
 
        Include only changes to these files - None for all changes.
422
 
 
423
 
    external_diff_options
424
 
        If set, use an external GNU diff and pass these options.
425
 
 
426
 
    extra_trees
427
 
        If set, more Trees to use for looking up file ids
428
 
 
429
 
    path_encoding
430
 
        If set, the path will be encoded as specified, otherwise is supposed
431
 
        to be utf8
 
470
    :param to_file: The output stream.
 
471
    :param specific_files:Include only changes to these files - None for all
 
472
        changes.
 
473
    :param external_diff_options: If set, use an external GNU diff and pass 
 
474
        these options.
 
475
    :param extra_trees: If set, more Trees to use for looking up file ids
 
476
    :param path_encoding: If set, the path will be encoded as specified, 
 
477
        otherwise is supposed to be utf8
 
478
    :param format_cls: Formatter class (DiffTree subclass)
432
479
    """
 
480
    if format_cls is None:
 
481
        format_cls = DiffTree
433
482
    old_tree.lock_read()
434
483
    try:
435
484
        if extra_trees is not None:
437
486
                tree.lock_read()
438
487
        new_tree.lock_read()
439
488
        try:
440
 
            differ = DiffTree.from_trees_options(old_tree, new_tree, to_file,
441
 
                                                 path_encoding,
442
 
                                                 external_diff_options,
443
 
                                                 old_label, new_label, using)
 
489
            differ = format_cls.from_trees_options(old_tree, new_tree, to_file,
 
490
                                                   path_encoding,
 
491
                                                   external_diff_options,
 
492
                                                   old_label, new_label, using)
444
493
            return differ.show_diff(specific_files, extra_trees)
445
494
        finally:
446
495
            new_tree.unlock()
453
502
 
454
503
def _patch_header_date(tree, file_id, path):
455
504
    """Returns a timestamp suitable for use in a patch header."""
456
 
    mtime = tree.get_file_mtime(file_id, path)
 
505
    try:
 
506
        mtime = tree.get_file_mtime(file_id, path)
 
507
    except errors.FileTimestampUnavailable:
 
508
        mtime = 0
457
509
    return timestamp.format_patch_date(mtime)
458
510
 
459
511
 
680
732
    @classmethod
681
733
    def from_string(klass, command_string, old_tree, new_tree, to_file,
682
734
                    path_encoding='utf-8'):
683
 
        command_template = commands.shlex_split_unicode(command_string)
 
735
        command_template = cmdline.split(command_string)
684
736
        if '@' not in command_string:
685
737
            command_template.extend(['@old_path', '@new_path'])
686
738
        return klass(command_template, old_tree, new_tree, to_file,
745
797
                target.close()
746
798
        finally:
747
799
            source.close()
 
800
        try:
 
801
            mtime = tree.get_file_mtime(file_id)
 
802
        except errors.FileTimestampUnavailable:
 
803
            pass
 
804
        else:
 
805
            os.utime(full_path, (mtime, mtime))
748
806
        if not allow_write:
749
807
            osutils.make_readonly(full_path)
750
 
        mtime = tree.get_file_mtime(file_id)
751
 
        os.utime(full_path, (mtime, mtime))
752
808
        return full_path
753
809
 
754
810
    def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
876
932
    def show_diff(self, specific_files, extra_trees=None):
877
933
        """Write tree diff to self.to_file
878
934
 
879
 
        :param sepecific_files: the specific files to compare (recursive)
 
935
        :param specific_files: the specific files to compare (recursive)
880
936
        :param extra_trees: extra trees to use for mapping paths to file_ids
881
937
        """
882
938
        try:
972
1028
            if error_path is None:
973
1029
                error_path = old_path
974
1030
            raise errors.NoDiffFound(error_path)
 
1031
 
 
1032
 
 
1033
format_registry = Registry()
 
1034
format_registry.register('default', DiffTree)