/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.436.2 by Jelmer Vernooij
Add stubs for testsuite, rebase-continue and rebase-abort commands.
1
# Copyright (C) 2006-2007 by Jelmer Vernooij
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
2
#
0.436.2 by Jelmer Vernooij
Add stubs for testsuite, rebase-continue and rebase-abort commands.
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
0.436.131 by Jelmer Vernooij
Change license back to GPLv2+
5
# the Free Software Foundation; either version 2 of the License, or
0.436.2 by Jelmer Vernooij
Add stubs for testsuite, rebase-continue and rebase-abort commands.
6
# (at your option) any later version.
7
#
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.
12
#
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
0.436.178 by Jelmer Vernooij
Finish rename to 'bzr-rewrite'.
16
0.436.16 by Jelmer Vernooij
Some more work on maptree.
17
"""Rebase."""
0.436.3 by Jelmer Vernooij
Fill in commands.
18
0.436.255 by Jelmer Vernooij
Enable absolute imports everywhere.
19
from __future__ import absolute_import
20
0.436.157 by Jelmer Vernooij
use absolute imports everywhere.
21
import os
22
7406.3.2 by Jelmer Vernooij
Update for breezy.
23
from ... import (
0.436.242 by Jelmer Vernooij
Fix compatibility with 2.5 API.
24
    config as _mod_config,
0.436.157 by Jelmer Vernooij
use absolute imports everywhere.
25
    osutils,
26
    )
7406.3.2 by Jelmer Vernooij
Update for breezy.
27
from ...errors import (
0.436.157 by Jelmer Vernooij
use absolute imports everywhere.
28
    BzrError,
29
    NoSuchFile,
30
    UnknownFormatError,
31
    NoCommonAncestor,
32
    UnrelatedBranches,
33
    )
7406.3.2 by Jelmer Vernooij
Update for breezy.
34
from ...bzr.generate_ids import gen_revision_id
35
from ...graph import FrozenHeadsCache
36
from ...merge import Merger
37
from ...revision import NULL_REVISION
38
from ...trace import mutter
39
from ...tsort import topo_sort
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
40
from ...tree import TreeChange
7406.3.2 by Jelmer Vernooij
Update for breezy.
41
from ... import ui
0.436.4 by Jelmer Vernooij
Add some tests.
42
7406.3.2 by Jelmer Vernooij
Update for breezy.
43
from .maptree import (
0.436.157 by Jelmer Vernooij
use absolute imports everywhere.
44
    MapTree,
45
    map_file_ids,
46
    )
0.436.17 by Jelmer Vernooij
Move maptree code to separate files.
47
0.436.3 by Jelmer Vernooij
Fill in commands.
48
REBASE_PLAN_FILENAME = 'rebase-plan'
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
49
REBASE_CURRENT_REVID_FILENAME = 'rebase-current'
0.436.4 by Jelmer Vernooij
Add some tests.
50
REBASE_PLAN_VERSION = 1
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
51
REVPROP_REBASE_OF = 'rebase-of'
0.436.3 by Jelmer Vernooij
Fill in commands.
52
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
53
class RebaseState(object):
54
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
55
    def has_plan(self):
56
        """Check whether there is a rebase plan present.
57
58
        :return: boolean
59
        """
60
        raise NotImplementedError(self.has_plan)
61
62
    def read_plan(self):
63
        """Read a rebase plan file.
64
65
        :return: Tuple with last revision info and replace map.
66
        """
67
        raise NotImplementedError(self.read_plan)
68
69
    def write_plan(self, replace_map):
70
        """Write a rebase plan file.
71
72
        :param replace_map: Replace map (old revid -> (new revid, new parents))
73
        """
74
        raise NotImplementedError(self.write_plan)
75
76
    def remove_plan(self):
77
        """Remove a rebase plan file.
78
        """
79
        raise NotImplementedError(self.remove_plan)
80
81
    def write_active_revid(self, revid):
82
        """Write the id of the revision that is currently being rebased.
83
84
        :param revid: Revision id to write
85
        """
86
        raise NotImplementedError(self.write_active_revid)
87
88
    def read_active_revid(self):
89
        """Read the id of the revision that is currently being rebased.
90
91
        :return: Id of the revision that is being rebased.
92
        """
93
        raise NotImplementedError(self.read_active_revid)
94
95
96
class RebaseState1(RebaseState):
97
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
98
    def __init__(self, wt):
99
        self.wt = wt
100
        self.transport = wt._transport
101
102
    def has_plan(self):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
103
        """See `RebaseState`."""
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
104
        try:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
105
            return self.transport.get_bytes(REBASE_PLAN_FILENAME) != b''
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
106
        except NoSuchFile:
107
            return False
108
109
    def read_plan(self):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
110
        """See `RebaseState`."""
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
111
        text = self.transport.get_bytes(REBASE_PLAN_FILENAME)
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
112
        if text == b'':
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
113
            raise NoSuchFile(REBASE_PLAN_FILENAME)
114
        return unmarshall_rebase_plan(text)
115
116
    def write_plan(self, replace_map):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
117
        """See `RebaseState`."""
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
118
        self.wt.update_feature_flags({b"rebase-v1": b"write-required"})
7406.3.5 by Jelmer Vernooij
Fix formatting.
119
        content = marshall_rebase_plan(
120
            self.wt.branch.last_revision_info(), replace_map)
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
121
        assert isinstance(content, bytes)
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
122
        self.transport.put_bytes(REBASE_PLAN_FILENAME, content)
123
124
    def remove_plan(self):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
125
        """See `RebaseState`."""
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
126
        self.wt.update_feature_flags({b"rebase-v1": None})
127
        self.transport.put_bytes(REBASE_PLAN_FILENAME, b'')
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
128
129
    def write_active_revid(self, revid):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
130
        """See `RebaseState`."""
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
131
        if revid is None:
132
            revid = NULL_REVISION
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
133
        assert isinstance(revid, bytes)
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
134
        self.transport.put_bytes(REBASE_CURRENT_REVID_FILENAME, revid)
135
136
    def read_active_revid(self):
0.436.192 by Jelmer Vernooij
Avoid reopening state when possible, allow subclasses.
137
        """See `RebaseState`."""
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
138
        try:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
139
            text = self.transport.get_bytes(REBASE_CURRENT_REVID_FILENAME).rstrip(b"\n")
0.436.191 by Jelmer Vernooij
Move rebase state to a separate object.
140
            if text == NULL_REVISION:
141
                return None
142
            return text
143
        except NoSuchFile:
144
            return None
0.436.3 by Jelmer Vernooij
Fill in commands.
145
146
0.436.4 by Jelmer Vernooij
Add some tests.
147
def marshall_rebase_plan(last_rev_info, replace_map):
0.436.3 by Jelmer Vernooij
Fill in commands.
148
    """Marshall a rebase plan.
149
150
    :param last_rev_info: Last revision info tuple.
0.436.4 by Jelmer Vernooij
Add some tests.
151
    :param replace_map: Replace map (old revid -> (new revid, new parents))
0.436.3 by Jelmer Vernooij
Fill in commands.
152
    :return: string
153
    """
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
154
    ret = b"# Bazaar rebase plan %d\n" % REBASE_PLAN_VERSION
155
    ret += b"%d %s\n" % last_rev_info
0.436.4 by Jelmer Vernooij
Add some tests.
156
    for oldrev in replace_map:
157
        (newrev, newparents) = replace_map[oldrev]
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
158
        ret += b"%s %s" % (oldrev, newrev) + \
159
            b"".join([b" %s" % p for p in newparents]) + b"\n"
0.436.4 by Jelmer Vernooij
Add some tests.
160
    return ret
161
162
163
def unmarshall_rebase_plan(text):
0.436.3 by Jelmer Vernooij
Fill in commands.
164
    """Unmarshall a rebase plan.
165
166
    :param text: Text to parse
0.436.4 by Jelmer Vernooij
Add some tests.
167
    :return: Tuple with last revision info, replace map.
0.436.3 by Jelmer Vernooij
Fill in commands.
168
    """
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
169
    lines = text.split(b'\n')
0.436.4 by Jelmer Vernooij
Add some tests.
170
    # Make sure header is there
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
171
    if lines[0] != b"# Bazaar rebase plan %d" % REBASE_PLAN_VERSION:
0.436.4 by Jelmer Vernooij
Add some tests.
172
        raise UnknownFormatError(lines[0])
173
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
174
    pts = lines[1].split(b" ", 1)
0.436.4 by Jelmer Vernooij
Add some tests.
175
    last_revision_info = (int(pts[0]), pts[1])
176
    replace_map = {}
177
    for l in lines[2:]:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
178
        if l == b"":
0.436.4 by Jelmer Vernooij
Add some tests.
179
            # Skip empty lines
180
            continue
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
181
        pts = l.split(b" ")
0.436.95 by Jelmer Vernooij
Use tuples more consistently.
182
        replace_map[pts[0]] = (pts[1], tuple(pts[2:]))
0.436.4 by Jelmer Vernooij
Add some tests.
183
    return (last_revision_info, replace_map)
184
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
185
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
186
def regenerate_default_revid(repository, revid):
0.436.52 by Jelmer Vernooij
Add docstrings, update NEWS.
187
    """Generate a revision id for the rebase of an existing revision.
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
188
0.436.52 by Jelmer Vernooij
Add docstrings, update NEWS.
189
    :param repository: Repository in which the revision is present.
190
    :param revid: Revision id of the revision that is being rebased.
191
    :return: new revision id."""
0.436.180 by Jelmer Vernooij
remove unused import
192
    if revid == NULL_REVISION:
193
        return NULL_REVISION
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
194
    rev = repository.get_revision(revid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
195
    return gen_revision_id(rev.committer, rev.timestamp)
196
197
0.441.4 by Robert Collins
* Fixed O(history) access during plan creation (Robert Collins, lp:#249823).
198
def generate_simple_plan(todo_set, start_revid, stop_revid, onto_revid, graph,
7406.3.5 by Jelmer Vernooij
Fix formatting.
199
                         generate_revid, skip_full_merged=False):
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
200
    """Create a simple rebase plan that replays history based
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
201
    on one revision being replayed on top of another.
0.436.3 by Jelmer Vernooij
Fill in commands.
202
0.443.2 by Max Bowsher
generate_simple_plan: Do not rebase only a leftmost path. Rebase all revisions topologically between the endpoints.
203
    :param todo_set: A set of revisions to rebase. Only the revisions
204
        topologically between stop_revid and start_revid (inclusive) are
205
        rebased; other revisions are ignored (and references to them are
206
        preserved).
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
207
    :param start_revid: Id of revision at which to start replaying
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
208
    :param stop_revid: Id of revision until which to stop replaying
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
209
    :param onto_revid: Id of revision on top of which to replay
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
210
    :param graph: Graph object
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
211
    :param generate_revid: Function for generating new revision ids
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
212
    :param skip_full_merged: Skip revisions that merge already merged
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
213
                             revisions.
0.436.3 by Jelmer Vernooij
Fill in commands.
214
0.436.4 by Jelmer Vernooij
Add some tests.
215
    :return: replace map
0.436.3 by Jelmer Vernooij
Fill in commands.
216
    """
0.441.4 by Robert Collins
* Fixed O(history) access during plan creation (Robert Collins, lp:#249823).
217
    assert start_revid is None or start_revid in todo_set, \
218
        "invalid start revid(%r), todo_set(%r)" % (start_revid, todo_set)
219
    assert stop_revid is None or stop_revid in todo_set, "invalid stop_revid"
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
220
    replace_map = {}
0.441.4 by Robert Collins
* Fixed O(history) access during plan creation (Robert Collins, lp:#249823).
221
    parent_map = graph.get_parent_map(todo_set)
222
    order = topo_sort(parent_map)
223
    if stop_revid is None:
224
        stop_revid = order[-1]
225
    if start_revid is None:
226
        # We need a common base.
227
        lca = graph.find_lca(stop_revid, onto_revid)
228
        if lca == set([NULL_REVISION]):
229
            raise UnrelatedBranches()
0.443.2 by Max Bowsher
generate_simple_plan: Do not rebase only a leftmost path. Rebase all revisions topologically between the endpoints.
230
        start_revid = order[0]
7406.3.5 by Jelmer Vernooij
Fix formatting.
231
    todo = order[order.index(start_revid):order.index(stop_revid) + 1]
0.441.4 by Robert Collins
* Fixed O(history) access during plan creation (Robert Collins, lp:#249823).
232
    heads_cache = FrozenHeadsCache(graph)
233
    # XXX: The output replacemap'd parents should get looked up in some manner
234
    # by the heads cache? RBC 20080719
235
    for oldrevid in todo:
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
236
        oldparents = parent_map[oldrevid]
237
        assert isinstance(oldparents, tuple), "not tuple: %r" % oldparents
0.443.3 by Max Bowsher
Overhaul the parent selection logic.
238
        parents = []
239
        # Left parent:
0.443.4 by Max Bowsher
Bugfix to parent computation.
240
        if heads_cache.heads((oldparents[0], onto_revid)) == set((onto_revid,)):
0.443.3 by Max Bowsher
Overhaul the parent selection logic.
241
            parents.append(onto_revid)
242
        elif oldparents[0] in replace_map:
243
            parents.append(replace_map[oldparents[0]][0])
244
        else:
245
            parents.append(onto_revid)
246
            parents.append(oldparents[0])
247
        # Other parents:
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
248
        if len(oldparents) > 1:
0.441.4 by Robert Collins
* Fixed O(history) access during plan creation (Robert Collins, lp:#249823).
249
            additional_parents = heads_cache.heads(oldparents[1:])
0.443.3 by Max Bowsher
Overhaul the parent selection logic.
250
            for oldparent in oldparents[1:]:
251
                if oldparent in additional_parents:
0.443.4 by Max Bowsher
Bugfix to parent computation.
252
                    if heads_cache.heads((oldparent, onto_revid)) == set((onto_revid,)):
0.443.3 by Max Bowsher
Overhaul the parent selection logic.
253
                        pass
254
                    elif oldparent in replace_map:
255
                        newparent = replace_map[oldparent][0]
256
                        if parents[0] == onto_revid:
257
                            parents[0] = newparent
258
                        else:
259
                            parents.append(newparent)
260
                    else:
261
                        parents.append(oldparent)
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
262
            if len(parents) == 1 and skip_full_merged:
263
                continue
0.443.3 by Max Bowsher
Overhaul the parent selection logic.
264
        parents = tuple(parents)
0.436.173 by Jelmer Vernooij
Add rebase-foreign command.
265
        newrevid = generate_revid(oldrevid, parents)
0.436.91 by Jelmer Vernooij
Fix blackbox tests, add comments to assertions.
266
        assert newrevid != oldrevid, "old and newrevid equal (%r)" % newrevid
267
        assert isinstance(parents, tuple), "parents not tuple: %r" % parents
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
268
        replace_map[oldrevid] = (newrevid, parents)
269
    return replace_map
270
271
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
272
def generate_transpose_plan(ancestry, renames, graph, generate_revid):
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
273
    """Create a rebase plan that replaces a bunch of revisions
274
    in a revision graph.
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
275
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
276
    :param ancestry: Ancestry to consider
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
277
    :param renames: Renames of revision
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
278
    :param graph: Graph object
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
279
    :param generate_revid: Function for creating new revision ids
280
    """
281
    replace_map = {}
282
    todo = []
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
283
    children = {}
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
284
    parent_map = {}
285
    for r, ps in ancestry:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
286
        if r not in children:
0.436.118 by Jelmer Vernooij
Cope with ghosts in svn-upgrade.
287
            children[r] = []
288
        if ps is None: # Ghost
289
            continue
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
290
        parent_map[r] = ps
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
291
        if r not in children:
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
292
            children[r] = []
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
293
        for p in ps:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
294
            if p not in children:
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
295
                children[p] = []
296
            children[p].append(r)
297
7406.3.5 by Jelmer Vernooij
Fix formatting.
298
    parent_map.update(graph.get_parent_map(filter(lambda x: x not in parent_map, renames.values())))
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
299
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
300
    # todo contains a list of revisions that need to
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
301
    # be rewritten
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
302
    for r, v in renames.items():
303
        replace_map[r] = (v, parent_map[v])
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
304
        todo.append(r)
305
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
306
    total = len(todo)
307
    processed = set()
308
    i = 0
309
    pb = ui.ui_factory.nested_progress_bar()
310
    try:
311
        while len(todo) > 0:
312
            r = todo.pop()
0.436.123 by Jelmer Vernooij
Cope with revision ids not changing.
313
            processed.add(r)
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
314
            i += 1
315
            pb.update('determining dependencies', i, total)
316
            # Add entry for them in replace_map
317
            for c in children[r]:
318
                if c in renames:
319
                    continue
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
320
                if c in replace_map:
0.436.89 by Jelmer Vernooij
Use tuples for parents.
321
                    parents = replace_map[c][1]
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
322
                else:
0.436.89 by Jelmer Vernooij
Use tuples for parents.
323
                    parents = parent_map[c]
324
                assert isinstance(parents, tuple), \
7406.3.5 by Jelmer Vernooij
Fix formatting.
325
                    "Expected tuple of parents, got: %r" % parents
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
326
                # replace r in parents with replace_map[r][0]
327
                if not replace_map[r][0] in parents:
0.436.90 by Jelmer Vernooij
Deal with parents being a tuple.
328
                    parents = list(parents)
329
                    parents[parents.index(r)] = replace_map[r][0]
330
                    parents = tuple(parents)
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
331
                replace_map[c] = (generate_revid(c, tuple(parents)),
0.436.173 by Jelmer Vernooij
Add rebase-foreign command.
332
                                  tuple(parents))
0.436.123 by Jelmer Vernooij
Cope with revision ids not changing.
333
                if replace_map[c][0] == c:
0.436.124 by Jelmer Vernooij
Remove erroneus [0].
334
                    del replace_map[c]
0.436.123 by Jelmer Vernooij
Cope with revision ids not changing.
335
                elif c not in processed:
336
                    todo.append(c)
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
337
    finally:
338
        pb.finished()
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
339
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
340
    # Remove items from the map that already exist
341
    for revid in renames:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
342
        if revid in replace_map:
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
343
            del replace_map[revid]
344
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
345
    return replace_map
346
347
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
348
def rebase_todo(repository, replace_map):
349
    """Figure out what revisions still need to be rebased.
350
351
    :param repository: Repository that contains the revisions
352
    :param replace_map: Replace map
353
    """
0.436.91 by Jelmer Vernooij
Fix blackbox tests, add comments to assertions.
354
    for revid, parent_ids in replace_map.items():
355
        assert isinstance(parent_ids, tuple), "replace map parents not tuple"
356
        if not repository.has_revision(parent_ids[0]):
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
357
            yield revid
358
359
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
360
def rebase(repository, replace_map, revision_rewriter):
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
361
    """Rebase a working tree according to the specified map.
362
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
363
    :param repository: Repository that contains the revisions
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
364
    :param replace_map: Dictionary with revisions to (optionally) rewrite
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
365
    :param merge_fn: Function for replaying a revision
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
366
    """
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
367
    # Figure out the dependencies
0.436.127 by Jelmer Vernooij
Use standard graph functions.
368
    graph = repository.get_graph()
369
    todo = list(graph.iter_topo_order(replace_map.keys()))
0.436.125 by Jelmer Vernooij
Use single call to find present revisions.
370
    pb = ui.ui_factory.nested_progress_bar()
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
371
    try:
0.436.127 by Jelmer Vernooij
Use standard graph functions.
372
        for i, revid in enumerate(todo):
373
            pb.update('rebase revisions', i, len(todo))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
374
            (newrevid, newparents) = replace_map[revid]
0.436.91 by Jelmer Vernooij
Fix blackbox tests, add comments to assertions.
375
            assert isinstance(newparents, tuple), "Expected tuple for %r" % newparents
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
376
            if repository.has_revision(newrevid):
377
                # Was already converted, no need to worry about it again
378
                continue
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
379
            revision_rewriter(revid, newrevid, newparents)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
380
    finally:
381
        pb.finished()
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
382
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
383
0.436.246 by Jelmer Vernooij
Use record_iter_changes in rebase.
384
def wrap_iter_changes(old_iter_changes, map_tree):
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
385
    for change in old_iter_changes:
386
        if change.parent_id[0] is not None:
387
            old_parent = map_tree.new_id(change.parent_id[0])
388
        else:
389
            old_parent = change.parent_id[0]
390
        if change.parent_id[1] is not None:
391
            new_parent = map_tree.new_id(change.parent_id[1])
392
        else:
393
            new_parent = change.parent_id[1]
7406.3.5 by Jelmer Vernooij
Fix formatting.
394
        yield TreeChange(
395
            map_tree.new_id(change.file_id), change.path,
396
            change.changed_content, change.versioned,
397
            (old_parent, new_parent), change.name, change.kind,
398
            change.executable)
0.436.246 by Jelmer Vernooij
Use record_iter_changes in rebase.
399
400
0.436.204 by Jelmer Vernooij
Split up large method.
401
class CommitBuilderRevisionRewriter(object):
402
    """Revision rewriter that use commit builder.
403
404
    :ivar repository: Repository in which the revision is present.
405
    """
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
406
0.436.209 by Jelmer Vernooij
Add map_ids option to CommitBuilderRevisionRewriter.
407
    def __init__(self, repository, map_ids=True):
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
408
        self.repository = repository
0.436.209 by Jelmer Vernooij
Add map_ids option to CommitBuilderRevisionRewriter.
409
        self.map_ids = map_ids
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
410
0.436.204 by Jelmer Vernooij
Split up large method.
411
    def _get_present_revisions(self, revids):
412
        return tuple([p for p in revids if self.repository.has_revision(p)])
413
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
414
    def __call__(self, oldrevid, newrevid, new_parents):
415
        """Replay a commit by simply commiting the same snapshot with different
416
        parents.
417
418
        :param oldrevid: Revision id of the revision to copy.
419
        :param newrevid: Revision id of the revision to create.
420
        :param new_parents: Revision ids of the new parent revisions.
421
        """
0.436.204 by Jelmer Vernooij
Split up large method.
422
        assert isinstance(new_parents, tuple), "CommitBuilderRevisionRewriter: Expected tuple for %r" % new_parents
7406.3.5 by Jelmer Vernooij
Fix formatting.
423
        mutter('creating copy %r of %r with new parents %r',
7406.3.6 by Jelmer Vernooij
Fix tests.
424
               newrevid, oldrevid, new_parents)
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
425
        oldrev = self.repository.get_revision(oldrevid)
426
427
        revprops = dict(oldrev.properties)
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
428
        revprops[REVPROP_REBASE_OF] = oldrevid.decode('utf-8')
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
429
0.436.246 by Jelmer Vernooij
Use record_iter_changes in rebase.
430
        # Check what new_ie.file_id should be
431
        # use old and new parent trees to generate new_id map
432
        nonghost_oldparents = self._get_present_revisions(oldrev.parent_ids)
433
        nonghost_newparents = self._get_present_revisions(new_parents)
434
        oldtree = self.repository.revision_tree(oldrevid)
435
        if self.map_ids:
7406.3.5 by Jelmer Vernooij
Fix formatting.
436
            fileid_map = map_file_ids(
437
                self.repository, nonghost_oldparents,
0.436.246 by Jelmer Vernooij
Use record_iter_changes in rebase.
438
                nonghost_newparents)
439
            mappedtree = MapTree(oldtree, fileid_map)
440
        else:
441
            mappedtree = oldtree
442
443
        try:
444
            old_base = nonghost_oldparents[0]
445
        except IndexError:
446
            old_base = NULL_REVISION
447
        try:
448
            new_base = new_parents[0]
449
        except IndexError:
450
            new_base = NULL_REVISION
451
        old_base_tree = self.repository.revision_tree(old_base)
452
        old_iter_changes = oldtree.iter_changes(old_base_tree)
453
        iter_changes = wrap_iter_changes(old_iter_changes, mappedtree)
7406.3.5 by Jelmer Vernooij
Fix formatting.
454
        builder = self.repository.get_commit_builder(
455
            branch=None, parents=new_parents, committer=oldrev.committer,
0.436.204 by Jelmer Vernooij
Split up large method.
456
            timestamp=oldrev.timestamp, timezone=oldrev.timezone,
0.436.245 by Jelmer Vernooij
Drop < 2.5 support.
457
            revprops=revprops, revision_id=newrevid,
458
            config_stack=_mod_config.GlobalStack())
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
459
        try:
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
460
            for (relpath, fs_hash) in builder.record_iter_changes(
0.436.246 by Jelmer Vernooij
Use record_iter_changes in rebase.
461
                    mappedtree, new_base, iter_changes):
462
                pass
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
463
            builder.finish_inventory()
464
            return builder.commit(oldrev.message)
465
        except:
466
            builder.abort()
467
            raise
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
468
469
0.436.203 by Jelmer Vernooij
Use camelcasing for class names.
470
class WorkingTreeRevisionRewriter(object):
0.436.228 by Jelmer Vernooij
use new style classes.
471
0.436.197 by Jelmer Vernooij
Use class.
472
    def __init__(self, wt, state, merge_type=None):
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
473
        """
474
        :param wt: Working tree in which to do the replays.
475
        """
0.436.197 by Jelmer Vernooij
Use class.
476
        self.wt = wt
0.436.201 by Jelmer Vernooij
Make determine_base a method.
477
        self.graph = self.wt.branch.repository.get_graph()
0.436.197 by Jelmer Vernooij
Use class.
478
        self.state = state
479
        self.merge_type = merge_type
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
480
0.436.198 by Jelmer Vernooij
Refactor revision rewriters as objects.
481
    def __call__(self, oldrevid, newrevid, newparents):
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
482
        """Replay a commit in a working tree, with a different base.
483
484
        :param oldrevid: Old revision id
485
        :param newrevid: New revision id
486
        :param newparents: New parent revision ids
0.436.197 by Jelmer Vernooij
Use class.
487
        """
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
488
        repository = self.wt.branch.repository
489
        if self.merge_type is None:
7406.3.2 by Jelmer Vernooij
Update for breezy.
490
            from ...merge import Merge3Merger
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
491
            merge_type = Merge3Merger
0.444.1 by John Szakmeister
Don't traceback when the user specifies the --merge option to rebase.
492
        else:
493
            merge_type = self.merge_type
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
494
        oldrev = self.wt.branch.repository.get_revision(oldrevid)
495
        # Make sure there are no conflicts or pending merges/changes
496
        # in the working tree
497
        complete_revert(self.wt, [newparents[0]])
498
        assert not self.wt.changes_from(self.wt.basis_tree()).has_changed(), "Changes in rev"
499
500
        oldtree = repository.revision_tree(oldrevid)
501
        self.state.write_active_revid(oldrevid)
502
        merger = Merger(self.wt.branch, this_tree=self.wt)
503
        merger.set_other_revision(oldrevid, self.wt.branch)
7406.3.5 by Jelmer Vernooij
Fix formatting.
504
        base_revid = self.determine_base(
505
            oldrevid, oldrev.parent_ids, newrevid, newparents)
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
506
        mutter('replaying %r as %r with base %r and new parents %r' %
507
               (oldrevid, newrevid, base_revid, newparents))
508
        merger.set_base_revision(base_revid, self.wt.branch)
509
        merger.merge_type = merge_type
510
        merger.do_merge()
511
        for newparent in newparents[1:]:
512
            self.wt.add_pending_merge(newparent)
0.436.200 by Jelmer Vernooij
Move in commit_rebase.
513
        self.commit_rebase(oldrev, newrevid)
0.436.199 by Jelmer Vernooij
Eliminate unnecessary function call.
514
        self.state.write_active_revid(None)
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
515
0.436.201 by Jelmer Vernooij
Make determine_base a method.
516
    def determine_base(self, oldrevid, oldparents, newrevid, newparents):
517
        """Determine the base for replaying a revision using merge.
518
519
        :param oldrevid: Revid of old revision.
520
        :param oldparents: List of old parents revids.
521
        :param newrevid: Revid of new revision.
522
        :param newparents: List of new parents revids.
523
        :return: Revision id of the new new revision.
524
        """
525
        # If this was the first commit, no base is needed
526
        if len(oldparents) == 0:
527
            return NULL_REVISION
528
529
        # In the case of a "simple" revision with just one parent,
530
        # that parent should be the base
531
        if len(oldparents) == 1:
532
            return oldparents[0]
533
0.436.204 by Jelmer Vernooij
Split up large method.
534
        # In case the rhs parent(s) of the origin revision has already been
535
        # merged in the new branch, use diff between rhs parent and diff from
0.436.201 by Jelmer Vernooij
Make determine_base a method.
536
        # original revision
537
        if len(newparents) == 1:
538
            # FIXME: Find oldparents entry that matches newparents[0]
539
            # and return it
540
            return oldparents[1]
541
542
        try:
7406.3.5 by Jelmer Vernooij
Fix formatting.
543
            return self.graph.find_unique_lca(*[oldparents[0], newparents[1]])
0.436.201 by Jelmer Vernooij
Make determine_base a method.
544
        except NoCommonAncestor:
545
            return oldparents[0]
546
0.436.200 by Jelmer Vernooij
Move in commit_rebase.
547
    def commit_rebase(self, oldrev, newrevid):
548
        """Commit a rebase.
549
550
        :param oldrev: Revision info of new revision to commit.
551
        :param newrevid: New revision id."""
552
        assert oldrev.revision_id != newrevid, "Invalid revid %r" % newrevid
553
        revprops = dict(oldrev.properties)
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
554
        revprops[REVPROP_REBASE_OF] = oldrev.revision_id.decode('utf-8')
0.436.200 by Jelmer Vernooij
Move in commit_rebase.
555
        committer = self.wt.branch.get_config().username()
556
        authors = oldrev.get_apparent_authors()
557
        if oldrev.committer == committer:
558
            # No need to explicitly record the authors if the original
559
            # committer is rebasing.
560
            if [oldrev.committer] == authors:
561
                authors = None
562
        else:
7406.3.5 by Jelmer Vernooij
Fix formatting.
563
            if oldrev.committer not in authors:
0.436.200 by Jelmer Vernooij
Move in commit_rebase.
564
                authors.append(oldrev.committer)
565
        if 'author' in revprops:
566
            del revprops['author']
567
        if 'authors' in revprops:
568
            del revprops['authors']
7406.3.5 by Jelmer Vernooij
Fix formatting.
569
        self.wt.commit(
570
            message=oldrev.message, timestamp=oldrev.timestamp,
571
            timezone=oldrev.timezone, revprops=revprops, rev_id=newrevid,
572
            committer=committer, authors=authors)
0.436.200 by Jelmer Vernooij
Move in commit_rebase.
573
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
574
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
575
def complete_revert(wt, newparents):
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
576
    """Simple helper that reverts to specified new parents and makes sure none
0.436.16 by Jelmer Vernooij
Some more work on maptree.
577
    of the extra files are left around.
578
579
    :param wt: Working tree to use for rebase
580
    :param newparents: New parents of the working tree
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
581
    """
582
    newtree = wt.branch.repository.revision_tree(newparents[0])
583
    delta = wt.changes_from(newtree)
584
    wt.branch.generate_revision_history(newparents[0])
0.436.138 by Jelmer Vernooij
Support replaying in empty branch.
585
    wt.set_parent_ids([r for r in newparents[:1] if r != NULL_REVISION])
7406.3.3 by Jelmer Vernooij
Fix python3 compatibility.
586
    for change in delta.added:
587
        abs_path = wt.abspath(change.path[1])
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
588
        if osutils.lexists(abs_path):
0.436.38 by Jelmer Vernooij
Handle directories in revert.
589
            if osutils.isdir(abs_path):
590
                osutils.rmtree(abs_path)
591
            else:
592
                os.unlink(abs_path)
0.436.48 by Jelmer Vernooij
Add replay command.
593
    wt.revert(None, old_tree=newtree, backups=False)
0.436.91 by Jelmer Vernooij
Fix blackbox tests, add comments to assertions.
594
    assert not wt.changes_from(wt.basis_tree()).has_changed(), "Rev changed"
0.436.138 by Jelmer Vernooij
Support replaying in empty branch.
595
    wt.set_parent_ids([r for r in newparents if r != NULL_REVISION])
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
596
597
0.436.34 by Jelmer Vernooij
Some more tests.
598
class ReplaySnapshotError(BzrError):
0.436.74 by Jelmer Vernooij
Add pydoctor file, more docstrings.
599
    """Raised when replaying a snapshot failed."""
0.436.151 by Jelmer Vernooij
Rename message to msg because the first happens to have the same name as an attribute that is deprecated in python 2.6.
600
    _fmt = """Replaying the snapshot failed: %(msg)s."""
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
601
0.436.151 by Jelmer Vernooij
Rename message to msg because the first happens to have the same name as an attribute that is deprecated in python 2.6.
602
    def __init__(self, msg):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
603
        BzrError.__init__(self)
0.436.151 by Jelmer Vernooij
Rename message to msg because the first happens to have the same name as an attribute that is deprecated in python 2.6.
604
        self.msg = msg