/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
2
# 
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.81 by Jelmer Vernooij
Change license to GPLv3+
5
# the Free Software Foundation; either version 3 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.16 by Jelmer Vernooij
Some more work on maptree.
16
"""Rebase."""
0.436.3 by Jelmer Vernooij
Fill in commands.
17
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
18
from bzrlib.config import Config
0.436.52 by Jelmer Vernooij
Add docstrings, update NEWS.
19
from bzrlib.errors import (BzrError, NoSuchFile, UnknownFormatError, 
0.436.84 by Jelmer Vernooij
Support rebasing pending merges.
20
                           NoCommonAncestor, UnrelatedBranches)
0.436.4 by Jelmer Vernooij
Add some tests.
21
from bzrlib.generate_ids import gen_revision_id
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
22
from bzrlib.merge import Merger
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
23
from bzrlib import osutils
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
24
from bzrlib.revision import NULL_REVISION
0.436.4 by Jelmer Vernooij
Add some tests.
25
from bzrlib.trace import mutter
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
26
import bzrlib.ui as ui
0.436.4 by Jelmer Vernooij
Add some tests.
27
0.436.17 by Jelmer Vernooij
Move maptree code to separate files.
28
from maptree import MapTree, map_file_ids
0.436.38 by Jelmer Vernooij
Handle directories in revert.
29
import os
0.436.17 by Jelmer Vernooij
Move maptree code to separate files.
30
0.436.3 by Jelmer Vernooij
Fill in commands.
31
REBASE_PLAN_FILENAME = 'rebase-plan'
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
32
REBASE_CURRENT_REVID_FILENAME = 'rebase-current'
0.436.4 by Jelmer Vernooij
Add some tests.
33
REBASE_PLAN_VERSION = 1
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
34
REVPROP_REBASE_OF = 'rebase-of'
0.436.3 by Jelmer Vernooij
Fill in commands.
35
36
def rebase_plan_exists(wt):
37
    """Check whether there is a rebase plan present.
38
39
    :param wt: Working tree for which to check.
40
    :return: boolean
41
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
42
    try:
43
        return wt._control_files.get(REBASE_PLAN_FILENAME).read() != ''
44
    except NoSuchFile:
45
        return False
0.436.3 by Jelmer Vernooij
Fill in commands.
46
47
48
def read_rebase_plan(wt):
49
    """Read a rebase plan file.
50
51
    :param wt: Working Tree for which to write the plan.
0.436.4 by Jelmer Vernooij
Add some tests.
52
    :return: Tuple with last revision info and replace map.
0.436.3 by Jelmer Vernooij
Fill in commands.
53
    """
54
    text = wt._control_files.get(REBASE_PLAN_FILENAME).read()
55
    if text == '':
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
56
        raise NoSuchFile(REBASE_PLAN_FILENAME)
0.436.4 by Jelmer Vernooij
Add some tests.
57
    return unmarshall_rebase_plan(text)
58
59
60
def write_rebase_plan(wt, replace_map):
0.436.3 by Jelmer Vernooij
Fill in commands.
61
    """Write a rebase plan file.
62
63
    :param wt: Working Tree for which to write the plan.
0.436.4 by Jelmer Vernooij
Add some tests.
64
    :param replace_map: Replace map (old revid -> (new revid, new parents))
0.436.3 by Jelmer Vernooij
Fill in commands.
65
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
66
    wt._control_files.put_utf8(REBASE_PLAN_FILENAME, 
67
            marshall_rebase_plan(wt.branch.last_revision_info(), replace_map))
0.436.3 by Jelmer Vernooij
Fill in commands.
68
69
70
def remove_rebase_plan(wt):
71
    """Remove a rebase plan file.
72
73
    :param wt: Working Tree for which to remove the plan.
74
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
75
    wt._control_files.put_utf8(REBASE_PLAN_FILENAME, '')
0.436.3 by Jelmer Vernooij
Fill in commands.
76
77
0.436.4 by Jelmer Vernooij
Add some tests.
78
def marshall_rebase_plan(last_rev_info, replace_map):
0.436.3 by Jelmer Vernooij
Fill in commands.
79
    """Marshall a rebase plan.
80
81
    :param last_rev_info: Last revision info tuple.
0.436.4 by Jelmer Vernooij
Add some tests.
82
    :param replace_map: Replace map (old revid -> (new revid, new parents))
0.436.3 by Jelmer Vernooij
Fill in commands.
83
    :return: string
84
    """
0.436.4 by Jelmer Vernooij
Add some tests.
85
    ret = "# Bazaar rebase plan %d\n" % REBASE_PLAN_VERSION
86
    ret += "%d %s\n" % last_rev_info
87
    for oldrev in replace_map:
88
        (newrev, newparents) = replace_map[oldrev]
89
        ret += "%s %s" % (oldrev, newrev) + \
90
            "".join([" %s" % p for p in newparents]) + "\n"
91
    return ret
92
93
94
def unmarshall_rebase_plan(text):
0.436.3 by Jelmer Vernooij
Fill in commands.
95
    """Unmarshall a rebase plan.
96
97
    :param text: Text to parse
0.436.4 by Jelmer Vernooij
Add some tests.
98
    :return: Tuple with last revision info, replace map.
0.436.3 by Jelmer Vernooij
Fill in commands.
99
    """
0.436.4 by Jelmer Vernooij
Add some tests.
100
    lines = text.split('\n')
101
    # Make sure header is there
102
    if lines[0] != "# Bazaar rebase plan %d" % REBASE_PLAN_VERSION:
103
        raise UnknownFormatError(lines[0])
104
105
    pts = lines[1].split(" ", 1)
106
    last_revision_info = (int(pts[0]), pts[1])
107
    replace_map = {}
108
    for l in lines[2:]:
109
        if l == "":
110
            # Skip empty lines
111
            continue
112
        pts = l.split(" ")
113
        replace_map[pts[0]] = (pts[1], pts[2:])
114
    return (last_revision_info, replace_map)
115
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
116
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
117
def regenerate_default_revid(repository, revid):
0.436.52 by Jelmer Vernooij
Add docstrings, update NEWS.
118
    """Generate a revision id for the rebase of an existing revision.
119
    
120
    :param repository: Repository in which the revision is present.
121
    :param revid: Revision id of the revision that is being rebased.
122
    :return: new revision id."""
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
123
    rev = repository.get_revision(revid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
124
    return gen_revision_id(rev.committer, rev.timestamp)
125
126
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
127
def generate_simple_plan(history, start_revid, stop_revid, onto_revid, 
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
128
                         onto_ancestry, graph, generate_revid,
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
129
                         skip_full_merged=False):
0.436.3 by Jelmer Vernooij
Fill in commands.
130
    """Create a simple rebase plan that replays history based 
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
131
    on one revision being replayed on top of another.
0.436.3 by Jelmer Vernooij
Fill in commands.
132
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
133
    :param history: Revision history
134
    :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.
135
    :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.
136
    :param onto_revid: Id of revision on top of which to replay
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
137
    :param onto_ancestry: Ancestry of onto_revid
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
138
    :param graph: Graph object
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
139
    :param generate_revid: Function for generating new revision ids
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
140
    :param skip_full_merged: Skip revisions that merge already merged 
141
                             revisions.
0.436.3 by Jelmer Vernooij
Fill in commands.
142
0.436.4 by Jelmer Vernooij
Add some tests.
143
    :return: replace map
0.436.3 by Jelmer Vernooij
Fill in commands.
144
    """
0.436.43 by Jelmer Vernooij
Factor out common revid code - maybe some of this can use aaron's common ancestor code instead?
145
    assert start_revid is None or start_revid in history
146
    assert stop_revid is None or stop_revid in history
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
147
    replace_map = {}
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
148
    if start_revid is not None:
149
        start_revno = history.index(start_revid)
150
    else:
151
        start_revno = None
152
    if stop_revid is not None:
153
        stop_revno = history.index(stop_revid)+1
154
    else:
155
        stop_revno = None
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
156
    new_parent = onto_revid
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
157
    todo = history[start_revno:stop_revno]
158
    parent_map = graph.get_parent_map(todo)
159
    for oldrevid in todo: 
160
        oldparents = parent_map[oldrevid]
161
        assert isinstance(oldparents, tuple), "not tuple: %r" % oldparents
162
        assert oldparents == () or \
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
163
                oldparents[0] == history[history.index(oldrevid)-1]
164
        if len(oldparents) > 1:
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
165
            parents = (new_parent,) + tuple(filter(lambda p: p not in onto_ancestry or p == onto_revid, oldparents[1:]))
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
166
            if len(parents) == 1 and skip_full_merged:
167
                continue
168
        else:
169
            parents = [new_parent]
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
170
        newrevid = generate_revid(oldrevid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
171
        assert newrevid != oldrevid
172
        replace_map[oldrevid] = (newrevid, parents)
173
        new_parent = newrevid
174
    return replace_map
175
176
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
177
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
178
    """Create a rebase plan that replaces a bunch of revisions
179
    in a revision graph.
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
180
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
181
    :param ancestry: Ancestry to consider
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
182
    :param renames: Renames of revision
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
183
    :param graph: Graph object
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
184
    :param generate_revid: Function for creating new revision ids
185
    """
186
    replace_map = {}
187
    todo = []
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
188
    children = {}
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
189
    parent_map = {}
190
    for r, ps in ancestry:
191
        parent_map[r] = ps
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
192
        if not children.has_key(r):
193
            children[r] = []
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
194
        for p in ps:
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
195
            if not children.has_key(p):
196
                children[p] = []
197
            children[p].append(r)
198
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
199
    parent_map.update(graph.get_parent_map(filter(lambda x: not x in parent_map, renames.values())))
200
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
201
    # todo contains a list of revisions that need to 
202
    # be rewritten
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
203
    for r, v in renames.items():
204
        replace_map[r] = (v, parent_map[v])
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
205
        todo.append(r)
206
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
207
    total = len(todo)
208
    processed = set()
209
    i = 0
210
    pb = ui.ui_factory.nested_progress_bar()
211
    try:
212
        while len(todo) > 0:
213
            r = todo.pop()
214
            i += 1
215
            pb.update('determining dependencies', i, total)
216
            # Add entry for them in replace_map
217
            for c in children[r]:
218
                if c in renames:
219
                    continue
220
                if replace_map.has_key(c):
0.436.62 by Jelmer Vernooij
Fix compatibility with packs.
221
                    parents = list(replace_map[c][1])
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
222
                else:
0.436.88 by Jelmer Vernooij
Avoid use of get_revision_graph() calls.
223
                    parents = list(parent_map[c])
0.436.36 by Jelmer Vernooij
Fix compatibility with bzr 0.19.
224
                assert isinstance(parents, list), \
225
                        "Expected list of parents, got: %r" % parents
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
226
                # replace r in parents with replace_map[r][0]
227
                if not replace_map[r][0] in parents:
228
                    parents[parents.index(r)] = replace_map[r][0]
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
229
                replace_map[c] = (generate_revid(c), parents)
230
                assert replace_map[c][0] != c
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
231
            processed.add(r)
232
            # Add them to todo[]
0.436.15 by Jelmer Vernooij
Fix inverse bug - needs tests.
233
            todo.extend(filter(lambda x: not x in processed, children[r]))
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
234
    finally:
235
        pb.finished()
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
236
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
237
    # Remove items from the map that already exist
238
    for revid in renames:
239
        if replace_map.has_key(revid):
240
            del replace_map[revid]
241
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
242
    return replace_map
243
244
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
245
def rebase_todo(repository, replace_map):
246
    """Figure out what revisions still need to be rebased.
247
248
    :param repository: Repository that contains the revisions
249
    :param replace_map: Replace map
250
    """
251
    for revid in replace_map:
252
        if not repository.has_revision(replace_map[revid][0]):
253
            yield revid
254
255
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
256
def rebase(repository, replace_map, replay_fn):
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
257
    """Rebase a working tree according to the specified map.
258
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
259
    :param repository: Repository that contains the revisions
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
260
    :param replace_map: Dictionary with revisions to (optionally) rewrite
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
261
    :param merge_fn: Function for replaying a revision
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
262
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
263
    todo = list(rebase_todo(repository, replace_map))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
264
    dependencies = {}
265
266
    # Figure out the dependencies
267
    for revid in todo:
268
        for p in replace_map[revid][1]:
269
            if repository.has_revision(p):
270
                continue
271
            if not dependencies.has_key(p):
272
                dependencies[p] = []
273
            dependencies[p].append(revid)
274
275
    pb = ui.ui_factory.nested_progress_bar()
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
276
    total = len(todo)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
277
    i = 0
278
    try:
279
        while len(todo) > 0:
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
280
            pb.update('rebase revisions', i, total)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
281
            i += 1
282
            revid = todo.pop()
283
            (newrevid, newparents) = replace_map[revid]
0.436.86 by Jelmer Vernooij
Fix some uses of get_revision_graph().
284
            assert isinstance(newparents, tuple)
0.436.19 by Jelmer Vernooij
- Add blackbox tests
285
            if filter(repository.has_revision, newparents) != newparents:
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
286
                # Not all parents present yet, avoid for now
287
                continue
288
            if repository.has_revision(newrevid):
289
                # Was already converted, no need to worry about it again
290
                continue
291
            replay_fn(repository, revid, newrevid, newparents)
292
            if dependencies.has_key(newrevid):
293
                todo.extend(dependencies[newrevid])
294
                del dependencies[newrevid]
295
    finally:
296
        pb.finished()
297
        
0.436.19 by Jelmer Vernooij
- Add blackbox tests
298
    #assert all(map(repository.has_revision, 
299
    #           [replace_map[r][0] for r in replace_map]))
0.436.16 by Jelmer Vernooij
Some more work on maptree.
300
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
301
302
0.436.34 by Jelmer Vernooij
Some more tests.
303
def replay_snapshot(repository, oldrevid, newrevid, new_parents, 
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
304
                    revid_renames, fix_revid=None):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
305
    """Replay a commit by simply commiting the same snapshot with different 
306
    parents.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
307
308
    :param repository: Repository in which the revision is present.
309
    :param oldrevid: Revision id of the revision to copy.
310
    :param newrevid: Revision id of the revision to create.
311
    :param new_parents: Revision ids of the new parent revisions.
0.436.34 by Jelmer Vernooij
Some more tests.
312
    :param revid_renames: Revision id renames for texts.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
313
    """
314
    assert isinstance(new_parents, list)
0.436.16 by Jelmer Vernooij
Some more work on maptree.
315
    mutter('creating copy %r of %r with new parents %r' % 
316
                               (newrevid, oldrevid, new_parents))
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
317
    oldrev = repository.get_revision(oldrevid)
318
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
319
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
320
    revprops[REVPROP_REBASE_OF] = oldrevid
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
321
0.436.49 by Jelmer Vernooij
Fix locking.
322
    builder = repository.get_commit_builder(branch=None, 
323
                                            parents=new_parents, 
324
                                            config=Config(),
325
                                            committer=oldrev.committer,
326
                                            timestamp=oldrev.timestamp,
327
                                            timezone=oldrev.timezone,
328
                                            revprops=revprops,
329
                                            revision_id=newrevid)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
330
    try:
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
331
        # Check what new_ie.file_id should be
332
        # use old and new parent inventories to generate new_id map
333
        fileid_map = map_file_ids(repository, oldrev.parent_ids, new_parents)
334
        oldtree = MapTree(repository.revision_tree(oldrevid), fileid_map)
335
        total = len(oldtree.inventory)
336
        pb = ui.ui_factory.nested_progress_bar()
337
        i = 0
338
        try:
339
            parent_invs = map(repository.get_revision_inventory, new_parents)
340
            transact = repository.get_transaction()
341
            for path, ie in oldtree.inventory.iter_entries():
342
                pb.update('upgrading file', i, total)
343
                ie = ie.copy()
344
                # Either this file was modified last in this revision, 
345
                # in which case it has to be rewritten
346
                if fix_revid is not None:
347
                    ie.revision = fix_revid(ie.revision)
348
                if ie.revision == oldrevid:
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
349
                    if repository.weave_store.get_weave_or_empty(ie.file_id, 
350
                            repository.get_transaction()).has_version(newrevid):
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
351
                        ie.revision = newrevid
352
                    else:
353
                        ie.revision = None
354
                else:
355
                    # or it was already there before the commit, in 
356
                    # which case the right revision should be used
357
                    if revid_renames.has_key(ie.revision):
358
                        ie.revision = revid_renames[ie.revision]
359
                    # make sure at least one of the new parents contains 
360
                    # the ie.file_id, ie.revision combination
0.436.50 by Jelmer Vernooij
Fix inconsistent parent errors.
361
                    if len(filter(lambda inv: ie.file_id in inv and inv[ie.file_id].revision == ie.revision, parent_invs)) == 0:
362
                        raise ReplayParentsInconsistent(ie.file_id, ie.revision)
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
363
                i += 1
364
                builder.record_entry_contents(ie, parent_invs, path, oldtree,
365
                        oldtree.path_content_summary(path))
366
        finally:
367
            pb.finished()
368
        builder.finish_inventory()
0.436.62 by Jelmer Vernooij
Fix compatibility with packs.
369
        return builder.commit(oldrev.message)
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
370
    except:
0.436.62 by Jelmer Vernooij
Fix compatibility with packs.
371
        builder.abort()
0.436.47 by Jelmer Vernooij
Add progress bar, fix compatibility with bzr.dev.
372
        raise
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
373
374
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
375
def commit_rebase(wt, oldrev, newrevid):
376
    """Commit a rebase.
377
    
378
    :param wt: Mutable tree with the changes.
379
    :param oldrev: Revision info of new revision to commit.
380
    :param newrevid: New revision id."""
381
    assert oldrev.revision_id != newrevid
382
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
383
    revprops[REVPROP_REBASE_OF] = oldrev.revision_id
0.439.3 by Lukáš Lalinský
Copy author or committer name from the old revision to the author property in the new revision
384
    committer = wt.branch.get_config().username()
385
    author = oldrev.get_apparent_author()
386
    if author == committer or 'author' in revprops:
387
        author = None
0.436.37 by Jelmer Vernooij
Store parents correctly.
388
    wt.commit(message=oldrev.message, timestamp=oldrev.timestamp, 
0.439.3 by Lukáš Lalinský
Copy author or committer name from the old revision to the author property in the new revision
389
              timezone=oldrev.timezone, revprops=revprops, rev_id=newrevid,
390
              committer=committer, author=author)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
391
    write_active_rebase_revid(wt, None)
392
393
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
394
def replay_determine_base(graph, oldrevid, oldparents, newrevid, newparents):
0.436.74 by Jelmer Vernooij
Add pydoctor file, more docstrings.
395
    """Determine the base for replaying a revision using merge.
396
397
    :param graph: Revision graph.
398
    :param oldrevid: Revid of old revision.
399
    :param oldparents: List of old parents revids.
400
    :param newrevid: Revid of new revision.
401
    :param newparents: List of new parents revids.
402
    :return: Revision id of the new new revision.
403
    """
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
404
    # If this was the first commit, no base is needed
405
    if len(oldparents) == 0:
406
        return NULL_REVISION
407
408
    # In the case of a "simple" revision with just one parent, 
409
    # that parent should be the base
410
    if len(oldparents) == 1:
411
        return oldparents[0]
412
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
413
    # In case the rhs parent(s) of the origin revision has already been merged
414
    # in the new branch, use diff between rhs parent and diff from 
415
    # original revision
416
    if len(newparents) == 1:
417
        # FIXME: Find oldparents entry that matches newparents[0] 
418
        # and return it
419
        return oldparents[1]
420
0.436.57 by Jelmer Vernooij
Allow overridding whether merges of already merged revisions should be replayed.
421
    try:
422
        return graph.find_unique_lca(*[oldparents[0],newparents[1]])
423
    except NoCommonAncestor:
424
        return oldparents[0]
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
425
426
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
427
def replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
428
                             merge_type=None):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
429
    """Replay a commit in a working tree, with a different base.
430
431
    :param wt: Working tree in which to do the replays.
432
    :param oldrevid: Old revision id
433
    :param newrevid: New revision id
434
    :param newparents: New parent revision ids
435
    """
436
    repository = wt.branch.repository
437
    if merge_type is None:
438
        from bzrlib.merge import Merge3Merger
439
        merge_type = Merge3Merger
440
    oldrev = wt.branch.repository.get_revision(oldrevid)
441
    # Make sure there are no conflicts or pending merges/changes 
442
    # in the working tree
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
443
    complete_revert(wt, [newparents[0]])
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
444
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
445
446
    oldtree = repository.revision_tree(oldrevid)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
447
    write_active_rebase_revid(wt, oldrevid)
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
448
    merger = Merger(wt.branch, this_tree=wt)
449
    merger.set_other_revision(oldrevid, wt.branch)
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
450
    base_revid = replay_determine_base(repository.get_graph(), 
451
                                       oldrevid, oldrev.parent_ids,
452
                                       newrevid, newparents)
0.436.55 by Jelmer Vernooij
Add functinality for skipping duplicate merges.
453
    mutter('replaying %r as %r with base %r and new parents %r' % 
454
           (oldrevid, newrevid, base_revid, newparents))
0.436.54 by Jelmer Vernooij
Move determination of merge base to separate function.
455
    merger.set_base_revision(base_revid, wt.branch)
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
456
    merger.merge_type = merge_type
457
    merger.do_merge()
458
    for newparent in newparents[1:]:
459
        wt.add_pending_merge(newparent)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
460
    commit_rebase(wt, oldrev, newrevid)
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
461
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
462
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
463
def workingtree_replay(wt, map_ids=False, merge_type=None):
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
464
    """Returns a function that can replay revisions in wt.
465
466
    :param wt: Working tree in which to do the replays.
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
467
    :param map_ids: Whether to try to map between file ids (False for path-based merge)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
468
    """
469
    def replay(repository, oldrevid, newrevid, newparents):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
470
        assert wt.branch.repository == repository
0.436.16 by Jelmer Vernooij
Some more work on maptree.
471
        return replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
472
                                        merge_type=merge_type)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
473
    return replay
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
474
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
475
476
def write_active_rebase_revid(wt, revid):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
477
    """Write the id of the revision that is currently being rebased. 
478
479
    :param wt: Working Tree that is being used for the rebase.
480
    :param revid: Revision id to write
481
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
482
    if revid is None:
483
        revid = NULL_REVISION
484
    wt._control_files.put_utf8(REBASE_CURRENT_REVID_FILENAME, revid)
485
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
486
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
487
def read_active_rebase_revid(wt):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
488
    """Read the id of the revision that is currently being rebased.
489
490
    :param wt: Working Tree that is being used for the rebase.
491
    :return: Id of the revision that is being rebased.
492
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
493
    try:
494
        text = wt._control_files.get(REBASE_CURRENT_REVID_FILENAME).read().rstrip("\n")
495
        if text == NULL_REVISION:
496
            return None
497
        return text
498
    except NoSuchFile:
499
        return None
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
500
501
502
def complete_revert(wt, newparents):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
503
    """Simple helper that reverts to specified new parents and makes sure none 
504
    of the extra files are left around.
505
506
    :param wt: Working tree to use for rebase
507
    :param newparents: New parents of the working tree
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
508
    """
509
    newtree = wt.branch.repository.revision_tree(newparents[0])
510
    delta = wt.changes_from(newtree)
511
    wt.branch.generate_revision_history(newparents[0])
0.436.38 by Jelmer Vernooij
Handle directories in revert.
512
    wt.set_parent_ids(newparents[:1])
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
513
    for (f, _, _) in delta.added:
514
        abs_path = wt.abspath(f)
515
        if osutils.lexists(abs_path):
0.436.38 by Jelmer Vernooij
Handle directories in revert.
516
            if osutils.isdir(abs_path):
517
                osutils.rmtree(abs_path)
518
            else:
519
                os.unlink(abs_path)
0.436.48 by Jelmer Vernooij
Add replay command.
520
    wt.revert(None, old_tree=newtree, backups=False)
0.436.38 by Jelmer Vernooij
Handle directories in revert.
521
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.37 by Jelmer Vernooij
Store parents correctly.
522
    wt.set_parent_ids(newparents)
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
523
524
0.436.34 by Jelmer Vernooij
Some more tests.
525
class ReplaySnapshotError(BzrError):
0.436.74 by Jelmer Vernooij
Add pydoctor file, more docstrings.
526
    """Raised when replaying a snapshot failed."""
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
527
    _fmt = """Replaying the snapshot failed: %(message)s."""
528
529
    def __init__(self, message):
530
        BzrError.__init__(self)
531
        self.message = message
0.436.34 by Jelmer Vernooij
Some more tests.
532
533
534
class ReplayParentsInconsistent(BzrError):
0.436.74 by Jelmer Vernooij
Add pydoctor file, more docstrings.
535
    """Raised when parents were inconsistent."""
0.436.34 by Jelmer Vernooij
Some more tests.
536
    _fmt = """Parents were inconsistent while replaying commit for file id %(fileid)s, revision %(revid)s."""
537
538
    def __init__(self, fileid, revid):
539
        BzrError.__init__(self)
540
        self.fileid = fileid
541
        self.revid = revid