~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branchbuilder.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 15:46:03 UTC
  • mfrom: (4985.3.21 update)
  • mto: This revision was merged to the branch mainline in revision 5021.
  • Revision ID: v.ladeuil+lp@free.fr-20100210154603-k4no1gvfuqpzrw7p
Update performs two merges in a more logical order but stop on conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2007, 2008, 2009 Canonical Ltd
2
2
#
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
12
12
#
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Utility for create branches with particular contents."""
18
18
 
19
19
from bzrlib import (
20
 
    bzrdir, 
 
20
    bzrdir,
21
21
    commit,
22
22
    errors,
23
23
    memorytree,
26
26
 
27
27
class BranchBuilder(object):
28
28
    r"""A BranchBuilder aids creating Branches with particular shapes.
29
 
    
 
29
 
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.
57
57
    """
58
58
 
59
 
    def __init__(self, transport, format=None):
 
59
    def __init__(self, transport=None, format=None, branch=None):
60
60
        """Construct a BranchBuilder on transport.
61
 
        
 
61
 
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.
67
69
        """
68
 
        if not transport.has('.'):
69
 
            transport.mkdir('.')
70
 
        if format is None:
71
 
            format = 'default'
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)
 
70
        if branch is not None:
 
71
            if format is not None:
 
72
                raise AssertionError(
 
73
                    "branch and format kwargs are mutually exclusive")
 
74
            if transport is not None:
 
75
                raise AssertionError(
 
76
                    "branch and transport kwargs are mutually exclusive")
 
77
            self._branch = branch
 
78
        else:
 
79
            if not transport.has('.'):
 
80
                transport.mkdir('.')
 
81
            if format is None:
 
82
                format = 'default'
 
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)
76
87
        self._tree = None
77
88
 
78
 
    def build_commit(self):
79
 
        """Build a commit on the branch."""
 
89
    def build_commit(self, **commit_kwargs):
 
90
        """Build a commit on the branch.
 
91
 
 
92
        This makes a commit with no real file content for when you only want
 
93
        to look at the revision graph structure.
 
94
 
 
95
        :param commit_kwargs: Arguments to pass through to commit, such as
 
96
             timestamp.
 
97
        """
80
98
        tree = memorytree.MemoryTree.create_on_branch(self._branch)
81
99
        tree.lock_write()
82
100
        try:
83
101
            tree.add('')
84
 
            return self._do_commit(tree)
 
102
            return self._do_commit(tree, **commit_kwargs)
85
103
        finally:
86
104
            tree.unlock()
87
105
 
93
111
            reporter=reporter,
94
112
            **kwargs)
95
113
 
96
 
    def _move_branch_pointer(self, new_revision_id):
 
114
    def _move_branch_pointer(self, new_revision_id,
 
115
        allow_leftmost_as_ghost=False):
97
116
        """Point self._branch to a different revision id."""
98
117
        self._branch.lock_write()
99
118
        try:
100
119
            # We don't seem to have a simple set_last_revision(), so we
101
120
            # implement it here.
102
121
            cur_revno, cur_revision_id = self._branch.last_revision_info()
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)
 
122
            try:
 
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:
 
129
                    raise
 
130
                new_revno = 1
107
131
        finally:
108
132
            self._branch.unlock()
109
133
        if self._tree is not None:
137
161
        self._tree = None
138
162
 
139
163
    def build_snapshot(self, revision_id, parent_ids, actions,
140
 
                       message=None):
 
164
        message=None, timestamp=None, allow_leftmost_as_ghost=False,
 
165
        committer=None, timezone=None):
141
166
        """Build a commit, shaped in a specific way.
142
167
 
143
168
        :param revision_id: The handle for the new commit, can be None
150
175
            ('rename', ('orig-path', 'new-path'))
151
176
        :param message: An optional commit message, if not supplied, a default
152
177
            commit message will be written.
 
178
        :param timestamp: If non-None, set the timestamp of the commit to this
 
179
            value.
 
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.
153
184
        :return: The revision_id of the new commit
154
185
        """
155
186
        if parent_ids is not None:
156
187
            base_id = parent_ids[0]
157
188
            if base_id != self._branch.last_revision():
158
 
                self._move_branch_pointer(base_id)
 
189
                self._move_branch_pointer(base_id,
 
190
                    allow_leftmost_as_ghost=allow_leftmost_as_ghost)
159
191
 
160
192
        if self._tree is not None:
161
193
            tree = self._tree
164
196
        tree.lock_write()
165
197
        try:
166
198
            if parent_ids is not None:
167
 
                tree.set_parent_ids(parent_ids)
 
199
                tree.set_parent_ids(parent_ids,
 
200
                    allow_leftmost_as_ghost=allow_leftmost_as_ghost)
168
201
            # Unfortunately, MemoryTree.add(directory) just creates an
169
202
            # inventory entry. And the only public function to create a
170
203
            # directory is MemoryTree.mkdir() which creates the directory, but
210
243
            tree.add(to_add_files, to_add_file_ids, to_add_kinds)
211
244
            for file_id, content in new_contents.iteritems():
212
245
                tree.put_file_bytes_non_atomic(file_id, content)
213
 
            return self._do_commit(tree, message=message, rev_id=revision_id) 
 
246
            return self._do_commit(tree, message=message, rev_id=revision_id,
 
247
                timestamp=timestamp, timezone=timezone, committer=committer)
214
248
        finally:
215
249
            tree.unlock()
216
250