/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
1
# Copyright (C) 2005, 2006 Canonical Ltd
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
2
#
1110 by Martin Pool
- merge aaron's merge improvements:
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
7
#
1110 by Martin Pool
- merge aaron's merge improvements:
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
12
#
1110 by Martin Pool
- merge aaron's merge improvements:
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
17
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
18
import difflib
1185.1.2 by Martin Pool
- merge various windows and other fixes from Ollie Rutherfurd
19
import os
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
20
import errno
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
21
import warnings
1113 by Martin Pool
- fix is_ancestor import problem in merge
22
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
23
from bzrlib import (
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
24
    errors,
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
25
    osutils,
1551.15.46 by Aaron Bentley
Move plan merge to tree
26
    patiencediff,
2221.4.15 by Aaron Bentley
Use RegistryOption for merge type
27
    registry,
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
28
    revision as _mod_revision,
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
29
    )
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
30
from bzrlib.branch import Branch
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
31
from bzrlib.conflicts import ConflictList, Conflict
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
32
from bzrlib.errors import (BzrCommandError,
1534.4.28 by Robert Collins
first cut at merge from integration.
33
                           BzrError,
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
34
                           NoCommonAncestor,
35
                           NoCommits,
1534.4.28 by Robert Collins
first cut at merge from integration.
36
                           NoSuchRevision,
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
37
                           NoSuchFile,
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
38
                           NotBranchError,
1185.33.27 by Martin Pool
[merge] much integrated work from robert and john
39
                           NotVersionedError,
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
40
                           UnrelatedBranches,
1534.10.12 by Aaron Bentley
Merge produces new conflicts
41
                           UnsupportedOperation,
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
42
                           WorkingTreeNotRevision,
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
43
                           BinaryFile,
1534.4.28 by Robert Collins
first cut at merge from integration.
44
                           )
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
45
from bzrlib.merge3 import Merge3
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
46
from bzrlib.osutils import rename, pathjoin
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
47
from progress import DummyProgress, ProgressPhase
3052.1.3 by John Arbash Meinel
deprecate revision.is_ancestor, update the callers and the tests.
48
from bzrlib.revision import (NULL_REVISION, ensure_null)
1558.15.5 by Aaron Bentley
Fixed binary handling in weave merge
49
from bzrlib.textfile import check_text_lines
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
50
from bzrlib.trace import mutter, warning, note
1534.7.172 by Aaron Bentley
Integrated fs conflicts with merge conflicts.
51
from bzrlib.transform import (TreeTransform, resolve_conflicts, cook_conflicts,
2590.2.8 by Aaron Bentley
Restore conflict handling changes
52
                              conflict_pass, FinalPaths, create_by_entry,
53
                              unique_add, ROOT_PARENT)
1551.15.46 by Aaron Bentley
Move plan merge to tree
54
from bzrlib.versionedfile import PlanWeaveMerge
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
55
from bzrlib import ui
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
56
57
# TODO: Report back as changes are merged in
58
2325.3.1 by John Arbash Meinel
New helper function for merge, which allows us to re-use the existing workingtree, rather than opening it again.
59
1185.35.4 by Aaron Bentley
Implemented remerge
60
def transform_tree(from_tree, to_tree, interesting_ids=None):
61
    merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True,
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
62
                interesting_ids=interesting_ids, this_tree=from_tree)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
63
1457.1.12 by Robert Collins
Update comment to reflect author.
64
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
65
class Merger(object):
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
66
    def __init__(self, this_branch, other_tree=None, base_tree=None,
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
67
                 this_tree=None, pb=DummyProgress(), change_reporter=None,
68
                 recurse='down'):
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
69
        object.__init__(self)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
70
        assert this_tree is not None, "this_tree is required"
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
71
        self.this_branch = this_branch
2598.5.4 by Aaron Bentley
Restore original Branch.last_revision behavior, fix bits that care
72
        self.this_basis = _mod_revision.ensure_null(
73
            this_branch.last_revision())
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
74
        self.this_rev_id = None
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
75
        self.this_tree = this_tree
1185.12.83 by Aaron Bentley
Preliminary weave merge support
76
        self.this_revision_tree = None
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
77
        self.this_basis_tree = None
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
78
        self.other_tree = other_tree
2100.3.29 by Aaron Bentley
Get merge working initially
79
        self.other_branch = None
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
80
        self.base_tree = base_tree
81
        self.ignore_zero = False
82
        self.backup_files = False
83
        self.interesting_ids = None
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
84
        self.interesting_files = None
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
85
        self.show_base = False
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
86
        self.reprocess = False
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
87
        self._pb = pb
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
88
        self.pp = None
2100.3.29 by Aaron Bentley
Get merge working initially
89
        self.recurse = recurse
1551.11.9 by Aaron Bentley
Apply change reporting to merge
90
        self.change_reporter = change_reporter
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
91
        self._cached_trees = {}
92
1551.15.67 by Aaron Bentley
Stop using _merge_helper for merging
93
    @staticmethod
94
    def from_uncommitted(tree, other_tree, pb):
1551.15.74 by Aaron Bentley
Textual updates from review
95
        """Return a Merger for uncommitted changes in other_tree.
96
97
        :param tree: The tree to merge into
98
        :param other_tree: The tree to get uncommitted changes from
99
        :param pb: A progress indicator
100
        """
1551.15.67 by Aaron Bentley
Stop using _merge_helper for merging
101
        merger = Merger(tree.branch, other_tree, other_tree.basis_tree(), tree,
102
                        pb)
103
        merger.base_rev_id = merger.base_tree.get_revision_id()
104
        merger.other_rev_id = None
105
        return merger
106
107
    @classmethod
108
    def from_mergeable(klass, tree, mergeable, pb):
1551.15.74 by Aaron Bentley
Textual updates from review
109
        """Return a Merger for a bundle or merge directive.
110
111
        :param tree: The tree to merge changes into
112
        :param mergeable: A merge directive or bundle
113
        :param pb: A progress indicator
114
        """
1551.15.67 by Aaron Bentley
Stop using _merge_helper for merging
115
        mergeable.install_revisions(tree.branch.repository)
116
        base_revision_id, other_revision_id, verified =\
117
            mergeable.get_merge_request(tree.branch.repository)
1551.15.77 by Aaron Bentley
Merge from bzr.dev
118
        if (base_revision_id != _mod_revision.NULL_REVISION and
119
            tree.branch.repository.get_graph().is_ancestor(
120
            base_revision_id, tree.branch.last_revision())):
1551.15.67 by Aaron Bentley
Stop using _merge_helper for merging
121
            base_revision_id = None
122
        merger = klass.from_revision_ids(pb, tree, other_revision_id,
123
                                         base_revision_id)
124
        return merger, verified
125
126
    @staticmethod
127
    def from_revision_ids(pb, this, other, base=None, other_branch=None,
128
                          base_branch=None):
1551.15.74 by Aaron Bentley
Textual updates from review
129
        """Return a Merger for revision-ids.
130
131
        :param tree: The tree to merge changes into
132
        :param other: The revision-id to use as OTHER
133
        :param base: The revision-id to use as BASE.  If not specified, will
134
            be auto-selected.
135
        :param other_branch: A branch containing the other revision-id.  If
136
            not supplied, this.branch is used.
137
        :param base_branch: A branch containing the base revision-id.  If
138
            not supplied, other_branch or this.branch will be used.
139
        :param pb: A progress indicator
140
        """
1551.15.67 by Aaron Bentley
Stop using _merge_helper for merging
141
        merger = Merger(this.branch, this_tree=this, pb=pb)
142
        if other_branch is None:
143
            other_branch = this.branch
144
        merger.set_other_revision(other, other_branch)
145
        if base is None:
146
            merger.find_base()
147
        else:
148
            if base_branch is None:
149
                base_branch = other_branch
150
            merger.set_base_revision(base, base_branch)
151
        return merger
152
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
153
    def revision_tree(self, revision_id, branch=None):
154
        if revision_id not in self._cached_trees:
155
            if branch is None:
156
                branch = self.this_branch
157
            try:
158
                tree = self.this_tree.revision_tree(revision_id)
159
            except errors.NoSuchRevisionInTree:
160
                tree = branch.repository.revision_tree(revision_id)
161
            self._cached_trees[revision_id] = tree
162
        return self._cached_trees[revision_id]
163
2485.8.58 by Vincent Ladeuil
merge bzr.dev@1617
164
    def _get_tree(self, treespec, possible_transports=None):
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
165
        from bzrlib import workingtree
166
        location, revno = treespec
167
        if revno is None:
168
            tree = workingtree.WorkingTree.open_containing(location)[0]
169
            return tree.branch, tree
2485.8.58 by Vincent Ladeuil
merge bzr.dev@1617
170
        branch = Branch.open_containing(location, possible_transports)[0]
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
171
        if revno == -1:
172
            revision_id = branch.last_revision()
173
        else:
174
            revision_id = branch.get_rev_id(revno)
175
        revision_id = ensure_null(revision_id)
176
        return branch, self.revision_tree(revision_id, branch)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
177
178
    def ensure_revision_trees(self):
179
        if self.this_revision_tree is None:
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
180
            self.this_basis_tree = self.revision_tree(self.this_basis)
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
181
            if self.this_basis == self.this_rev_id:
182
                self.this_revision_tree = self.this_basis_tree
183
1185.12.83 by Aaron Bentley
Preliminary weave merge support
184
        if self.other_rev_id is None:
185
            other_basis_tree = self.revision_tree(self.other_basis)
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
186
            changes = other_basis_tree.changes_from(self.other_tree)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
187
            if changes.has_changed():
188
                raise WorkingTreeNotRevision(self.this_tree)
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
189
            other_rev_id = self.other_basis
1185.12.83 by Aaron Bentley
Preliminary weave merge support
190
            self.other_tree = other_basis_tree
191
192
    def file_revisions(self, file_id):
193
        self.ensure_revision_trees()
194
        def get_id(tree, file_id):
195
            revision_id = tree.inventory[file_id].revision
196
            assert revision_id is not None
197
            return revision_id
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
198
        if self.this_rev_id is None:
199
            if self.this_basis_tree.get_file_sha1(file_id) != \
200
                self.this_tree.get_file_sha1(file_id):
201
                raise WorkingTreeNotRevision(self.this_tree)
202
203
        trees = (self.this_basis_tree, self.other_tree)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
204
        return [get_id(tree, file_id) for tree in trees]
205
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
206
    def check_basis(self, check_clean, require_commits=True):
207
        if self.this_basis is None and require_commits is True:
2249.3.1 by John Arbash Meinel
Mention using 'bzr pull' if there are no commits in current branch
208
            raise BzrCommandError("This branch has no commits."
209
                                  " (perhaps you would prefer 'bzr pull')")
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
210
        if check_clean:
211
            self.compare_basis()
212
            if self.this_basis != self.this_rev_id:
2796.2.1 by Aaron Bentley
Begin work on reconfigure command
213
                raise errors.UncommittedChanges(self.this_tree)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
214
215
    def compare_basis(self):
2590.2.20 by Aaron Bentley
Fix handling of ghost base trees
216
        try:
217
            basis_tree = self.revision_tree(self.this_tree.last_revision())
218
        except errors.RevisionNotPresent:
219
            basis_tree = self.this_tree.basis_tree()
220
        changes = self.this_tree.changes_from(basis_tree)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
221
        if not changes.has_changed():
222
            self.this_rev_id = self.this_basis
223
224
    def set_interesting_files(self, file_list):
2590.2.7 by Aaron Bentley
Misc cleanup
225
        self.interesting_files = file_list
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
226
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
227
    def set_pending(self):
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
228
        if not self.base_is_ancestor or not self.base_is_other_ancestor or self.other_rev_id is None:
1185.12.77 by Aaron Bentley
Prevented all ancestors from being marked as pending merges
229
            return
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
230
        self._add_parent()
231
232
    def _add_parent(self):
233
        new_parents = self.this_tree.get_parent_ids() + [self.other_rev_id]
2590.2.20 by Aaron Bentley
Fix handling of ghost base trees
234
        new_parent_trees = []
235
        for revision_id in new_parents:
236
            try:
237
                tree = self.revision_tree(revision_id)
238
            except errors.RevisionNotPresent:
239
                tree = None
240
            else:
241
                tree.lock_read()
242
            new_parent_trees.append((revision_id, tree))
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
243
        try:
2590.2.20 by Aaron Bentley
Fix handling of ghost base trees
244
            self.this_tree.set_parent_trees(new_parent_trees,
245
                                            allow_leftmost_as_ghost=True)
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
246
        finally:
247
            for _revision_id, tree in new_parent_trees:
2590.2.20 by Aaron Bentley
Fix handling of ghost base trees
248
                if tree is not None:
249
                    tree.unlock()
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
250
2485.8.37 by Vincent Ladeuil
Fix merge multiple connections. Test suite *not* passing (sftp
251
    def set_other(self, other_revision, possible_transports=None):
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
252
        """Set the revision and tree to merge from.
253
254
        This sets the other_tree, other_rev_id, other_basis attributes.
255
256
        :param other_revision: The [path, revision] list to merge from.
257
        """
2485.8.58 by Vincent Ladeuil
merge bzr.dev@1617
258
        self.other_branch, self.other_tree = self._get_tree(other_revision,
259
                                                            possible_transports)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
260
        if other_revision[1] == -1:
2598.5.4 by Aaron Bentley
Restore original Branch.last_revision behavior, fix bits that care
261
            self.other_rev_id = _mod_revision.ensure_null(
262
                self.other_branch.last_revision())
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
263
            if _mod_revision.is_null(self.other_rev_id):
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
264
                raise NoCommits(self.other_branch)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
265
            self.other_basis = self.other_rev_id
266
        elif other_revision[1] is not None:
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
267
            self.other_rev_id = self.other_branch.get_rev_id(other_revision[1])
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
268
            self.other_basis = self.other_rev_id
269
        else:
270
            self.other_rev_id = None
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
271
            self.other_basis = self.other_branch.last_revision()
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
272
            if self.other_basis is None:
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
273
                raise NoCommits(self.other_branch)
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
274
        if self.other_rev_id is not None:
275
            self._cached_trees[self.other_rev_id] = self.other_tree
2590.2.19 by Aaron Bentley
Avoid fetch within a repository
276
        self._maybe_fetch(self.other_branch,self.this_branch, self.other_basis)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
277
2100.3.29 by Aaron Bentley
Get merge working initially
278
    def set_other_revision(self, revision_id, other_branch):
279
        """Set 'other' based on a branch and revision id
280
281
        :param revision_id: The revision to use for a tree
282
        :param other_branch: The branch containing this tree
283
        """
284
        self.other_rev_id = revision_id
285
        self.other_branch = other_branch
2590.2.19 by Aaron Bentley
Avoid fetch within a repository
286
        self._maybe_fetch(other_branch, self.this_branch, self.other_rev_id)
2100.3.29 by Aaron Bentley
Get merge working initially
287
        self.other_tree = self.revision_tree(revision_id)
288
        self.other_basis = revision_id
289
2520.4.110 by Aaron Bentley
Implement cherrypick support for merge directives
290
    def set_base_revision(self, revision_id, branch):
291
        """Set 'base' based on a branch and revision id
292
293
        :param revision_id: The revision to use for a tree
294
        :param branch: The branch containing this tree
295
        """
296
        self.base_rev_id = revision_id
297
        self.base_branch = branch
2520.4.132 by Aaron Bentley
Merge from bzr.dev
298
        self._maybe_fetch(branch, self.this_branch, revision_id)
2520.4.110 by Aaron Bentley
Implement cherrypick support for merge directives
299
        self.base_tree = self.revision_tree(revision_id)
3052.1.3 by John Arbash Meinel
deprecate revision.is_ancestor, update the callers and the tests.
300
        graph = self.this_branch.repository.get_graph()
301
        self.base_is_ancestor = graph.is_ancestor(self.base_rev_id,
302
                                                  self.this_basis)
303
        self.base_is_other_ancestor = graph.is_ancestor(self.base_rev_id,
304
                                                        self.other_basis)
2520.4.132 by Aaron Bentley
Merge from bzr.dev
305
2590.2.19 by Aaron Bentley
Avoid fetch within a repository
306
    def _maybe_fetch(self, source, target, revision_id):
2665.5.2 by Aaron Bentley
Switch commit and merge to Repository.has_same_location
307
        if not source.repository.has_same_location(target.repository):
2590.2.19 by Aaron Bentley
Avoid fetch within a repository
308
            target.fetch(source, revision_id)
2520.4.110 by Aaron Bentley
Implement cherrypick support for merge directives
309
1185.82.25 by Aaron Bentley
Added changeset-merging functionality
310
    def find_base(self):
2590.2.22 by Aaron Bentley
Remove cruft
311
        this_repo = self.this_branch.repository
312
        graph = this_repo.get_graph()
313
        revisions = [ensure_null(self.this_basis),
314
                     ensure_null(self.other_basis)]
315
        if NULL_REVISION in revisions:
316
            self.base_rev_id = NULL_REVISION
317
        else:
318
            self.base_rev_id = graph.find_unique_lca(*revisions)
319
            if self.base_rev_id == NULL_REVISION:
320
                raise UnrelatedBranches()
2590.2.13 by Aaron Bentley
Make find_base implement the base_finding code
321
        self.base_tree = self.revision_tree(self.base_rev_id)
322
        self.base_is_ancestor = True
2590.2.18 by Aaron Bentley
Merge is_ancestor fix
323
        self.base_is_other_ancestor = True
1185.82.25 by Aaron Bentley
Added changeset-merging functionality
324
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
325
    def set_base(self, base_revision):
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
326
        """Set the base revision to use for the merge.
327
328
        :param base_revision: A 2-list containing a path and revision number.
329
        """
1185.12.96 by Aaron Bentley
Merge from mpool
330
        mutter("doing merge() with no base_revision specified")
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
331
        if base_revision == [None, None]:
2590.2.13 by Aaron Bentley
Make find_base implement the base_finding code
332
            self.find_base()
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
333
        else:
2590.2.11 by Aaron Bentley
Aggressively cache trees, use dirstate. re-mplement _add_parent.
334
            base_branch, self.base_tree = self._get_tree(base_revision)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
335
            if base_revision[1] == -1:
336
                self.base_rev_id = base_branch.last_revision()
337
            elif base_revision[1] is None:
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
338
                self.base_rev_id = _mod_revision.NULL_REVISION
493 by Martin Pool
- Merge aaron's merge command
339
            else:
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
340
                self.base_rev_id = _mod_revision.ensure_null(
341
                    base_branch.get_rev_id(base_revision[1]))
2590.2.19 by Aaron Bentley
Avoid fetch within a repository
342
            self._maybe_fetch(base_branch, self.this_branch, self.base_rev_id)
3052.1.3 by John Arbash Meinel
deprecate revision.is_ancestor, update the callers and the tests.
343
            graph = self.this_branch.repository.get_graph()
344
            self.base_is_ancestor = graph.is_ancestor(self.base_rev_id,
345
                                                      self.this_basis)
346
            self.base_is_other_ancestor = graph.is_ancestor(self.base_rev_id,
347
                                                            self.other_basis)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
348
349
    def do_merge(self):
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
350
        kwargs = {'working_tree':self.this_tree, 'this_tree': self.this_tree,
351
                  'other_tree': self.other_tree,
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
352
                  'interesting_ids': self.interesting_ids,
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
353
                  'interesting_files': self.interesting_files,
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
354
                  'pp': self.pp}
1534.7.84 by Aaron Bentley
Added reprocess support, support for varying merge types
355
        if self.merge_type.requires_base:
356
            kwargs['base_tree'] = self.base_tree
1534.7.137 by Aaron Bentley
Avoided generating a new tree for every weave merge
357
        if self.merge_type.supports_reprocess:
358
            kwargs['reprocess'] = self.reprocess
359
        elif self.reprocess:
1551.6.14 by Aaron Bentley
Tweaks from merge review
360
            raise BzrError("Conflict reduction is not supported for merge"
361
                                  " type %s." % self.merge_type)
1534.7.137 by Aaron Bentley
Avoided generating a new tree for every weave merge
362
        if self.merge_type.supports_show_base:
363
            kwargs['show_base'] = self.show_base
364
        elif self.show_base:
1534.8.2 by Aaron Bentley
Implemented weave merge
365
            raise BzrError("Showing base is not supported for this"
366
                                  " merge type. %s" % self.merge_type)
2255.2.50 by John Arbash Meinel
merge only needs a lock_tree_write() on the working tree, not a full lock_write()
367
        self.this_tree.lock_tree_write()
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
368
        if self.base_tree is not None:
369
            self.base_tree.lock_read()
370
        if self.other_tree is not None:
371
            self.other_tree.lock_read()
372
        try:
2255.2.83 by John Arbash Meinel
[merge] bzr.dev 2294
373
            merge = self.merge_type(pb=self._pb,
374
                                    change_reporter=self.change_reporter,
375
                                    **kwargs)
2255.2.226 by Robert Collins
Get merge_nested finally working: change nested tree iterators to take file_ids, and ensure the right branch is connected to in the merge logic. May not be suitable for shared repositories yet.
376
            if self.recurse == 'down':
377
                for path, file_id in self.this_tree.iter_references():
378
                    sub_tree = self.this_tree.get_nested_tree(file_id, path)
379
                    other_revision = self.other_tree.get_reference_revision(
380
                        file_id, path)
381
                    if  other_revision == sub_tree.last_revision():
382
                        continue
383
                    sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
384
                    sub_merge.merge_type = self.merge_type
385
                    relpath = self.this_tree.relpath(path)
386
                    other_branch = self.other_branch.reference_parent(file_id, relpath)
387
                    sub_merge.set_other_revision(other_revision, other_branch)
388
                    base_revision = self.base_tree.get_reference_revision(file_id)
389
                    sub_merge.base_tree = \
390
                        sub_tree.branch.repository.revision_tree(base_revision)
391
                    sub_merge.do_merge()
392
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
393
        finally:
394
            if self.other_tree is not None:
395
                self.other_tree.unlock()
396
            if self.base_tree is not None:
397
                self.base_tree.unlock()
398
            self.this_tree.unlock()
1534.7.151 by Aaron Bentley
Fixed all changes applied successfully
399
        if len(merge.cooked_conflicts) == 0:
1534.7.141 by Aaron Bentley
Added conflict reporting
400
            if not self.ignore_zero:
401
                note("All changes applied successfully.")
402
        else:
403
            note("%d conflicts encountered." % len(merge.cooked_conflicts))
404
1534.7.134 by Aaron Bentley
Hid raw conflicts
405
        return len(merge.cooked_conflicts)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
406
1545.2.4 by Aaron Bentley
PEP8 fixes
407
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
408
class Merge3Merger(object):
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
409
    """Three-way merger that uses the merge3 text merger"""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
410
    requires_base = True
411
    supports_reprocess = True
412
    supports_show_base = True
413
    history_based = False
2590.2.7 by Aaron Bentley
Misc cleanup
414
    winner_idx = {"this": 2, "other": 1, "conflict": 1}
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
415
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
416
    def __init__(self, working_tree, this_tree, base_tree, other_tree, 
1558.2.2 by Aaron Bentley
Make remerge honour interesting-ids
417
                 interesting_ids=None, reprocess=False, show_base=False,
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
418
                 pb=DummyProgress(), pp=None, change_reporter=None,
419
                 interesting_files=None):
2590.2.10 by Aaron Bentley
Updates from review
420
        """Initialize the merger object and perform the merge.
421
422
        :param working_tree: The working tree to apply the merge to
423
        :param this_tree: The local tree in the merge operation
424
        :param base_tree: The common tree in the merge operation
425
        :param other_tree: The other other tree to merge changes from
426
        :param interesting_ids: The file_ids of files that should be
427
            participate in the merge.  May not be combined with
428
            interesting_files.
429
        :param: reprocess If True, perform conflict-reduction processing.
430
        :param show_base: If True, show the base revision in text conflicts.
431
            (incompatible with reprocess)
432
        :param pb: A Progress bar
433
        :param pp: A ProgressPhase object
434
        :param change_reporter: An object that should report changes made
435
        :param interesting_files: The tree-relative paths of files that should
436
            participate in the merge.  If these paths refer to directories,
437
            the contents of those directories will also be included.  May not
438
            be combined with interesting_ids.  If neither interesting_files nor
439
            interesting_ids is specified, all files may participate in the
440
            merge.
441
        """
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
442
        object.__init__(self)
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
443
        if interesting_files is not None:
444
            assert interesting_ids is None
2590.2.4 by Aaron Bentley
Move entry generation to a helper
445
        self.interesting_ids = interesting_ids
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
446
        self.interesting_files = interesting_files
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
447
        self.this_tree = working_tree
2255.7.52 by Robert Collins
Lock trees in Merge3Merger correctly.
448
        self.this_tree.lock_tree_write()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
449
        self.base_tree = base_tree
2255.7.52 by Robert Collins
Lock trees in Merge3Merger correctly.
450
        self.base_tree.lock_read()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
451
        self.other_tree = other_tree
2255.7.52 by Robert Collins
Lock trees in Merge3Merger correctly.
452
        self.other_tree.lock_read()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
453
        self._raw_conflicts = []
454
        self.cooked_conflicts = []
455
        self.reprocess = reprocess
456
        self.show_base = show_base
1534.9.1 by Aaron Bentley
Added progress bars to merge
457
        self.pb = pb
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
458
        self.pp = pp
1551.11.9 by Aaron Bentley
Apply change reporting to merge
459
        self.change_reporter = change_reporter
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
460
        if self.pp is None:
461
            self.pp = ProgressPhase("Merge phase", 3, self.pb)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
462
1534.9.1 by Aaron Bentley
Added progress bars to merge
463
        self.tt = TreeTransform(working_tree, self.pb)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
464
        try:
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
465
            self.pp.next_phase()
2590.2.4 by Aaron Bentley
Move entry generation to a helper
466
            entries = self._entries3()
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
467
            child_pb = ui.ui_factory.nested_progress_bar()
1551.2.31 by Aaron Bentley
Got merge and revert using nested pbs
468
            try:
2590.2.4 by Aaron Bentley
Move entry generation to a helper
469
                for num, (file_id, changed, parents3, names3,
470
                          executable3) in enumerate(entries):
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
471
                    child_pb.update('Preparing file merge', num, len(entries))
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
472
                    self._merge_names(file_id, parents3, names3)
473
                    if changed:
474
                        file_status = self.merge_contents(file_id)
475
                    else:
476
                        file_status = 'unmodified'
477
                    self._merge_executable(file_id,
478
                        executable3, file_status)
1551.2.31 by Aaron Bentley
Got merge and revert using nested pbs
479
            finally:
480
                child_pb.finished()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
481
            self.fix_root()
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
482
            self.pp.next_phase()
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
483
            child_pb = ui.ui_factory.nested_progress_bar()
1551.2.31 by Aaron Bentley
Got merge and revert using nested pbs
484
            try:
2590.2.8 by Aaron Bentley
Restore conflict handling changes
485
                fs_conflicts = resolve_conflicts(self.tt, child_pb,
486
                    lambda t, c: conflict_pass(t, c, self.other_tree))
1551.2.31 by Aaron Bentley
Got merge and revert using nested pbs
487
            finally:
488
                child_pb.finished()
1551.11.9 by Aaron Bentley
Apply change reporting to merge
489
            if change_reporter is not None:
1551.11.12 by Aaron Bentley
Changes from review
490
                from bzrlib import delta
1551.11.9 by Aaron Bentley
Apply change reporting to merge
491
                delta.report_changes(self.tt._iter_changes(), change_reporter)
1534.7.172 by Aaron Bentley
Integrated fs conflicts with merge conflicts.
492
            self.cook_conflicts(fs_conflicts)
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
493
            for conflict in self.cooked_conflicts:
494
                warning(conflict)
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
495
            self.pp.next_phase()
2590.2.17 by Aaron Bentley
Avoid redundant conflict check
496
            results = self.tt.apply(no_conflicts=True)
1558.4.3 by Aaron Bentley
Merge_modified performance/concurrency fix
497
            self.write_modified(results)
1534.10.12 by Aaron Bentley
Merge produces new conflicts
498
            try:
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
499
                working_tree.add_conflicts(self.cooked_conflicts)
1534.10.12 by Aaron Bentley
Merge produces new conflicts
500
            except UnsupportedOperation:
501
                pass
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
502
        finally:
1711.7.7 by John Arbash Meinel
Don't squelch errors in tt.finalize()
503
            self.tt.finalize()
2255.7.52 by Robert Collins
Lock trees in Merge3Merger correctly.
504
            self.other_tree.unlock()
505
            self.base_tree.unlock()
506
            self.this_tree.unlock()
1551.2.31 by Aaron Bentley
Got merge and revert using nested pbs
507
            self.pb.clear()
1534.7.192 by Aaron Bentley
Record hashes produced by merges
508
2590.2.4 by Aaron Bentley
Move entry generation to a helper
509
    def _entries3(self):
2590.2.7 by Aaron Bentley
Misc cleanup
510
        """Gather data about files modified between three trees.
511
512
        Return a list of tuples of file_id, changed, parents3, names3,
513
        executable3.  changed is a boolean indicating whether the file contents
514
        or kind were changed.  parents3 is a tuple of parent ids for base,
515
        other and this.  names3 is a tuple of names for base, other and this.
516
        executable3 is a tuple of execute-bit values for base, other and this.
517
        """
2590.2.4 by Aaron Bentley
Move entry generation to a helper
518
        result = []
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
519
        iterator = self.other_tree._iter_changes(self.base_tree,
520
                include_unchanged=True, specific_files=self.interesting_files,
521
                extra_trees=[self.this_tree])
2590.2.4 by Aaron Bentley
Move entry generation to a helper
522
        for (file_id, paths, changed, versioned, parents, names, kind,
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
523
             executable) in iterator:
2590.2.4 by Aaron Bentley
Move entry generation to a helper
524
            if (self.interesting_ids is not None and
525
                file_id not in self.interesting_ids):
526
                continue
527
            if file_id in self.this_tree.inventory:
528
                entry = self.this_tree.inventory[file_id]
529
                this_name = entry.name
530
                this_parent = entry.parent_id
531
                this_executable = entry.executable
532
            else:
533
                this_name = None
534
                this_parent = None
535
                this_executable = None
536
            parents3 = parents + (this_parent,)
537
            names3 = names + (this_name,)
538
            executable3 = executable + (this_executable,)
539
            result.append((file_id, changed, parents3, names3, executable3))
540
        return result
541
1731.1.33 by Aaron Bentley
Revert no-special-root changes
542
    def fix_root(self):
543
        try:
544
            self.tt.final_kind(self.tt.root)
545
        except NoSuchFile:
546
            self.tt.cancel_deletion(self.tt.root)
547
        if self.tt.final_file_id(self.tt.root) is None:
548
            self.tt.version_file(self.tt.tree_file_id(self.tt.root), 
549
                                 self.tt.root)
550
        if self.other_tree.inventory.root is None:
551
            return
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
552
        other_root_file_id = self.other_tree.get_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
553
        other_root = self.tt.trans_id_file_id(other_root_file_id)
554
        if other_root == self.tt.root:
555
            return
556
        try:
557
            self.tt.final_kind(other_root)
558
        except NoSuchFile:
559
            return
560
        self.reparent_children(self.other_tree.inventory.root, self.tt.root)
561
        self.tt.cancel_creation(other_root)
562
        self.tt.cancel_versioning(other_root)
563
564
    def reparent_children(self, ie, target):
565
        for thing, child in ie.children.iteritems():
566
            trans_id = self.tt.trans_id_file_id(child.file_id)
567
            self.tt.adjust_path(self.tt.final_name(trans_id), target, trans_id)
568
1534.7.192 by Aaron Bentley
Record hashes produced by merges
569
    def write_modified(self, results):
570
        modified_hashes = {}
571
        for path in results.modified_paths:
572
            file_id = self.this_tree.path2id(self.this_tree.relpath(path))
573
            if file_id is None:
574
                continue
575
            hash = self.this_tree.get_file_sha1(file_id)
576
            if hash is None:
577
                continue
578
            modified_hashes[file_id] = hash
579
        self.this_tree.set_merge_modified(modified_hashes)
580
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
581
    @staticmethod
582
    def parent(entry, file_id):
1534.7.157 by Aaron Bentley
Added more docs
583
        """Determine the parent for a file_id (used as a key method)"""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
584
        if entry is None:
585
            return None
586
        return entry.parent_id
587
588
    @staticmethod
589
    def name(entry, file_id):
1534.7.157 by Aaron Bentley
Added more docs
590
        """Determine the name for a file_id (used as a key method)"""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
591
        if entry is None:
592
            return None
593
        return entry.name
594
    
595
    @staticmethod
596
    def contents_sha1(tree, file_id):
1534.7.157 by Aaron Bentley
Added more docs
597
        """Determine the sha1 of the file contents (used as a key method)."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
598
        if file_id not in tree:
599
            return None
600
        return tree.get_file_sha1(file_id)
601
602
    @staticmethod
603
    def executable(tree, file_id):
1534.7.157 by Aaron Bentley
Added more docs
604
        """Determine the executability of a file-id (used as a key method)."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
605
        if file_id not in tree:
606
            return None
607
        if tree.kind(file_id) != "file":
608
            return False
609
        return tree.is_executable(file_id)
610
611
    @staticmethod
612
    def kind(tree, file_id):
1534.7.157 by Aaron Bentley
Added more docs
613
        """Determine the kind of a file-id (used as a key method)."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
614
        if file_id not in tree:
615
            return None
616
        return tree.kind(file_id)
617
618
    @staticmethod
2590.2.8 by Aaron Bentley
Restore conflict handling changes
619
    def _three_way(base, other, this):
620
        #if base == other, either they all agree, or only THIS has changed.
621
        if base == other:
622
            return 'this'
2590.2.10 by Aaron Bentley
Updates from review
623
        elif this not in (base, other):
2590.2.8 by Aaron Bentley
Restore conflict handling changes
624
            return 'conflict'
2590.2.10 by Aaron Bentley
Updates from review
625
        # "Ambiguous clean merge" -- both sides have made the same change.
2590.2.8 by Aaron Bentley
Restore conflict handling changes
626
        elif this == other:
627
            return "this"
2590.2.10 by Aaron Bentley
Updates from review
628
        # this == base: only other has changed.
2590.2.8 by Aaron Bentley
Restore conflict handling changes
629
        else:
630
            return "other"
631
632
    @staticmethod
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
633
    def scalar_three_way(this_tree, base_tree, other_tree, file_id, key):
634
        """Do a three-way test on a scalar.
635
        Return "this", "other" or "conflict", depending whether a value wins.
636
        """
637
        key_base = key(base_tree, file_id)
638
        key_other = key(other_tree, file_id)
639
        #if base == other, either they all agree, or only THIS has changed.
640
        if key_base == key_other:
641
            return "this"
642
        key_this = key(this_tree, file_id)
643
        if key_this not in (key_base, key_other):
644
            return "conflict"
645
        # "Ambiguous clean merge"
646
        elif key_this == key_other:
647
            return "this"
648
        else:
649
            assert key_this == key_base
650
            return "other"
651
652
    def merge_names(self, file_id):
653
        def get_entry(tree):
654
            if file_id in tree.inventory:
655
                return tree.inventory[file_id]
656
            else:
657
                return None
658
        this_entry = get_entry(self.this_tree)
659
        other_entry = get_entry(self.other_tree)
660
        base_entry = get_entry(self.base_tree)
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
661
        entries = (base_entry, other_entry, this_entry)
662
        names = []
663
        parents = []
664
        for entry in entries:
665
            if entry is None:
666
                names.append(None)
667
                parents.append(None)
668
            else:
669
                names.append(entry.name)
670
                parents.append(entry.parent_id)
2590.2.2 by Aaron Bentley
Do most name merging from iter_changes output
671
        return self._merge_names(file_id, parents, names)
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
672
2590.2.2 by Aaron Bentley
Do most name merging from iter_changes output
673
    def _merge_names(self, file_id, parents, names):
2590.2.7 by Aaron Bentley
Misc cleanup
674
        """Perform a merge on file_id names and parents"""
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
675
        base_name, other_name, this_name = names
676
        base_parent, other_parent, this_parent = parents
2590.2.2 by Aaron Bentley
Do most name merging from iter_changes output
677
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
678
        name_winner = self._three_way(*names)
679
680
        parent_id_winner = self._three_way(*parents)
2590.2.2 by Aaron Bentley
Do most name merging from iter_changes output
681
        if this_name is None:
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
682
            if name_winner == "this":
683
                name_winner = "other"
684
            if parent_id_winner == "this":
685
                parent_id_winner = "other"
686
        if name_winner == "this" and parent_id_winner == "this":
687
            return
688
        if name_winner == "conflict":
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
689
            trans_id = self.tt.trans_id_file_id(file_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
690
            self._raw_conflicts.append(('name conflict', trans_id, 
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
691
                                        this_name, other_name))
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
692
        if parent_id_winner == "conflict":
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
693
            trans_id = self.tt.trans_id_file_id(file_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
694
            self._raw_conflicts.append(('parent conflict', trans_id, 
2590.2.1 by Aaron Bentley
Start work on merging names based on iter_changes
695
                                        this_parent, other_parent))
2590.2.2 by Aaron Bentley
Do most name merging from iter_changes output
696
        if other_name is None:
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
697
            # it doesn't matter whether the result was 'other' or 
698
            # 'conflict'-- if there's no 'other', we leave it alone.
699
            return
700
        # if we get here, name_winner and parent_winner are set to safe values.
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
701
        trans_id = self.tt.trans_id_file_id(file_id)
2590.2.7 by Aaron Bentley
Misc cleanup
702
        parent_id = parents[self.winner_idx[parent_id_winner]]
1731.1.33 by Aaron Bentley
Revert no-special-root changes
703
        if parent_id is not None:
704
            parent_trans_id = self.tt.trans_id_file_id(parent_id)
2590.2.7 by Aaron Bentley
Misc cleanup
705
            self.tt.adjust_path(names[self.winner_idx[name_winner]],
1731.1.33 by Aaron Bentley
Revert no-special-root changes
706
                                parent_trans_id, trans_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
707
708
    def merge_contents(self, file_id):
1534.7.157 by Aaron Bentley
Added more docs
709
        """Performa a merge on file_id contents."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
710
        def contents_pair(tree):
711
            if file_id not in tree:
712
                return (None, None)
713
            kind = tree.kind(file_id)
714
            if kind == "file":
715
                contents = tree.get_file_sha1(file_id)
716
            elif kind == "symlink":
717
                contents = tree.get_symlink_target(file_id)
718
            else:
719
                contents = None
720
            return kind, contents
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
721
722
        def contents_conflict():
723
            trans_id = self.tt.trans_id_file_id(file_id)
724
            name = self.tt.final_name(trans_id)
725
            parent_id = self.tt.final_parent(trans_id)
726
            if file_id in self.this_tree.inventory:
727
                self.tt.unversion_file(trans_id)
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
728
                if file_id in self.this_tree:
729
                    self.tt.delete_contents(trans_id)
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
730
            file_group = self._dump_conflicts(name, parent_id, file_id, 
731
                                              set_version=True)
732
            self._raw_conflicts.append(('contents conflict', file_group))
733
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
734
        # See SPOT run.  run, SPOT, run.
735
        # So we're not QUITE repeating ourselves; we do tricky things with
736
        # file kind...
737
        base_pair = contents_pair(self.base_tree)
738
        other_pair = contents_pair(self.other_tree)
739
        if base_pair == other_pair:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
740
            # OTHER introduced no changes
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
741
            return "unmodified"
742
        this_pair = contents_pair(self.this_tree)
743
        if this_pair == other_pair:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
744
            # THIS and OTHER introduced the same changes
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
745
            return "unmodified"
746
        else:
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
747
            trans_id = self.tt.trans_id_file_id(file_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
748
            if this_pair == base_pair:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
749
                # only OTHER introduced changes
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
750
                if file_id in self.this_tree:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
751
                    # Remove any existing contents
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
752
                    self.tt.delete_contents(trans_id)
1534.7.147 by Aaron Bentley
Tweak to check inventory, not tree for file ids
753
                if file_id in self.other_tree:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
754
                    # OTHER changed the file
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
755
                    create_by_entry(self.tt, 
756
                                    self.other_tree.inventory[file_id], 
757
                                    self.other_tree, trans_id)
1534.7.147 by Aaron Bentley
Tweak to check inventory, not tree for file ids
758
                    if file_id not in self.this_tree.inventory:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
759
                        self.tt.version_file(file_id, trans_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
760
                    return "modified"
1534.7.147 by Aaron Bentley
Tweak to check inventory, not tree for file ids
761
                elif file_id in self.this_tree.inventory:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
762
                    # OTHER deleted the file
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
763
                    self.tt.unversion_file(trans_id)
764
                    return "deleted"
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
765
            #BOTH THIS and OTHER introduced changes; scalar conflict
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
766
            elif this_pair[0] == "file" and other_pair[0] == "file":
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
767
                # THIS and OTHER are both files, so text merge.  Either
768
                # BASE is a file, or both converted to files, so at least we
769
                # have agreement that output should be a file.
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
770
                try:
771
                    self.text_merge(file_id, trans_id)
772
                except BinaryFile:
773
                    return contents_conflict()
1534.7.147 by Aaron Bentley
Tweak to check inventory, not tree for file ids
774
                if file_id not in self.this_tree.inventory:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
775
                    self.tt.version_file(file_id, trans_id)
1534.7.152 by Aaron Bentley
Fixed overwrites
776
                try:
777
                    self.tt.tree_kind(trans_id)
778
                    self.tt.delete_contents(trans_id)
779
                except NoSuchFile:
780
                    pass
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
781
                return "modified"
782
            else:
1534.7.145 by Aaron Bentley
More fixups after get_trans_id
783
                # Scalar conflict, can't text merge.  Dump conflicts
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
784
                return contents_conflict()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
785
786
    def get_lines(self, tree, file_id):
1534.7.157 by Aaron Bentley
Added more docs
787
        """Return the lines in a file, or an empty list."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
788
        if file_id in tree:
789
            return tree.get_file(file_id).readlines()
790
        else:
791
            return []
792
793
    def text_merge(self, file_id, trans_id):
794
        """Perform a three-way text merge on a file_id"""
795
        # it's possible that we got here with base as a different type.
796
        # if so, we just want two-way text conflicts.
797
        if file_id in self.base_tree and \
798
            self.base_tree.kind(file_id) == "file":
799
            base_lines = self.get_lines(self.base_tree, file_id)
800
        else:
801
            base_lines = []
802
        other_lines = self.get_lines(self.other_tree, file_id)
803
        this_lines = self.get_lines(self.this_tree, file_id)
804
        m3 = Merge3(base_lines, this_lines, other_lines)
805
        start_marker = "!START OF MERGE CONFLICT!" + "I HOPE THIS IS UNIQUE"
806
        if self.show_base is True:
807
            base_marker = '|' * 7
808
        else:
809
            base_marker = None
810
811
        def iter_merge3(retval):
812
            retval["text_conflicts"] = False
813
            for line in m3.merge_lines(name_a = "TREE", 
814
                                       name_b = "MERGE-SOURCE", 
815
                                       name_base = "BASE-REVISION",
816
                                       start_marker=start_marker, 
817
                                       base_marker=base_marker,
818
                                       reprocess=self.reprocess):
819
                if line.startswith(start_marker):
820
                    retval["text_conflicts"] = True
821
                    yield line.replace(start_marker, '<' * 7)
822
                else:
823
                    yield line
824
        retval = {}
825
        merge3_iterator = iter_merge3(retval)
826
        self.tt.create_file(merge3_iterator, trans_id)
827
        if retval["text_conflicts"] is True:
828
            self._raw_conflicts.append(('text conflict', trans_id))
829
            name = self.tt.final_name(trans_id)
830
            parent_id = self.tt.final_parent(trans_id)
831
            file_group = self._dump_conflicts(name, parent_id, file_id, 
832
                                              this_lines, base_lines,
833
                                              other_lines)
834
            file_group.append(trans_id)
835
836
    def _dump_conflicts(self, name, parent_id, file_id, this_lines=None, 
837
                        base_lines=None, other_lines=None, set_version=False,
838
                        no_base=False):
1534.7.157 by Aaron Bentley
Added more docs
839
        """Emit conflict files.
840
        If this_lines, base_lines, or other_lines are omitted, they will be
841
        determined automatically.  If set_version is true, the .OTHER, .THIS
842
        or .BASE (in that order) will be created as versioned files.
843
        """
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
844
        data = [('OTHER', self.other_tree, other_lines), 
845
                ('THIS', self.this_tree, this_lines)]
846
        if not no_base:
847
            data.append(('BASE', self.base_tree, base_lines))
848
        versioned = False
849
        file_group = []
850
        for suffix, tree, lines in data:
851
            if file_id in tree:
852
                trans_id = self._conflict_file(name, parent_id, tree, file_id,
853
                                               suffix, lines)
854
                file_group.append(trans_id)
855
                if set_version and not versioned:
856
                    self.tt.version_file(file_id, trans_id)
857
                    versioned = True
858
        return file_group
859
           
860
    def _conflict_file(self, name, parent_id, tree, file_id, suffix, 
861
                       lines=None):
1534.7.157 by Aaron Bentley
Added more docs
862
        """Emit a single conflict file."""
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
863
        name = name + '.' + suffix
864
        trans_id = self.tt.create_path(name, parent_id)
865
        entry = tree.inventory[file_id]
866
        create_by_entry(self.tt, entry, tree, trans_id, lines)
867
        return trans_id
868
869
    def merge_executable(self, file_id, file_status):
1534.7.157 by Aaron Bentley
Added more docs
870
        """Perform a merge on the execute bit."""
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
871
        executable = [self.executable(t, file_id) for t in (self.base_tree,
872
                      self.other_tree, self.this_tree)]
873
        self._merge_executable(file_id, executable, file_status)
874
875
    def _merge_executable(self, file_id, executable, file_status):
876
        """Perform a merge on the execute bit."""
877
        base_executable, other_executable, this_executable = executable
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
878
        if file_status == "deleted":
879
            return
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
880
        trans_id = self.tt.trans_id_file_id(file_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
881
        try:
882
            if self.tt.final_kind(trans_id) != "file":
883
                return
884
        except NoSuchFile:
885
            return
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
886
        winner = self._three_way(*executable)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
887
        if winner == "conflict":
888
        # There must be a None in here, if we have a conflict, but we
889
        # need executability since file status was not deleted.
1534.10.35 by Aaron Bentley
Merge handles contents + executable + deletion conflict
890
            if self.executable(self.other_tree, file_id) is None:
1534.7.142 by Aaron Bentley
Fixed executability conflicts
891
                winner = "this"
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
892
            else:
1534.7.142 by Aaron Bentley
Fixed executability conflicts
893
                winner = "other"
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
894
        if winner == "this":
2325.3.4 by John Arbash Meinel
Rather than setting the executable bit for every file, properly create the working inventory to include it.
895
            if file_status == "modified":
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
896
                executability = this_executable
2325.3.4 by John Arbash Meinel
Rather than setting the executable bit for every file, properly create the working inventory to include it.
897
                if executability is not None:
898
                    trans_id = self.tt.trans_id_file_id(file_id)
899
                    self.tt.set_executability(executability, trans_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
900
        else:
901
            assert winner == "other"
902
            if file_id in self.other_tree:
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
903
                executability = other_executable
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
904
            elif file_id in self.this_tree:
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
905
                executability = this_executable
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
906
            elif file_id in self.base_tree:
2590.2.3 by Aaron Bentley
Merge the execute bit based on iter_changes
907
                executability = base_executable
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
908
            if executability is not None:
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
909
                trans_id = self.tt.trans_id_file_id(file_id)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
910
                self.tt.set_executability(executability, trans_id)
911
1534.7.172 by Aaron Bentley
Integrated fs conflicts with merge conflicts.
912
    def cook_conflicts(self, fs_conflicts):
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
913
        """Convert all conflicts into a form that doesn't depend on trans_id"""
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
914
        from conflicts import Conflict
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
915
        name_conflicts = {}
1534.7.172 by Aaron Bentley
Integrated fs conflicts with merge conflicts.
916
        self.cooked_conflicts.extend(cook_conflicts(fs_conflicts, self.tt))
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
917
        fp = FinalPaths(self.tt)
918
        for conflict in self._raw_conflicts:
919
            conflict_type = conflict[0]
920
            if conflict_type in ('name conflict', 'parent conflict'):
921
                trans_id = conflict[1]
922
                conflict_args = conflict[2:]
923
                if trans_id not in name_conflicts:
924
                    name_conflicts[trans_id] = {}
925
                unique_add(name_conflicts[trans_id], conflict_type, 
926
                           conflict_args)
927
            if conflict_type == 'contents conflict':
928
                for trans_id in conflict[1]:
929
                    file_id = self.tt.final_file_id(trans_id)
930
                    if file_id is not None:
931
                        break
932
                path = fp.get_path(trans_id)
933
                for suffix in ('.BASE', '.THIS', '.OTHER'):
934
                    if path.endswith(suffix):
935
                        path = path[:-len(suffix)]
936
                        break
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
937
                c = Conflict.factory(conflict_type, path=path, file_id=file_id)
938
                self.cooked_conflicts.append(c)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
939
            if conflict_type == 'text conflict':
940
                trans_id = conflict[1]
941
                path = fp.get_path(trans_id)
942
                file_id = self.tt.final_file_id(trans_id)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
943
                c = Conflict.factory(conflict_type, path=path, file_id=file_id)
944
                self.cooked_conflicts.append(c)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
945
946
        for trans_id, conflicts in name_conflicts.iteritems():
947
            try:
948
                this_parent, other_parent = conflicts['parent conflict']
949
                assert this_parent != other_parent
950
            except KeyError:
951
                this_parent = other_parent = \
952
                    self.tt.final_file_id(self.tt.final_parent(trans_id))
953
            try:
954
                this_name, other_name = conflicts['name conflict']
955
                assert this_name != other_name
956
            except KeyError:
957
                this_name = other_name = self.tt.final_name(trans_id)
958
            other_path = fp.get_path(trans_id)
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
959
            if this_parent is not None and this_name is not None:
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
960
                this_parent_path = \
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
961
                    fp.get_path(self.tt.trans_id_file_id(this_parent))
1534.7.166 by Aaron Bentley
Swapped os.path.join for pathjoin everywhere
962
                this_path = pathjoin(this_parent_path, this_name)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
963
            else:
964
                this_path = "<deleted>"
965
            file_id = self.tt.final_file_id(trans_id)
1534.10.20 by Aaron Bentley
Got all tests passing
966
            c = Conflict.factory('path conflict', path=this_path,
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
967
                                 conflict_path=other_path, file_id=file_id)
968
            self.cooked_conflicts.append(c)
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
969
        self.cooked_conflicts.sort(key=Conflict.sort_key)
1534.7.141 by Aaron Bentley
Added conflict reporting
970
971
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
972
class WeaveMerger(Merge3Merger):
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
973
    """Three-way tree merger, text weave merger."""
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
974
    supports_reprocess = True
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
975
    supports_show_base = False
976
1534.9.1 by Aaron Bentley
Added progress bars to merge
977
    def __init__(self, working_tree, this_tree, base_tree, other_tree, 
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
978
                 interesting_ids=None, pb=DummyProgress(), pp=None,
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
979
                 reprocess=False, change_reporter=None,
980
                 interesting_files=None):
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
981
        super(WeaveMerger, self).__init__(working_tree, this_tree, 
1558.2.2 by Aaron Bentley
Make remerge honour interesting-ids
982
                                          base_tree, other_tree, 
983
                                          interesting_ids=interesting_ids, 
1551.11.11 by Aaron Bentley
Get tests passing
984
                                          pb=pb, pp=pp, reprocess=reprocess,
985
                                          change_reporter=change_reporter)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
986
987
    def _merged_lines(self, file_id):
988
        """Generate the merged lines.
989
        There is no distinction between lines that are meant to contain <<<<<<<
990
        and conflicts.
991
        """
1551.15.52 by Aaron Bentley
Tweak from review comments
992
        plan = self.this_tree.plan_file_merge(file_id, self.other_tree)
993
        textmerge = PlanWeaveMerge(plan, '<<<<<<< TREE\n',
994
            '>>>>>>> MERGE-SOURCE\n')
995
        return textmerge.merge_lines(self.reprocess)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
996
997
    def text_merge(self, file_id, trans_id):
1534.7.157 by Aaron Bentley
Added more docs
998
        """Perform a (weave) text merge for a given file and file-id.
999
        If conflicts are encountered, .THIS and .OTHER files will be emitted,
1000
        and a conflict will be noted.
1001
        """
1551.6.12 by Aaron Bentley
Indicate conflicts from merge_lines, insead of guessing
1002
        lines, conflicts = self._merged_lines(file_id)
1558.15.10 by Aaron Bentley
Merge bzr.dev
1003
        lines = list(lines)
1558.15.5 by Aaron Bentley
Fixed binary handling in weave merge
1004
        # Note we're checking whether the OUTPUT is binary in this case, 
1005
        # because we don't want to get into weave merge guts.
1006
        check_text_lines(lines)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1007
        self.tt.create_file(lines, trans_id)
1008
        if conflicts:
1009
            self._raw_conflicts.append(('text conflict', trans_id))
1010
            name = self.tt.final_name(trans_id)
1011
            parent_id = self.tt.final_parent(trans_id)
1012
            file_group = self._dump_conflicts(name, parent_id, file_id, 
1013
                                              no_base=True)
1014
            file_group.append(trans_id)
1015
1016
1017
class Diff3Merger(Merge3Merger):
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
1018
    """Three-way merger using external diff3 for text merging"""
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
1019
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1020
    def dump_file(self, temp_dir, name, tree, file_id):
1021
        out_path = pathjoin(temp_dir, name)
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
1022
        out_file = open(out_path, "wb")
1023
        try:
1024
            in_file = tree.get_file(file_id)
1025
            for line in in_file:
1026
                out_file.write(line)
1027
        finally:
1028
            out_file.close()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1029
        return out_path
1030
1031
    def text_merge(self, file_id, trans_id):
1534.7.157 by Aaron Bentley
Added more docs
1032
        """Perform a diff3 merge using a specified file-id and trans-id.
1033
        If conflicts are encountered, .BASE, .THIS. and .OTHER conflict files
1034
        will be dumped, and a will be conflict noted.
1035
        """
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1036
        import bzrlib.patch
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
1037
        temp_dir = osutils.mkdtemp(prefix="bzr-")
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1038
        try:
1534.7.166 by Aaron Bentley
Swapped os.path.join for pathjoin everywhere
1039
            new_file = pathjoin(temp_dir, "new")
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1040
            this = self.dump_file(temp_dir, "this", self.this_tree, file_id)
1041
            base = self.dump_file(temp_dir, "base", self.base_tree, file_id)
1042
            other = self.dump_file(temp_dir, "other", self.other_tree, file_id)
1043
            status = bzrlib.patch.diff3(new_file, this, base, other)
1044
            if status not in (0, 1):
1045
                raise BzrError("Unhandled diff3 exit code")
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
1046
            f = open(new_file, 'rb')
1047
            try:
1048
                self.tt.create_file(f, trans_id)
1049
            finally:
1050
                f.close()
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1051
            if status == 1:
1052
                name = self.tt.final_name(trans_id)
1053
                parent_id = self.tt.final_parent(trans_id)
1054
                self._dump_conflicts(name, parent_id, file_id)
1551.8.39 by Aaron Bentley
Fix diff3 conflict-reporting bug
1055
                self._raw_conflicts.append(('text conflict', trans_id))
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1056
        finally:
1996.3.18 by John Arbash Meinel
Now that mkdtemp and rmtree are lazy, they should not be directly improted.
1057
            osutils.rmtree(temp_dir)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1058
1059
1060
def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1061
                backup_files=False,
1062
                merge_type=Merge3Merger,
1063
                interesting_ids=None,
1064
                show_base=False,
1065
                reprocess=False,
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1066
                other_rev_id=None,
1067
                interesting_files=None,
1534.9.9 by Aaron Bentley
Added progress bar to pull
1068
                this_tree=None,
1551.11.10 by Aaron Bentley
Add change reporting to pull
1069
                pb=DummyProgress(),
1070
                change_reporter=None):
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1071
    """Primary interface for merging. 
1072
1073
        typical use is probably 
1074
        'merge_inner(branch, branch.get_revision_tree(other_revision),
1075
                     branch.get_revision_tree(base_revision))'
1076
        """
1077
    if this_tree is None:
2367.2.1 by Robert Collins
Remove bzrlib 0.8 compatability where it was making the code unclear or messy. (Robert Collins)
1078
        raise BzrError("bzrlib.merge.merge_inner requires a this_tree "
1079
            "parameter as of bzrlib version 0.8.")
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1080
    merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree,
1551.11.10 by Aaron Bentley
Add change reporting to pull
1081
                    pb=pb, change_reporter=change_reporter)
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1082
    merger.backup_files = backup_files
1083
    merger.merge_type = merge_type
1084
    merger.interesting_ids = interesting_ids
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
1085
    merger.ignore_zero = ignore_zero
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1086
    if interesting_files:
1087
        assert not interesting_ids, ('Only supply interesting_ids'
1088
                                     ' or interesting_files')
2590.2.5 by Aaron Bentley
Allow selected files to be specified instead of selected ids
1089
        merger.interesting_files = interesting_files
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
1090
    merger.show_base = show_base
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
1091
    merger.reprocess = reprocess
1092
    merger.other_rev_id = other_rev_id
1093
    merger.other_basis = other_rev_id
1094
    return merger.do_merge()
1095
2221.4.15 by Aaron Bentley
Use RegistryOption for merge type
1096
def get_merge_type_registry():
2221.4.17 by Aaron Bentley
PEP8-ness
1097
    """Merge type registry is in bzrlib.option to avoid circular imports.
2221.4.15 by Aaron Bentley
Use RegistryOption for merge type
1098
1099
    This method provides a sanctioned way to retrieve it.
1100
    """
1101
    from bzrlib import option
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
1102
    return option._merge_type_registry
1551.15.46 by Aaron Bentley
Move plan merge to tree
1103
1104
1105
def _plan_annotate_merge(annotated_a, annotated_b, ancestors_a, ancestors_b):
1106
    def status_a(revision, text):
1107
        if revision in ancestors_b:
1108
            return 'killed-b', text
1109
        else:
1110
            return 'new-a', text
1111
1112
    def status_b(revision, text):
1113
        if revision in ancestors_a:
1114
            return 'killed-a', text
1115
        else:
1116
            return 'new-b', text
1117
1118
    plain_a = [t for (a, t) in annotated_a]
1119
    plain_b = [t for (a, t) in annotated_b]
1120
    matcher = patiencediff.PatienceSequenceMatcher(None, plain_a, plain_b)
1121
    blocks = matcher.get_matching_blocks()
1122
    a_cur = 0
1123
    b_cur = 0
1124
    for ai, bi, l in blocks:
1125
        # process all mismatched sections
1126
        # (last mismatched section is handled because blocks always
1127
        # includes a 0-length last block)
1128
        for revision, text in annotated_a[a_cur:ai]:
1129
            yield status_a(revision, text)
1130
        for revision, text in annotated_b[b_cur:bi]:
1131
            yield status_b(revision, text)
1132
1133
        # and now the matched section
1134
        a_cur = ai + l
1135
        b_cur = bi + l
1136
        for text_a, text_b in zip(plain_a[ai:a_cur], plain_b[bi:b_cur]):
1137
            assert text_a == text_b
1138
            yield "unchanged", text_a
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1139
1140
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
1141
class _PlanMerge(object):
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1142
    """Plan an annotate merge using on-the-fly annotation"""
1143
1144
    def __init__(self, a_rev, b_rev, vf):
1145
        """Contructor.
1146
1147
        :param a_rev: Revision-id of one revision to merge
1148
        :param b_rev: Revision-id of the other revision to merge
1149
        :param vf: A versionedfile containing both revisions
1150
        """
1151
        self.a_rev = a_rev
1152
        self.b_rev = b_rev
1153
        self.lines_a = vf.get_lines(a_rev)
1154
        self.lines_b = vf.get_lines(b_rev)
1155
        self.vf = vf
3062.1.14 by Aaron Bentley
Use topo_sorted=False with get_ancestry
1156
        a_ancestry = set(vf.get_ancestry(a_rev, topo_sorted=False))
1157
        b_ancestry = set(vf.get_ancestry(b_rev, topo_sorted=False))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1158
        self.uncommon = a_ancestry.symmetric_difference(b_ancestry)
3062.1.12 by Aaron Bentley
Implement simple text cache
1159
        self._last_lines = None
1160
        self._last_lines_revision_id = None
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1161
1162
    def plan_merge(self):
1163
        """Generate a 'plan' for merging the two revisions.
1164
1165
        This involves comparing their texts and determining the cause of
1166
        differences.  If text A has a line and text B does not, then either the
1167
        line was added to text A, or it was deleted from B.  Once the causes
1168
        are combined, they are written out in the format described in
1169
        VersionedFile.plan_merge
1170
        """
1171
        blocks = self._get_matching_blocks(self.a_rev, self.b_rev)
1172
        new_a = self._find_new(self.a_rev)
1173
        new_b = self._find_new(self.b_rev)
1174
        last_i = 0
1175
        last_j = 0
1176
        a_lines = self.vf.get_lines(self.a_rev)
1177
        b_lines = self.vf.get_lines(self.b_rev)
1178
        for i, j, n in blocks:
1179
            # determine why lines aren't common
1180
            for a_index in range(last_i, i):
1181
                if a_index in new_a:
1182
                    cause = 'new-a'
1183
                else:
1184
                    cause = 'killed-b'
1185
                yield cause, a_lines[a_index]
1186
            for b_index in range(last_j, j):
1187
                if b_index in new_b:
1188
                    cause = 'new-b'
1189
                else:
1190
                    cause = 'killed-a'
1191
                yield cause, b_lines[b_index]
1192
            # handle common lines
1193
            for a_index in range(i, i+n):
1194
                yield 'unchanged', a_lines[a_index]
1195
            last_i = i+n
1196
            last_j = j+n
1197
1198
    def _get_matching_blocks(self, left_revision, right_revision):
1199
        """Return a description of which sections of two revisions match.
1200
1201
        See SequenceMatcher.get_matching_blocks
1202
        """
3062.1.12 by Aaron Bentley
Implement simple text cache
1203
        if self._last_lines_revision_id == left_revision:
1204
            left_lines = self._last_lines
1205
        else:
1206
            left_lines = self.vf.get_lines(left_revision)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1207
        right_lines = self.vf.get_lines(right_revision)
3062.1.12 by Aaron Bentley
Implement simple text cache
1208
        self._last_lines = right_lines
1209
        self._last_lines_revision_id = right_revision
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
1210
        matcher = patiencediff.PatienceSequenceMatcher(None, left_lines,
1211
                                                       right_lines)
1212
        return matcher.get_matching_blocks()
1213
1214
    def _unique_lines(self, matching_blocks):
1215
        """Analyse matching_blocks to determine which lines are unique
1216
1217
        :return: a tuple of (unique_left, unique_right), where the values are
1218
            sets of line numbers of unique lines.
1219
        """
1220
        last_i = 0
1221
        last_j = 0
1222
        unique_left = []
1223
        unique_right = []
1224
        for i, j, n in matching_blocks:
1225
            unique_left.extend(range(last_i, i))
1226
            unique_right.extend(range(last_j, j))
1227
            last_i = i + n
1228
            last_j = j + n
1229
        return unique_left, unique_right
1230
1231
    def _find_new(self, version_id):
1232
        """Determine which lines are new in the ancestry of this version.
1233
1234
        If a lines is present in this version, and not present in any
1235
        common ancestor, it is considered new.
1236
        """
1237
        if version_id not in self.uncommon:
1238
            return set()
1239
        parents = self.vf.get_parents(version_id)
1240
        if len(parents) == 0:
1241
            return set(range(len(self.vf.get_lines(version_id))))
1242
        new = None
1243
        for parent in parents:
1244
            blocks = self._get_matching_blocks(version_id, parent)
1245
            result, unused = self._unique_lines(blocks)
1246
            parent_new = self._find_new(parent)
1247
            for i, j, n in blocks:
1248
                for ii, jj in [(i+r, j+r) for r in range(n)]:
1249
                    if jj in parent_new:
1250
                        result.append(ii)
1251
            if new is None:
1252
                new = set(result)
1253
            else:
1254
                new.intersection_update(result)
1255
        return new
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
1256
1257
    @staticmethod
1258
    def _subtract_plans(old_plan, new_plan):
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
1259
        # Can't use patience diff-- C version doesn't work with tuples
1260
        matcher = difflib.SequenceMatcher(None, old_plan, new_plan)
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
1261
        last_j = 0
1262
        for i, j, n in matcher.get_matching_blocks():
1263
            for jj in range(last_j, j):
1264
                yield new_plan[jj]
1265
            for jj in range(j, j+n):
1266
                plan_line = new_plan[jj]
1267
                if plan_line[0] == 'new-b':
1268
                    pass
1269
                elif plan_line[0] == 'killed-b':
1270
                    yield 'unchanged', plan_line[1]
1271
                else:
1272
                    yield plan_line
1273
            last_j = j + n