~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-01 12:53:09 UTC
  • mfrom: (4988.6.2 private-serialise-inv)
  • Revision ID: pqm@pqm.ubuntu.com-20100201125309-4nitvjqjlp05b7vt
(Jelmer) Make Repository.serialise_inventory private.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
import warnings
18
17
 
19
18
from bzrlib import (
20
19
    branch as _mod_branch,
27
26
    merge3,
28
27
    osutils,
29
28
    patiencediff,
 
29
    progress,
30
30
    revision as _mod_revision,
31
31
    textfile,
32
32
    trace,
36
36
    ui,
37
37
    versionedfile
38
38
    )
39
 
from bzrlib.cleanup import OperationWithCleanups
40
39
from bzrlib.symbol_versioning import (
41
40
    deprecated_in,
42
41
    deprecated_method,
46
45
 
47
46
def transform_tree(from_tree, to_tree, interesting_ids=None):
48
47
    from_tree.lock_tree_write()
49
 
    operation = OperationWithCleanups(merge_inner)
50
 
    operation.add_cleanup(from_tree.unlock)
51
 
    operation.run_simple(from_tree.branch, to_tree, from_tree,
52
 
        ignore_zero=True, interesting_ids=interesting_ids, this_tree=from_tree)
 
48
    try:
 
49
        merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True,
 
50
                    interesting_ids=interesting_ids, this_tree=from_tree)
 
51
    finally:
 
52
        from_tree.unlock()
53
53
 
54
54
 
55
55
class MergeHooks(hooks.Hooks):
99
99
    This is a base class for concrete custom file merging logic. Concrete
100
100
    classes should implement ``merge_text``.
101
101
 
102
 
    See ``bzrlib.plugins.news_merge.news_merge`` for an example concrete class.
103
 
    
104
102
    :ivar affected_files: The configured file paths to merge.
105
 
 
106
103
    :cvar name_prefix: The prefix to use when looking up configuration
107
 
        details. <name_prefix>_merge_files describes the files targeted by the
108
 
        hook for example.
109
 
        
 
104
        details.
110
105
    :cvar default_files: The default file paths to merge when no configuration
111
106
        is present.
112
107
    """
123
118
            raise ValueError("name_prefix must be set.")
124
119
 
125
120
    def filename_matches_config(self, params):
126
 
        """Check whether the file should call the merge hook.
127
 
 
128
 
        <name_prefix>_merge_files configuration variable is a list of files
129
 
        that should use the hook.
130
 
        """
131
121
        affected_files = self.affected_files
132
122
        if affected_files is None:
133
123
            config = self.merger.this_tree.branch.get_config()
160
150
            # option.
161
151
            not self.filename_matches_config(params)):
162
152
            return 'not_applicable', None
163
 
        return self.merge_text(params)
 
153
        return self.merge_text(self, params)
164
154
 
165
155
    def merge_text(self, params):
166
156
        """Merge the byte contents of a single file.
237
227
        self.interesting_files = None
238
228
        self.show_base = False
239
229
        self.reprocess = False
240
 
        if pb is not None:
241
 
            warnings.warn("pb parameter to Merger() is deprecated and ignored")
 
230
        if pb is None:
 
231
            pb = progress.DummyProgress()
 
232
        self._pb = pb
242
233
        self.pp = None
243
234
        self.recurse = recurse
244
235
        self.change_reporter = change_reporter
454
445
    def _add_parent(self):
455
446
        new_parents = self.this_tree.get_parent_ids() + [self.other_rev_id]
456
447
        new_parent_trees = []
457
 
        operation = OperationWithCleanups(self.this_tree.set_parent_trees)
458
448
        for revision_id in new_parents:
459
449
            try:
460
450
                tree = self.revision_tree(revision_id)
462
452
                tree = None
463
453
            else:
464
454
                tree.lock_read()
465
 
                operation.add_cleanup(tree.unlock)
466
455
            new_parent_trees.append((revision_id, tree))
467
 
        operation.run_simple(new_parent_trees, allow_leftmost_as_ghost=True)
 
456
        try:
 
457
            self.this_tree.set_parent_trees(new_parent_trees,
 
458
                                            allow_leftmost_as_ghost=True)
 
459
        finally:
 
460
            for _revision_id, tree in new_parent_trees:
 
461
                if tree is not None:
 
462
                    tree.unlock()
468
463
 
469
464
    def set_other(self, other_revision, possible_transports=None):
470
465
        """Set the revision and tree to merge from.
593
588
                  'other_tree': self.other_tree,
594
589
                  'interesting_ids': self.interesting_ids,
595
590
                  'interesting_files': self.interesting_files,
596
 
                  'this_branch': self.this_branch,
 
591
                  'pp': self.pp, 'this_branch': self.this_branch,
597
592
                  'do_merge': False}
598
593
        if self.merge_type.requires_base:
599
594
            kwargs['base_tree'] = self.base_tree
617
612
        if self._is_criss_cross and getattr(self.merge_type,
618
613
                                            'supports_lca_trees', False):
619
614
            kwargs['lca_trees'] = self._lca_trees
620
 
        return self.merge_type(pb=None,
 
615
        return self.merge_type(pb=self._pb,
621
616
                               change_reporter=self.change_reporter,
622
617
                               **kwargs)
623
618
 
624
 
    def _do_merge_to(self):
625
 
        merge = self.make_merger()
 
619
    def _do_merge_to(self, merge):
626
620
        if self.other_branch is not None:
627
621
            self.other_branch.update_references(self.this_branch)
628
622
        merge.do_merge()
642
636
                    sub_tree.branch.repository.revision_tree(base_revision)
643
637
                sub_merge.base_rev_id = base_revision
644
638
                sub_merge.do_merge()
645
 
        return merge
646
639
 
647
640
    def do_merge(self):
648
 
        operation = OperationWithCleanups(self._do_merge_to)
649
641
        self.this_tree.lock_tree_write()
650
 
        operation.add_cleanup(self.this_tree.unlock)
651
 
        if self.base_tree is not None:
652
 
            self.base_tree.lock_read()
653
 
            operation.add_cleanup(self.base_tree.unlock)
654
 
        if self.other_tree is not None:
655
 
            self.other_tree.lock_read()
656
 
            operation.add_cleanup(self.other_tree.unlock)
657
 
        merge = operation.run_simple()
 
642
        try:
 
643
            if self.base_tree is not None:
 
644
                self.base_tree.lock_read()
 
645
            try:
 
646
                if self.other_tree is not None:
 
647
                    self.other_tree.lock_read()
 
648
                try:
 
649
                    merge = self.make_merger()
 
650
                    self._do_merge_to(merge)
 
651
                finally:
 
652
                    if self.other_tree is not None:
 
653
                        self.other_tree.unlock()
 
654
            finally:
 
655
                if self.base_tree is not None:
 
656
                    self.base_tree.unlock()
 
657
        finally:
 
658
            self.this_tree.unlock()
658
659
        if len(merge.cooked_conflicts) == 0:
659
660
            if not self.ignore_zero and not trace.is_quiet():
660
661
                trace.note("All changes applied successfully.")
695
696
 
696
697
    def __init__(self, working_tree, this_tree, base_tree, other_tree,
697
698
                 interesting_ids=None, reprocess=False, show_base=False,
698
 
                 pb=None, pp=None, change_reporter=None,
 
699
                 pb=progress.DummyProgress(), pp=None, change_reporter=None,
699
700
                 interesting_files=None, do_merge=True,
700
701
                 cherrypick=False, lca_trees=None, this_branch=None):
701
702
        """Initialize the merger object and perform the merge.
711
712
        :param: reprocess If True, perform conflict-reduction processing.
712
713
        :param show_base: If True, show the base revision in text conflicts.
713
714
            (incompatible with reprocess)
714
 
        :param pb: ignored
 
715
        :param pb: A Progress bar
715
716
        :param pp: A ProgressPhase object
716
717
        :param change_reporter: An object that should report changes made
717
718
        :param interesting_files: The tree-relative paths of files that should
744
745
        # making sure we haven't missed any corner cases.
745
746
        # if lca_trees is None:
746
747
        #     self._lca_trees = [self.base_tree]
 
748
        self.pb = pb
 
749
        self.pp = pp
747
750
        self.change_reporter = change_reporter
748
751
        self.cherrypick = cherrypick
 
752
        if self.pp is None:
 
753
            self.pp = progress.ProgressPhase("Merge phase", 3, self.pb)
749
754
        if do_merge:
750
755
            self.do_merge()
751
 
        if pp is not None:
752
 
            warnings.warn("pp argument to Merge3Merger is deprecated")
753
 
        if pb is not None:
754
 
            warnings.warn("pb argument to Merge3Merger is deprecated")
755
756
 
756
757
    def do_merge(self):
757
 
        operation = OperationWithCleanups(self._do_merge)
758
758
        self.this_tree.lock_tree_write()
759
 
        operation.add_cleanup(self.this_tree.unlock)
760
759
        self.base_tree.lock_read()
761
 
        operation.add_cleanup(self.base_tree.unlock)
762
760
        self.other_tree.lock_read()
763
 
        operation.add_cleanup(self.other_tree.unlock)
764
 
        operation.run()
765
 
 
766
 
    def _do_merge(self, operation):
767
 
        self.tt = transform.TreeTransform(self.this_tree, None)
768
 
        operation.add_cleanup(self.tt.finalize)
769
 
        self._compute_transform()
770
 
        results = self.tt.apply(no_conflicts=True)
771
 
        self.write_modified(results)
772
761
        try:
773
 
            self.this_tree.add_conflicts(self.cooked_conflicts)
774
 
        except errors.UnsupportedOperation:
775
 
            pass
 
762
            self.tt = transform.TreeTransform(self.this_tree, self.pb)
 
763
            try:
 
764
                self.pp.next_phase()
 
765
                self._compute_transform()
 
766
                self.pp.next_phase()
 
767
                results = self.tt.apply(no_conflicts=True)
 
768
                self.write_modified(results)
 
769
                try:
 
770
                    self.this_tree.add_conflicts(self.cooked_conflicts)
 
771
                except errors.UnsupportedOperation:
 
772
                    pass
 
773
            finally:
 
774
                self.tt.finalize()
 
775
        finally:
 
776
            self.other_tree.unlock()
 
777
            self.base_tree.unlock()
 
778
            self.this_tree.unlock()
 
779
            self.pb.clear()
776
780
 
777
781
    def make_preview_transform(self):
778
 
        operation = OperationWithCleanups(self._make_preview_transform)
779
782
        self.base_tree.lock_read()
780
 
        operation.add_cleanup(self.base_tree.unlock)
781
783
        self.other_tree.lock_read()
782
 
        operation.add_cleanup(self.other_tree.unlock)
783
 
        return operation.run_simple()
784
 
 
785
 
    def _make_preview_transform(self):
786
784
        self.tt = transform.TransformPreview(self.this_tree)
787
 
        self._compute_transform()
 
785
        try:
 
786
            self.pp.next_phase()
 
787
            self._compute_transform()
 
788
            self.pp.next_phase()
 
789
        finally:
 
790
            self.other_tree.unlock()
 
791
            self.base_tree.unlock()
 
792
            self.pb.clear()
788
793
        return self.tt
789
794
 
790
795
    def _compute_transform(self):
812
817
        finally:
813
818
            child_pb.finished()
814
819
        self.fix_root()
 
820
        self.pp.next_phase()
815
821
        child_pb = ui.ui_factory.nested_progress_bar()
816
822
        try:
817
823
            fs_conflicts = transform.resolve_conflicts(self.tt, child_pb,
1710
1716
                other_rev_id=None,
1711
1717
                interesting_files=None,
1712
1718
                this_tree=None,
1713
 
                pb=None,
 
1719
                pb=progress.DummyProgress(),
1714
1720
                change_reporter=None):
1715
1721
    """Primary interface for merging.
1716
1722