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
 | 
|
15  | 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
|
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,  | 
|
24  | 
    )
 | 
|
| 
2466.7.3
by Robert Collins
 Create bzrlib.branchbuilder.  | 
25  | 
|
26  | 
||
27  | 
class BranchBuilder(object):  | 
|
| 
3825.3.2
by Martin Pool
 Correct example of branchbuilder and change to a doctest, and refactor  | 
28  | 
r"""A BranchBuilder aids creating Branches with particular shapes.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
29  | 
|
| 
2466.7.7
by Robert Collins
 Document basic usage.  | 
30  | 
    The expected way to use BranchBuilder is to construct a
 | 
31  | 
    BranchBuilder on the transport you want your branch on, and then call
 | 
|
32  | 
    appropriate build_ methods on it to get the shape of history you want.
 | 
|
33  | 
||
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
34  | 
    This is meant as a helper for the test suite, not as a general class for
 | 
35  | 
    real data.
 | 
|
36  | 
||
| 
2466.7.7
by Robert Collins
 Document basic usage.  | 
37  | 
    For instance:
 | 
| 
3825.3.2
by Martin Pool
 Correct example of branchbuilder and change to a doctest, and refactor  | 
38  | 
|
39  | 
    >>> from bzrlib.transport.memory import MemoryTransport
 | 
|
40  | 
    >>> builder = BranchBuilder(MemoryTransport("memory:///"))
 | 
|
41  | 
    >>> builder.start_series()
 | 
|
42  | 
    >>> builder.build_snapshot('rev-id', None, [
 | 
|
43  | 
    ...     ('add', ('', 'root-id', 'directory', '')),
 | 
|
44  | 
    ...     ('add', ('filename', 'f-id', 'file', 'content\n'))])
 | 
|
45  | 
    'rev-id'
 | 
|
46  | 
    >>> builder.build_snapshot('rev2-id', ['rev-id'],
 | 
|
47  | 
    ...     [('modify', ('f-id', 'new-content\n'))])
 | 
|
48  | 
    'rev2-id'
 | 
|
49  | 
    >>> builder.finish_series()
 | 
|
50  | 
    >>> branch = builder.get_branch()
 | 
|
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
51  | 
|
52  | 
    :ivar _tree: This is a private member which is not meant to be modified by
 | 
|
53  | 
        users of this class. While a 'series' is in progress, it should hold a
 | 
|
54  | 
        MemoryTree with the contents of the last commit (ready to be modified
 | 
|
55  | 
        by the next build_snapshot command) with a held write lock. Outside of
 | 
|
56  | 
        a series in progress, it should be None.
 | 
|
| 
2466.7.7
by Robert Collins
 Document basic usage.  | 
57  | 
    """
 | 
| 
2466.7.3
by Robert Collins
 Create bzrlib.branchbuilder.  | 
58  | 
|
| 
2466.7.10
by Robert Collins
 Add a format parameter to BranchBuilder.  | 
59  | 
def __init__(self, transport, format=None):  | 
| 
2466.7.5
by Robert Collins
 Better docstring for BranchBuilder.__init__.  | 
60  | 
"""Construct a BranchBuilder on transport.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
61  | 
|
| 
2466.7.5
by Robert Collins
 Better docstring for BranchBuilder.__init__.  | 
62  | 
        :param transport: The transport the branch should be created on.
 | 
63  | 
            If the path of the transport does not exist but its parent does
 | 
|
64  | 
            it will be created.
 | 
|
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
65  | 
        :param format: Either a BzrDirFormat, or the name of a format in the
 | 
66  | 
            bzrdir format registry for the branch to be built.
 | 
|
| 
2466.7.5
by Robert Collins
 Better docstring for BranchBuilder.__init__.  | 
67  | 
        """
 | 
| 
2466.7.4
by Robert Collins
 Add BranchBuilder.get_branch().  | 
68  | 
if not transport.has('.'):  | 
69  | 
transport.mkdir('.')  | 
|
| 
2466.7.10
by Robert Collins
 Add a format parameter to BranchBuilder.  | 
70  | 
if format is None:  | 
71  | 
format = 'default'  | 
|
| 
3567.4.12
by John Arbash Meinel
 Expose the branch building framework to the test suite.  | 
72  | 
if isinstance(format, str):  | 
73  | 
format = bzrdir.format_registry.make_bzrdir(format)  | 
|
| 
2466.7.4
by Robert Collins
 Add BranchBuilder.get_branch().  | 
74  | 
self._branch = bzrdir.BzrDir.create_branch_convenience(transport.base,  | 
| 
3567.4.13
by John Arbash Meinel
 Test that make_branch_builder works on a real filesystem.  | 
75  | 
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.  | 
76  | 
self._tree = None  | 
| 
2466.7.4
by Robert Collins
 Add BranchBuilder.get_branch().  | 
77  | 
|
| 
4070.5.1
by Martin Pool
 BranchBuilder now takes a timestamp for commits  | 
78  | 
def build_commit(self, **commit_kwargs):  | 
79  | 
"""Build a commit on the branch.  | 
|
| 
4070.4.12
by Martin Pool
 Kill trailing whitespace  | 
80  | 
|
| 
4070.5.1
by Martin Pool
 BranchBuilder now takes a timestamp for commits  | 
81  | 
        This makes a commit with no real file content for when you only want
 | 
82  | 
        to look at the revision graph structure.
 | 
|
83  | 
||
84  | 
        :param commit_kwargs: Arguments to pass through to commit, such as
 | 
|
85  | 
             timestamp.
 | 
|
86  | 
        """
 | 
|
| 
2466.7.6
by Robert Collins
 Add BranchBuilder.build_commit.  | 
87  | 
tree = memorytree.MemoryTree.create_on_branch(self._branch)  | 
88  | 
tree.lock_write()  | 
|
| 
2466.7.9
by Robert Collins
 Return the commited revision id from BranchBuilder.build_commit to save later instrospection.  | 
89  | 
try:  | 
90  | 
tree.add('')  | 
|
| 
4070.5.1
by Martin Pool
 BranchBuilder now takes a timestamp for commits  | 
91  | 
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.  | 
92  | 
finally:  | 
93  | 
tree.unlock()  | 
|
| 
2466.7.6
by Robert Collins
 Add BranchBuilder.build_commit.  | 
94  | 
|
| 
3825.3.2
by Martin Pool
 Correct example of branchbuilder and change to a doctest, and refactor  | 
95  | 
def _do_commit(self, tree, message=None, **kwargs):  | 
96  | 
reporter = commit.NullCommitReporter()  | 
|
97  | 
if message is None:  | 
|
98  | 
message = u'commit %d' % (self._branch.revno() + 1,)  | 
|
99  | 
return tree.commit(message,  | 
|
100  | 
reporter=reporter,  | 
|
101  | 
**kwargs)  | 
|
102  | 
||
| 
3567.4.10
by John Arbash Meinel
 Clean up the build_snapshot api a bit.  | 
103  | 
def _move_branch_pointer(self, new_revision_id):  | 
104  | 
"""Point self._branch to a different revision id."""  | 
|
105  | 
self._branch.lock_write()  | 
|
106  | 
try:  | 
|
107  | 
            # We don't seem to have a simple set_last_revision(), so we
 | 
|
108  | 
            # implement it here.
 | 
|
109  | 
cur_revno, cur_revision_id = self._branch.last_revision_info()  | 
|
110  | 
g = self._branch.repository.get_graph()  | 
|
111  | 
new_revno = g.find_distance_to_null(new_revision_id,  | 
|
112  | 
[(cur_revision_id, cur_revno)])  | 
|
113  | 
self._branch.set_last_revision_info(new_revno, new_revision_id)  | 
|
114  | 
finally:  | 
|
115  | 
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.  | 
116  | 
if self._tree is not None:  | 
117  | 
            # We are currently processing a series, but when switching branch
 | 
|
118  | 
            # pointers, it is easiest to just create a new memory tree.
 | 
|
119  | 
            # That way we are sure to have the right files-on-disk
 | 
|
120  | 
            # We are cheating a little bit here, and locking the new tree
 | 
|
121  | 
            # before the old tree is unlocked. But that way the branch stays
 | 
|
122  | 
            # locked throughout.
 | 
|
123  | 
new_tree = memorytree.MemoryTree.create_on_branch(self._branch)  | 
|
124  | 
new_tree.lock_write()  | 
|
125  | 
self._tree.unlock()  | 
|
126  | 
self._tree = new_tree  | 
|
127  | 
||
128  | 
def start_series(self):  | 
|
129  | 
"""We will be creating a series of commits.  | 
|
130  | 
||
131  | 
        This allows us to hold open the locks while we are processing.
 | 
|
132  | 
||
133  | 
        Make sure to call 'finish_series' when you are done.
 | 
|
134  | 
        """
 | 
|
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
135  | 
if self._tree is not None:  | 
136  | 
raise AssertionError('You cannot start a new series while a'  | 
|
137  | 
' 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.  | 
138  | 
self._tree = memorytree.MemoryTree.create_on_branch(self._branch)  | 
139  | 
self._tree.lock_write()  | 
|
140  | 
||
141  | 
def finish_series(self):  | 
|
142  | 
"""Call this after start_series to unlock the various objects."""  | 
|
143  | 
self._tree.unlock()  | 
|
144  | 
self._tree = None  | 
|
| 
3567.4.10
by John Arbash Meinel
 Clean up the build_snapshot api a bit.  | 
145  | 
|
| 
3567.4.15
by John Arbash Meinel
 Allow setting the commit message.  | 
146  | 
def build_snapshot(self, revision_id, parent_ids, actions,  | 
| 
4070.5.1
by Martin Pool
 BranchBuilder now takes a timestamp for commits  | 
147  | 
message=None, timestamp=None):  | 
| 
3567.4.10
by John Arbash Meinel
 Clean up the build_snapshot api a bit.  | 
148  | 
"""Build a commit, shaped in a specific way.  | 
149  | 
||
| 
3567.4.15
by John Arbash Meinel
 Allow setting the commit message.  | 
150  | 
        :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.  | 
151  | 
        :param parent_ids: A list of parent_ids to use for the commit.
 | 
152  | 
            It can be None, which indicates to use the last commit.
 | 
|
153  | 
        :param actions: A list of actions to perform. Supported actions are:
 | 
|
154  | 
            ('add', ('path', 'file-id', 'kind', 'content' or None))
 | 
|
155  | 
            ('modify', ('file-id', 'new-content'))
 | 
|
156  | 
            ('unversion', 'file-id')
 | 
|
| 
3567.5.2
by John Arbash Meinel
 'rename' is a supported action.  | 
157  | 
            ('rename', ('orig-path', 'new-path'))
 | 
| 
3567.4.15
by John Arbash Meinel
 Allow setting the commit message.  | 
158  | 
        :param message: An optional commit message, if not supplied, a default
 | 
159  | 
            commit message will be written.
 | 
|
| 
4070.4.12
by Martin Pool
 Kill trailing whitespace  | 
160  | 
        :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  | 
161  | 
            value.
 | 
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
162  | 
        :return: The revision_id of the new commit
 | 
| 
3567.4.10
by John Arbash Meinel
 Clean up the build_snapshot api a bit.  | 
163  | 
        """
 | 
| 
3567.4.8
by John Arbash Meinel
 Add the ability to force a basis for a revision.  | 
164  | 
if parent_ids is not None:  | 
| 
3567.4.10
by John Arbash Meinel
 Clean up the build_snapshot api a bit.  | 
165  | 
base_id = parent_ids[0]  | 
166  | 
if base_id != self._branch.last_revision():  | 
|
167  | 
self._move_branch_pointer(base_id)  | 
|
168  | 
||
| 
3567.4.17
by John Arbash Meinel
 Add the ability to define a series of commits, which allows us to hold open the locks.  | 
169  | 
if self._tree is not None:  | 
170  | 
tree = self._tree  | 
|
171  | 
else:  | 
|
172  | 
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.  | 
173  | 
tree.lock_write()  | 
174  | 
try:  | 
|
| 
3567.4.8
by John Arbash Meinel
 Add the ability to force a basis for a revision.  | 
175  | 
if parent_ids is not None:  | 
176  | 
tree.set_parent_ids(parent_ids)  | 
|
| 
3567.4.7
by John Arbash Meinel
 Revert back to using MemoryTree.mkdir() rather than creating the directory during add().  | 
177  | 
            # Unfortunately, MemoryTree.add(directory) just creates an
 | 
178  | 
            # inventory entry. And the only public function to create a
 | 
|
179  | 
            # directory is MemoryTree.mkdir() which creates the directory, but
 | 
|
180  | 
            # also always adds it. So we have to use a multi-pass setup.
 | 
|
181  | 
to_add_directories = []  | 
|
182  | 
to_add_files = []  | 
|
| 
3567.4.1
by John Arbash Meinel
 Initial work to have BranchBuilder allow us to do tree-shape work.  | 
183  | 
to_add_file_ids = []  | 
184  | 
to_add_kinds = []  | 
|
| 
3567.4.3
by John Arbash Meinel
 Add an action for modifying an existing file  | 
185  | 
new_contents = {}  | 
| 
3567.4.4
by John Arbash Meinel
 Add the ability to 'unversion' files, and handle unknown actions.  | 
186  | 
to_unversion_ids = []  | 
| 
3567.5.1
by John Arbash Meinel
 Implement rename_one on MemoryTree, and expose that in the Branch Builder  | 
187  | 
to_rename = []  | 
| 
3567.4.1
by John Arbash Meinel
 Initial work to have BranchBuilder allow us to do tree-shape work.  | 
188  | 
for action, info in actions:  | 
189  | 
if action == 'add':  | 
|
190  | 
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().  | 
191  | 
if kind == 'directory':  | 
192  | 
to_add_directories.append((path, file_id))  | 
|
193  | 
else:  | 
|
194  | 
to_add_files.append(path)  | 
|
195  | 
to_add_file_ids.append(file_id)  | 
|
196  | 
to_add_kinds.append(kind)  | 
|
197  | 
if content is not None:  | 
|
198  | 
new_contents[file_id] = content  | 
|
| 
3567.4.3
by John Arbash Meinel
 Add an action for modifying an existing file  | 
199  | 
elif action == 'modify':  | 
200  | 
file_id, content = info  | 
|
201  | 
new_contents[file_id] = content  | 
|
| 
3567.4.4
by John Arbash Meinel
 Add the ability to 'unversion' files, and handle unknown actions.  | 
202  | 
elif action == 'unversion':  | 
203  | 
to_unversion_ids.append(info)  | 
|
| 
3567.5.1
by John Arbash Meinel
 Implement rename_one on MemoryTree, and expose that in the Branch Builder  | 
204  | 
elif action == 'rename':  | 
205  | 
from_relpath, to_relpath = info  | 
|
206  | 
to_rename.append((from_relpath, to_relpath))  | 
|
| 
3567.4.4
by John Arbash Meinel
 Add the ability to 'unversion' files, and handle unknown actions.  | 
207  | 
else:  | 
| 
3567.4.18
by John Arbash Meinel
 Apply the review changes from Martin to the exact patch he approved.  | 
208  | 
raise ValueError('Unknown build action: "%s"' % (action,))  | 
| 
3567.4.4
by John Arbash Meinel
 Add the ability to 'unversion' files, and handle unknown actions.  | 
209  | 
if to_unversion_ids:  | 
210  | 
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().  | 
211  | 
for path, file_id in to_add_directories:  | 
212  | 
if path == '':  | 
|
213  | 
                    # Special case, because the path already exists
 | 
|
214  | 
tree.add([path], [file_id], ['directory'])  | 
|
215  | 
else:  | 
|
216  | 
tree.mkdir(path, file_id)  | 
|
| 
3567.5.1
by John Arbash Meinel
 Implement rename_one on MemoryTree, and expose that in the Branch Builder  | 
217  | 
for from_relpath, to_relpath in to_rename:  | 
218  | 
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().  | 
219  | 
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  | 
220  | 
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.  | 
221  | 
tree.put_file_bytes_non_atomic(file_id, content)  | 
| 
4070.5.1
by Martin Pool
 BranchBuilder now takes a timestamp for commits  | 
222  | 
return self._do_commit(tree, message=message, rev_id=revision_id,  | 
223  | 
timestamp=timestamp)  | 
|
| 
3567.4.1
by John Arbash Meinel
 Initial work to have BranchBuilder allow us to do tree-shape work.  | 
224  | 
finally:  | 
225  | 
tree.unlock()  | 
|
226  | 
||
| 
2466.7.4
by Robert Collins
 Add BranchBuilder.get_branch().  | 
227  | 
def get_branch(self):  | 
228  | 
"""Return the branch created by the builder."""  | 
|
229  | 
return self._branch  |