1
# Copyright (C) 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2007, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Utility for create branches with particular contents."""
19
19
from bzrlib import (
27
27
class BranchBuilder(object):
28
28
r"""A BranchBuilder aids creating Branches with particular shapes.
30
30
The expected way to use BranchBuilder is to construct a
31
31
BranchBuilder on the transport you want your branch on, and then call
32
32
appropriate build_ methods on it to get the shape of history you want.
56
56
a series in progress, it should be None.
59
def __init__(self, transport=None, format=None, branch=None):
59
def __init__(self, transport, format=None):
60
60
"""Construct a BranchBuilder on transport.
62
62
:param transport: The transport the branch should be created on.
63
63
If the path of the transport does not exist but its parent does
64
64
it will be created.
65
65
:param format: Either a BzrDirFormat, or the name of a format in the
66
66
bzrdir format registry for the branch to be built.
67
:param branch: An already constructed branch to use. This param is
68
mutually exclusive with the transport and format params.
70
if branch is not None:
71
if format is not None:
73
"branch and format kwargs are mutually exclusive")
74
if transport is not None:
76
"branch and transport kwargs are mutually exclusive")
79
if not transport.has('.'):
83
if isinstance(format, str):
84
format = bzrdir.format_registry.make_bzrdir(format)
85
self._branch = bzrdir.BzrDir.create_branch_convenience(
86
transport.base, format=format, force_new_tree=False)
68
if not transport.has('.'):
72
if isinstance(format, str):
73
format = bzrdir.format_registry.make_bzrdir(format)
74
self._branch = bzrdir.BzrDir.create_branch_convenience(transport.base,
75
format=format, force_new_tree=False)
89
def build_commit(self, **commit_kwargs):
90
"""Build a commit on the branch.
92
This makes a commit with no real file content for when you only want
93
to look at the revision graph structure.
95
:param commit_kwargs: Arguments to pass through to commit, such as
78
def build_commit(self):
79
"""Build a commit on the branch."""
98
80
tree = memorytree.MemoryTree.create_on_branch(self._branch)
102
return self._do_commit(tree, **commit_kwargs)
84
return self._do_commit(tree)
111
93
reporter=reporter,
114
def _move_branch_pointer(self, new_revision_id,
115
allow_leftmost_as_ghost=False):
96
def _move_branch_pointer(self, new_revision_id):
116
97
"""Point self._branch to a different revision id."""
117
98
self._branch.lock_write()
119
100
# We don't seem to have a simple set_last_revision(), so we
120
101
# implement it here.
121
102
cur_revno, cur_revision_id = self._branch.last_revision_info()
123
g = self._branch.repository.get_graph()
124
new_revno = g.find_distance_to_null(new_revision_id,
125
[(cur_revision_id, cur_revno)])
126
self._branch.set_last_revision_info(new_revno, new_revision_id)
127
except errors.GhostRevisionsHaveNoRevno:
128
if not allow_leftmost_as_ghost:
103
g = self._branch.repository.get_graph()
104
new_revno = g.find_distance_to_null(new_revision_id,
105
[(cur_revision_id, cur_revno)])
106
self._branch.set_last_revision_info(new_revno, new_revision_id)
132
108
self._branch.unlock()
133
109
if self._tree is not None:
161
137
self._tree = None
163
139
def build_snapshot(self, revision_id, parent_ids, actions,
164
message=None, timestamp=None, allow_leftmost_as_ghost=False,
165
committer=None, timezone=None):
166
141
"""Build a commit, shaped in a specific way.
168
143
:param revision_id: The handle for the new commit, can be None
175
150
('rename', ('orig-path', 'new-path'))
176
151
:param message: An optional commit message, if not supplied, a default
177
152
commit message will be written.
178
:param timestamp: If non-None, set the timestamp of the commit to this
180
:param timezone: An optional timezone for timestamp.
181
:param committer: An optional username to use for commit
182
:param allow_leftmost_as_ghost: True if the leftmost parent should be
183
permitted to be a ghost.
184
153
:return: The revision_id of the new commit
186
155
if parent_ids is not None:
187
156
base_id = parent_ids[0]
188
157
if base_id != self._branch.last_revision():
189
self._move_branch_pointer(base_id,
190
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
158
self._move_branch_pointer(base_id)
192
160
if self._tree is not None:
193
161
tree = self._tree
196
164
tree.lock_write()
198
166
if parent_ids is not None:
199
tree.set_parent_ids(parent_ids,
200
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
167
tree.set_parent_ids(parent_ids)
201
168
# Unfortunately, MemoryTree.add(directory) just creates an
202
169
# inventory entry. And the only public function to create a
203
170
# directory is MemoryTree.mkdir() which creates the directory, but
243
210
tree.add(to_add_files, to_add_file_ids, to_add_kinds)
244
211
for file_id, content in new_contents.iteritems():
245
212
tree.put_file_bytes_non_atomic(file_id, content)
246
return self._do_commit(tree, message=message, rev_id=revision_id,
247
timestamp=timestamp, timezone=timezone, committer=committer)
213
return self._do_commit(tree, message=message, rev_id=revision_id)