/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
1
# Copyright (C) 2007, 2008, 2009 Canonical Ltd
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
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
5
# the Free Software Foundation; either version 2 of the License, or
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
16
17
"""Utility for create branches with particular contents."""
18
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
19
from bzrlib import (
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
20
    bzrdir,
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
21
    commit,
22
    errors,
23
    memorytree,
4476.3.51 by Andrew Bennetts
Fix deserialization of deletes in inventory deltas, don't give up on serialized deltas from a supports_tree_refs repo unless the delta contains tree refs, and experiment to add automatic_root param to branchbuilder.
24
    revision as _mod_revision,
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
25
    )
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
26
27
28
class BranchBuilder(object):
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
29
    r"""A BranchBuilder aids creating Branches with particular shapes.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
30
2466.7.7 by Robert Collins
Document basic usage.
31
    The expected way to use BranchBuilder is to construct a
32
    BranchBuilder on the transport you want your branch on, and then call
33
    appropriate build_ methods on it to get the shape of history you want.
34
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
35
    This is meant as a helper for the test suite, not as a general class for
36
    real data.
37
2466.7.7 by Robert Collins
Document basic usage.
38
    For instance:
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
39
40
    >>> from bzrlib.transport.memory import MemoryTransport
41
    >>> builder = BranchBuilder(MemoryTransport("memory:///"))
42
    >>> builder.start_series()
43
    >>> builder.build_snapshot('rev-id', None, [
44
    ...     ('add', ('', 'root-id', 'directory', '')),
45
    ...     ('add', ('filename', 'f-id', 'file', 'content\n'))])
46
    'rev-id'
47
    >>> builder.build_snapshot('rev2-id', ['rev-id'],
48
    ...     [('modify', ('f-id', 'new-content\n'))])
49
    'rev2-id'
50
    >>> builder.finish_series()
51
    >>> branch = builder.get_branch()
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
52
53
    :ivar _tree: This is a private member which is not meant to be modified by
54
        users of this class. While a 'series' is in progress, it should hold a
55
        MemoryTree with the contents of the last commit (ready to be modified
56
        by the next build_snapshot command) with a held write lock. Outside of
57
        a series in progress, it should be None.
2466.7.7 by Robert Collins
Document basic usage.
58
    """
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
59
4476.3.51 by Andrew Bennetts
Fix deserialization of deletes in inventory deltas, don't give up on serialized deltas from a supports_tree_refs repo unless the delta contains tree refs, and experiment to add automatic_root param to branchbuilder.
60
    def __init__(self, transport=None, format=None, branch=None,
61
            automatic_root=False):
2466.7.5 by Robert Collins
Better docstring for BranchBuilder.__init__.
62
        """Construct a BranchBuilder on transport.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
63
2466.7.5 by Robert Collins
Better docstring for BranchBuilder.__init__.
64
        :param transport: The transport the branch should be created on.
65
            If the path of the transport does not exist but its parent does
66
            it will be created.
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
67
        :param format: Either a BzrDirFormat, or the name of a format in the
68
            bzrdir format registry for the branch to be built.
4257.3.8 by Andrew Bennetts
Fix TestCase.make_branch_builder to make a branch in the specified format. Also add an interrepo test scenario for KnitPack1 -> KnitPack6RichRoot, which fails.
69
        :param branch: An already constructed branch to use.  This param is
70
            mutually exclusive with the transport and format params.
4476.3.51 by Andrew Bennetts
Fix deserialization of deletes in inventory deltas, don't give up on serialized deltas from a supports_tree_refs repo unless the delta contains tree refs, and experiment to add automatic_root param to branchbuilder.
71
        :param automatic_root: if True, a root entry will be created
72
            automatically.  The rich-root support of the branch's repository is
73
            taken into account when automatically creating a root.  Pass False
74
            if you want to add the root explicitly (and handle rich-root vs.
75
            not manually).
2466.7.5 by Robert Collins
Better docstring for BranchBuilder.__init__.
76
        """
4257.3.8 by Andrew Bennetts
Fix TestCase.make_branch_builder to make a branch in the specified format. Also add an interrepo test scenario for KnitPack1 -> KnitPack6RichRoot, which fails.
77
        if branch is not None:
78
            if format is not None:
79
                raise AssertionError(
80
                    "branch and format kwargs are mutually exclusive")
81
            if transport is not None:
82
                raise AssertionError(
83
                    "branch and transport kwargs are mutually exclusive")
84
            self._branch = branch
85
        else:
86
            if not transport.has('.'):
87
                transport.mkdir('.')
88
            if format is None:
89
                format = 'default'
90
            if isinstance(format, str):
91
                format = bzrdir.format_registry.make_bzrdir(format)
92
            self._branch = bzrdir.BzrDir.create_branch_convenience(
93
                transport.base, format=format, force_new_tree=False)
3567.4.17 by John Arbash Meinel
Add the ability to define a series of commits, which allows us to hold open the locks.
94
        self._tree = None
4476.3.51 by Andrew Bennetts
Fix deserialization of deletes in inventory deltas, don't give up on serialized deltas from a supports_tree_refs repo unless the delta contains tree refs, and experiment to add automatic_root param to branchbuilder.
95
        self._automatic_root = automatic_root
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
96
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
97
    def build_commit(self, **commit_kwargs):
98
        """Build a commit on the branch.
4070.4.12 by Martin Pool
Kill trailing whitespace
99
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
100
        This makes a commit with no real file content for when you only want
101
        to look at the revision graph structure.
102
103
        :param commit_kwargs: Arguments to pass through to commit, such as
104
             timestamp.
105
        """
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
106
        tree = memorytree.MemoryTree.create_on_branch(self._branch)
107
        tree.lock_write()
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
108
        try:
109
            tree.add('')
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
110
            return self._do_commit(tree, **commit_kwargs)
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
111
        finally:
112
            tree.unlock()
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
113
3825.3.2 by Martin Pool
Correct example of branchbuilder and change to a doctest, and refactor
114
    def _do_commit(self, tree, message=None, **kwargs):
115
        reporter = commit.NullCommitReporter()
116
        if message is None:
117
            message = u'commit %d' % (self._branch.revno() + 1,)
118
        return tree.commit(message,
119
            reporter=reporter,
120
            **kwargs)
121
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
122
    def _move_branch_pointer(self, new_revision_id,
123
        allow_leftmost_as_ghost=False):
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
124
        """Point self._branch to a different revision id."""
125
        self._branch.lock_write()
126
        try:
127
            # We don't seem to have a simple set_last_revision(), so we
128
            # implement it here.
129
            cur_revno, cur_revision_id = self._branch.last_revision_info()
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
130
            try:
131
                g = self._branch.repository.get_graph()
132
                new_revno = g.find_distance_to_null(new_revision_id,
133
                    [(cur_revision_id, cur_revno)])
134
                self._branch.set_last_revision_info(new_revno, new_revision_id)
135
            except errors.GhostRevisionsHaveNoRevno:
136
                if not allow_leftmost_as_ghost:
137
                    raise
138
                new_revno = 1
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
139
        finally:
140
            self._branch.unlock()
3567.4.17 by John Arbash Meinel
Add the ability to define a series of commits, which allows us to hold open the locks.
141
        if self._tree is not None:
142
            # We are currently processing a series, but when switching branch
143
            # pointers, it is easiest to just create a new memory tree.
144
            # That way we are sure to have the right files-on-disk
145
            # We are cheating a little bit here, and locking the new tree
146
            # before the old tree is unlocked. But that way the branch stays
147
            # locked throughout.
148
            new_tree = memorytree.MemoryTree.create_on_branch(self._branch)
149
            new_tree.lock_write()
150
            self._tree.unlock()
151
            self._tree = new_tree
152
153
    def start_series(self):
154
        """We will be creating a series of commits.
155
156
        This allows us to hold open the locks while we are processing.
157
158
        Make sure to call 'finish_series' when you are done.
159
        """
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
160
        if self._tree is not None:
161
            raise AssertionError('You cannot start a new series while a'
162
                                 ' series is already going.')
3567.4.17 by John Arbash Meinel
Add the ability to define a series of commits, which allows us to hold open the locks.
163
        self._tree = memorytree.MemoryTree.create_on_branch(self._branch)
164
        self._tree.lock_write()
165
166
    def finish_series(self):
167
        """Call this after start_series to unlock the various objects."""
168
        self._tree.unlock()
169
        self._tree = None
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
170
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
171
    def build_snapshot(self, revision_id, parent_ids, actions,
4454.3.24 by John Arbash Meinel
update BranchBuilder to support 'committer'
172
        message=None, timestamp=None, allow_leftmost_as_ghost=False,
4523.2.1 by Vincent Ladeuil
Fix TZ-dependent tests.
173
        committer=None, timezone=None):
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
174
        """Build a commit, shaped in a specific way.
175
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
176
        :param revision_id: The handle for the new commit, can be None
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
177
        :param parent_ids: A list of parent_ids to use for the commit.
178
            It can be None, which indicates to use the last commit.
179
        :param actions: A list of actions to perform. Supported actions are:
180
            ('add', ('path', 'file-id', 'kind', 'content' or None))
181
            ('modify', ('file-id', 'new-content'))
182
            ('unversion', 'file-id')
3567.5.2 by John Arbash Meinel
'rename' is a supported action.
183
            ('rename', ('orig-path', 'new-path'))
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
184
        :param message: An optional commit message, if not supplied, a default
185
            commit message will be written.
4070.4.12 by Martin Pool
Kill trailing whitespace
186
        :param timestamp: If non-None, set the timestamp of the commit to this
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
187
            value.
4523.2.1 by Vincent Ladeuil
Fix TZ-dependent tests.
188
        :param timezone: An optional timezone for timestamp.
4454.3.24 by John Arbash Meinel
update BranchBuilder to support 'committer'
189
        :param committer: An optional username to use for commit
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
190
        :param allow_leftmost_as_ghost: True if the leftmost parent should be
191
            permitted to be a ghost.
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
192
        :return: The revision_id of the new commit
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
193
        """
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
194
        if parent_ids is not None:
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
195
            base_id = parent_ids[0]
196
            if base_id != self._branch.last_revision():
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
197
                self._move_branch_pointer(base_id,
198
                    allow_leftmost_as_ghost=allow_leftmost_as_ghost)
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
199
3567.4.17 by John Arbash Meinel
Add the ability to define a series of commits, which allows us to hold open the locks.
200
        if self._tree is not None:
201
            tree = self._tree
202
        else:
203
            tree = memorytree.MemoryTree.create_on_branch(self._branch)
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
204
        tree.lock_write()
205
        try:
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
206
            if parent_ids is not None:
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
207
                tree.set_parent_ids(parent_ids,
208
                    allow_leftmost_as_ghost=allow_leftmost_as_ghost)
4476.3.51 by Andrew Bennetts
Fix deserialization of deletes in inventory deltas, don't give up on serialized deltas from a supports_tree_refs repo unless the delta contains tree refs, and experiment to add automatic_root param to branchbuilder.
209
            elif self._branch.last_revision() == _mod_revision.NULL_REVISION:
210
                if self._automatic_root:
211
                    # No parent revision, and automatic_root.  Create an
212
                    # appropriate root entry.
213
                    if self._branch.repository.supports_rich_root():
214
                        from bzrlib.generate_ids import gen_root_id
215
                        new_root_id = gen_root_id()
216
                    else:
217
                        from bzrlib.inventory import ROOT_ID
218
                        new_root_id = ROOT_ID
219
                    add_root_action = (
220
                        'add', ('', new_root_id, 'directory', None))
221
                    actions = [add_root_action] + list(actions)
222
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
223
            # Unfortunately, MemoryTree.add(directory) just creates an
224
            # inventory entry. And the only public function to create a
225
            # directory is MemoryTree.mkdir() which creates the directory, but
226
            # also always adds it. So we have to use a multi-pass setup.
227
            to_add_directories = []
228
            to_add_files = []
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
229
            to_add_file_ids = []
230
            to_add_kinds = []
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
231
            new_contents = {}
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
232
            to_unversion_ids = []
3567.5.1 by John Arbash Meinel
Implement rename_one on MemoryTree, and expose that in the Branch Builder
233
            to_rename = []
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
234
            for action, info in actions:
235
                if action == 'add':
236
                    path, file_id, kind, content = info
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
237
                    if kind == 'directory':
238
                        to_add_directories.append((path, file_id))
239
                    else:
240
                        to_add_files.append(path)
241
                        to_add_file_ids.append(file_id)
242
                        to_add_kinds.append(kind)
243
                        if content is not None:
244
                            new_contents[file_id] = content
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
245
                elif action == 'modify':
246
                    file_id, content = info
247
                    new_contents[file_id] = content
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
248
                elif action == 'unversion':
249
                    to_unversion_ids.append(info)
3567.5.1 by John Arbash Meinel
Implement rename_one on MemoryTree, and expose that in the Branch Builder
250
                elif action == 'rename':
251
                    from_relpath, to_relpath = info
252
                    to_rename.append((from_relpath, to_relpath))
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
253
                else:
3567.4.18 by John Arbash Meinel
Apply the review changes from Martin to the exact patch he approved.
254
                    raise ValueError('Unknown build action: "%s"' % (action,))
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
255
            if to_unversion_ids:
256
                tree.unversion(to_unversion_ids)
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
257
            for path, file_id in to_add_directories:
258
                if path == '':
259
                    # Special case, because the path already exists
260
                    tree.add([path], [file_id], ['directory'])
261
                else:
262
                    tree.mkdir(path, file_id)
3567.5.1 by John Arbash Meinel
Implement rename_one on MemoryTree, and expose that in the Branch Builder
263
            for from_relpath, to_relpath in to_rename:
264
                tree.rename_one(from_relpath, to_relpath)
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
265
            tree.add(to_add_files, to_add_file_ids, to_add_kinds)
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
266
            for file_id, content in new_contents.iteritems():
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
267
                tree.put_file_bytes_non_atomic(file_id, content)
4070.5.1 by Martin Pool
BranchBuilder now takes a timestamp for commits
268
            return self._do_commit(tree, message=message, rev_id=revision_id,
4523.2.1 by Vincent Ladeuil
Fix TZ-dependent tests.
269
                timestamp=timestamp, timezone=timezone, committer=committer)
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
270
        finally:
271
            tree.unlock()
272
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
273
    def get_branch(self):
274
        """Return the branch created by the builder."""
275
        return self._branch