/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
1
# Copyright (C) 2007 Canonical Ltd
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
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
19
from bzrlib import bzrdir, errors, memorytree
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
20
21
22
class BranchBuilder(object):
2466.7.7 by Robert Collins
Document basic usage.
23
    """A BranchBuilder aids creating Branches with particular shapes.
24
    
25
    The expected way to use BranchBuilder is to construct a
26
    BranchBuilder on the transport you want your branch on, and then call
27
    appropriate build_ methods on it to get the shape of history you want.
28
29
    For instance:
30
      builder = BranchBuilder(self.get_transport().clone('relpath'))
31
      builder.build_commit()
32
      builder.build_commit()
33
      builder.build_commit()
34
      branch = builder.get_branch()
35
    """
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
36
2466.7.10 by Robert Collins
Add a format parameter to BranchBuilder.
37
    def __init__(self, transport, format=None):
2466.7.5 by Robert Collins
Better docstring for BranchBuilder.__init__.
38
        """Construct a BranchBuilder on transport.
39
        
40
        :param transport: The transport the branch should be created on.
41
            If the path of the transport does not exist but its parent does
42
            it will be created.
2466.7.10 by Robert Collins
Add a format parameter to BranchBuilder.
43
        :param format: The name of a format in the bzrdir format registry
44
            for the branch to be built.
2466.7.5 by Robert Collins
Better docstring for BranchBuilder.__init__.
45
        """
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
46
        if not transport.has('.'):
47
            transport.mkdir('.')
2466.7.10 by Robert Collins
Add a format parameter to BranchBuilder.
48
        if format is None:
49
            format = 'default'
3567.4.12 by John Arbash Meinel
Expose the branch building framework to the test suite.
50
        if isinstance(format, str):
51
            format = bzrdir.format_registry.make_bzrdir(format)
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
52
        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.
53
            format=format, force_new_tree=False)
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
54
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
55
    def build_commit(self):
56
        """Build a commit on the branch."""
57
        tree = memorytree.MemoryTree.create_on_branch(self._branch)
58
        tree.lock_write()
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
59
        try:
60
            tree.add('')
61
            return tree.commit('commit %d' % (self._branch.revno() + 1))
62
        finally:
63
            tree.unlock()
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
64
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
65
    def _move_branch_pointer(self, new_revision_id):
66
        """Point self._branch to a different revision id."""
67
        self._branch.lock_write()
68
        try:
69
            # We don't seem to have a simple set_last_revision(), so we
70
            # implement it here.
71
            cur_revno, cur_revision_id = self._branch.last_revision_info()
72
            g = self._branch.repository.get_graph()
73
            new_revno = g.find_distance_to_null(new_revision_id,
74
                                                [(cur_revision_id, cur_revno)])
75
            self._branch.set_last_revision_info(new_revno, new_revision_id)
76
        finally:
77
            self._branch.unlock()
78
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
79
    def build_snapshot(self, revision_id, parent_ids, actions,
80
                       message=None):
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
81
        """Build a commit, shaped in a specific way.
82
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
83
        :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.
84
        :param parent_ids: A list of parent_ids to use for the commit.
85
            It can be None, which indicates to use the last commit.
86
        :param actions: A list of actions to perform. Supported actions are:
87
            ('add', ('path', 'file-id', 'kind', 'content' or None))
88
            ('modify', ('file-id', 'new-content'))
89
            ('unversion', 'file-id')
90
            # not supported yet: ('rename', ('orig-path', 'new-path'))
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
91
        :param message: An optional commit message, if not supplied, a default
92
            commit message will be written.
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
93
        ;return: The revision_id of the new commit
94
        """
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
95
        if parent_ids is not None:
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
96
            base_id = parent_ids[0]
97
            if base_id != self._branch.last_revision():
98
                self._move_branch_pointer(base_id)
99
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
100
        tree = memorytree.MemoryTree.create_on_branch(self._branch)
101
        tree.lock_write()
102
        try:
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
103
            if parent_ids is not None:
104
                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().
105
            # Unfortunately, MemoryTree.add(directory) just creates an
106
            # inventory entry. And the only public function to create a
107
            # directory is MemoryTree.mkdir() which creates the directory, but
108
            # also always adds it. So we have to use a multi-pass setup.
109
            to_add_directories = []
110
            to_add_files = []
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
111
            to_add_file_ids = []
112
            to_add_kinds = []
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
113
            new_contents = {}
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
114
            to_unversion_ids = []
3567.4.9 by John Arbash Meinel
comments
115
            # TODO: MemoryTree doesn't support rename() or
116
            #       apply_inventory_delta, so we'll postpone allowing renames
117
            #       for now
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
118
            # to_rename = []
119
            for action, info in actions:
120
                if action == 'add':
121
                    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().
122
                    if kind == 'directory':
123
                        to_add_directories.append((path, file_id))
124
                    else:
125
                        to_add_files.append(path)
126
                        to_add_file_ids.append(file_id)
127
                        to_add_kinds.append(kind)
128
                        if content is not None:
129
                            new_contents[file_id] = content
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
130
                elif action == 'modify':
131
                    file_id, content = info
132
                    new_contents[file_id] = content
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
133
                elif action == 'unversion':
134
                    to_unversion_ids.append(info)
135
                else:
136
                    raise errors.UnknownBuildAction(action)
137
            if to_unversion_ids:
138
                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().
139
            for path, file_id in to_add_directories:
140
                if path == '':
141
                    # Special case, because the path already exists
142
                    tree.add([path], [file_id], ['directory'])
143
                else:
144
                    tree.mkdir(path, file_id)
145
            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
146
            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.
147
                tree.put_file_bytes_non_atomic(file_id, content)
148
3567.4.15 by John Arbash Meinel
Allow setting the commit message.
149
            if message is None:
150
                message = u'commit %d' % (self._branch.revno() + 1,)
151
            return tree.commit(message, rev_id=revision_id)
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
152
        finally:
153
            tree.unlock()
154
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
155
    def get_branch(self):
156
        """Return the branch created by the builder."""
157
        return self._branch