/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/memorytree.py

  • Committer: Robert Collins
  • Date: 2005-10-16 22:31:25 UTC
  • mto: This revision was merged to the branch mainline in revision 1458.
  • Revision ID: robertc@lifelesslap.robertcollins.net-20051016223125-26d4401cb94b7b82
Branch.relpath has been moved to WorkingTree.relpath.

WorkingTree no no longer takes an inventory, rather it takes an optional branch
parameter, and if None is given will open the branch at basedir implicitly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""MemoryTree object.
18
 
 
19
 
See MemoryTree for more details.
20
 
"""
21
 
 
22
 
 
23
 
import os
24
 
 
25
 
from bzrlib import (
26
 
    errors,
27
 
    mutabletree,
28
 
    revision as _mod_revision,
29
 
    )
30
 
from bzrlib.decorators import needs_read_lock
31
 
from bzrlib.osutils import sha_file
32
 
from bzrlib.mutabletree import needs_tree_write_lock
33
 
from bzrlib.transport.memory import MemoryTransport
34
 
 
35
 
 
36
 
class MemoryTree(mutabletree.MutableTree):
37
 
    """A MemoryTree is a specialisation of MutableTree.
38
 
 
39
 
    It maintains nearly no state outside of read_lock and write_lock
40
 
    transactions. (it keeps a reference to the branch, and its last-revision
41
 
    only).
42
 
    """
43
 
 
44
 
    def __init__(self, branch, revision_id):
45
 
        """Construct a MemoryTree for branch using revision_id."""
46
 
        self.branch = branch
47
 
        self.bzrdir = branch.bzrdir
48
 
        self._branch_revision_id = revision_id
49
 
        self._locks = 0
50
 
        self._lock_mode = None
51
 
 
52
 
    @needs_tree_write_lock
53
 
    def _add(self, files, ids, kinds):
54
 
        """See MutableTree._add."""
55
 
        for f, file_id, kind in zip(files, ids, kinds):
56
 
            if kind is None:
57
 
                kind = 'file'
58
 
            if file_id is None:
59
 
                self._inventory.add_path(f, kind=kind)
60
 
            else:
61
 
                self._inventory.add_path(f, kind=kind, file_id=file_id)
62
 
 
63
 
    def basis_tree(self):
64
 
        """See Tree.basis_tree()."""
65
 
        return self._basis_tree
66
 
 
67
 
    @staticmethod
68
 
    def create_on_branch(branch):
69
 
        """Create a MemoryTree for branch, using the last-revision of branch."""
70
 
        revision_id = _mod_revision.ensure_null(branch.last_revision())
71
 
        return MemoryTree(branch, revision_id)
72
 
 
73
 
    def _gather_kinds(self, files, kinds):
74
 
        """See MutableTree._gather_kinds.
75
 
 
76
 
        This implementation does not care about the file kind of
77
 
        missing files, so is a no-op.
78
 
        """
79
 
 
80
 
    def get_file(self, file_id, path=None):
81
 
        """See Tree.get_file."""
82
 
        if path is None:
83
 
            path = self.id2path(file_id)
84
 
        return self._file_transport.get(path)
85
 
 
86
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
87
 
        """See Tree.get_file_sha1()."""
88
 
        if path is None:
89
 
            path = self.id2path(file_id)
90
 
        stream = self._file_transport.get(path)
91
 
        return sha_file(stream)
92
 
 
93
 
    def get_root_id(self):
94
 
        return self.path2id('')
95
 
 
96
 
    def _comparison_data(self, entry, path):
97
 
        """See Tree._comparison_data."""
98
 
        if entry is None:
99
 
            return None, False, None
100
 
        return entry.kind, entry.executable, None
101
 
 
102
 
    @needs_tree_write_lock
103
 
    def rename_one(self, from_rel, to_rel):
104
 
        file_id = self.path2id(from_rel)
105
 
        to_dir, to_tail = os.path.split(to_rel)
106
 
        to_parent_id = self.path2id(to_dir)
107
 
        self._file_transport.move(from_rel, to_rel)
108
 
        self._inventory.rename(file_id, to_parent_id, to_tail)
109
 
 
110
 
    def path_content_summary(self, path):
111
 
        """See Tree.path_content_summary."""
112
 
        id = self.path2id(path)
113
 
        if id is None:
114
 
            return 'missing', None, None, None
115
 
        kind = self.kind(id)
116
 
        if kind == 'file':
117
 
            bytes = self._file_transport.get_bytes(path)
118
 
            size = len(bytes)
119
 
            executable = self._inventory[id].executable
120
 
            sha1 = None # no stat cache
121
 
            return (kind, size, executable, sha1)
122
 
        elif kind == 'directory':
123
 
            # memory tree does not support nested trees yet.
124
 
            return kind, None, None, None
125
 
        elif kind == 'symlink':
126
 
            raise NotImplementedError('symlink support')
127
 
        else:
128
 
            raise NotImplementedError('unknown kind')
129
 
 
130
 
    def _file_size(self, entry, stat_value):
131
 
        """See Tree._file_size."""
132
 
        if entry is None:
133
 
            return 0
134
 
        return entry.text_size
135
 
 
136
 
    @needs_read_lock
137
 
    def get_parent_ids(self):
138
 
        """See Tree.get_parent_ids.
139
 
 
140
 
        This implementation returns the current cached value from
141
 
            self._parent_ids.
142
 
        """
143
 
        return list(self._parent_ids)
144
 
 
145
 
    def has_filename(self, filename):
146
 
        """See Tree.has_filename()."""
147
 
        return self._file_transport.has(filename)
148
 
 
149
 
    def is_executable(self, file_id, path=None):
150
 
        return self._inventory[file_id].executable
151
 
 
152
 
    def kind(self, file_id):
153
 
        return self._inventory[file_id].kind
154
 
 
155
 
    def mkdir(self, path, file_id=None):
156
 
        """See MutableTree.mkdir()."""
157
 
        self.add(path, file_id, 'directory')
158
 
        if file_id is None:
159
 
            file_id = self.path2id(path)
160
 
        self._file_transport.mkdir(path)
161
 
        return file_id
162
 
 
163
 
    @needs_read_lock
164
 
    def last_revision(self):
165
 
        """See MutableTree.last_revision."""
166
 
        return self._branch_revision_id
167
 
 
168
 
    def lock_read(self):
169
 
        """Lock the memory tree for reading.
170
 
 
171
 
        This triggers population of data from the branch for its revision.
172
 
        """
173
 
        self._locks += 1
174
 
        try:
175
 
            if self._locks == 1:
176
 
                self.branch.lock_read()
177
 
                self._lock_mode = "r"
178
 
                self._populate_from_branch()
179
 
        except:
180
 
            self._locks -= 1
181
 
            raise
182
 
 
183
 
    def lock_tree_write(self):
184
 
        """See MutableTree.lock_tree_write()."""
185
 
        self._locks += 1
186
 
        try:
187
 
            if self._locks == 1:
188
 
                self.branch.lock_read()
189
 
                self._lock_mode = "w"
190
 
                self._populate_from_branch()
191
 
            elif self._lock_mode == "r":
192
 
                raise errors.ReadOnlyError(self)
193
 
        except:
194
 
            self._locks -= 1
195
 
            raise
196
 
 
197
 
    def lock_write(self):
198
 
        """See MutableTree.lock_write()."""
199
 
        self._locks += 1
200
 
        try:
201
 
            if self._locks == 1:
202
 
                self.branch.lock_write()
203
 
                self._lock_mode = "w"
204
 
                self._populate_from_branch()
205
 
            elif self._lock_mode == "r":
206
 
                raise errors.ReadOnlyError(self)
207
 
        except:
208
 
            self._locks -= 1
209
 
            raise
210
 
 
211
 
    def _populate_from_branch(self):
212
 
        """Populate the in-tree state from the branch."""
213
 
        self._set_basis()
214
 
        if self._branch_revision_id == _mod_revision.NULL_REVISION:
215
 
            self._parent_ids = []
216
 
        else:
217
 
            self._parent_ids = [self._branch_revision_id]
218
 
        self._inventory = self._basis_tree._inventory._get_mutable_inventory()
219
 
        self._file_transport = MemoryTransport()
220
 
        # TODO copy the revision trees content, or do it lazy, or something.
221
 
        inventory_entries = self._inventory.iter_entries()
222
 
        for path, entry in inventory_entries:
223
 
            if path == '':
224
 
                continue
225
 
            if entry.kind == 'directory':
226
 
                self._file_transport.mkdir(path)
227
 
            elif entry.kind == 'file':
228
 
                self._file_transport.put_file(path,
229
 
                    self._basis_tree.get_file(entry.file_id))
230
 
            else:
231
 
                raise NotImplementedError(self._populate_from_branch)
232
 
 
233
 
    def put_file_bytes_non_atomic(self, file_id, bytes):
234
 
        """See MutableTree.put_file_bytes_non_atomic."""
235
 
        self._file_transport.put_bytes(self.id2path(file_id), bytes)
236
 
 
237
 
    def unlock(self):
238
 
        """Release a lock.
239
 
 
240
 
        This frees all cached state when the last lock context for the tree is
241
 
        left.
242
 
        """
243
 
        if self._locks == 1:
244
 
            self._basis_tree = None
245
 
            self._parent_ids = []
246
 
            self._inventory = None
247
 
            try:
248
 
                self.branch.unlock()
249
 
            finally:
250
 
                self._locks = 0
251
 
                self._lock_mode = None
252
 
        else:
253
 
            self._locks -= 1
254
 
 
255
 
    @needs_tree_write_lock
256
 
    def unversion(self, file_ids):
257
 
        """Remove the file ids in file_ids from the current versioned set.
258
 
 
259
 
        When a file_id is unversioned, all of its children are automatically
260
 
        unversioned.
261
 
 
262
 
        :param file_ids: The file ids to stop versioning.
263
 
        :raises: NoSuchId if any fileid is not currently versioned.
264
 
        """
265
 
        # XXX: This should be in mutabletree, but the inventory-save action
266
 
        # is not relevant to memory tree. Until that is done in unlock by
267
 
        # working tree, we cannot share the implementation.
268
 
        for file_id in file_ids:
269
 
            if self._inventory.has_id(file_id):
270
 
                self._inventory.remove_recursive_id(file_id)
271
 
            else:
272
 
                raise errors.NoSuchId(self, file_id)
273
 
 
274
 
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
275
 
        """See MutableTree.set_parent_trees()."""
276
 
        for revision_id in revision_ids:
277
 
            _mod_revision.check_not_reserved_id(revision_id)
278
 
        if len(revision_ids) == 0:
279
 
            self._parent_ids = []
280
 
            self._branch_revision_id = _mod_revision.NULL_REVISION
281
 
        else:
282
 
            self._parent_ids = revision_ids
283
 
            self._branch_revision_id = revision_ids[0]
284
 
        self._allow_leftmost_as_ghost = allow_leftmost_as_ghost
285
 
        self._set_basis()
286
 
    
287
 
    def _set_basis(self):
288
 
        try:
289
 
            self._basis_tree = self.branch.repository.revision_tree(
290
 
                self._branch_revision_id)
291
 
        except errors.NoSuchRevision:
292
 
            if self._allow_leftmost_as_ghost:
293
 
                self._basis_tree = self.branch.repository.revision_tree(
294
 
                    _mod_revision.NULL_REVISION)
295
 
            else:
296
 
                raise
297
 
 
298
 
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
299
 
        """See MutableTree.set_parent_trees()."""
300
 
        if len(parents_list) == 0:
301
 
            self._parent_ids = []
302
 
            self._basis_tree = self.branch.repository.revision_tree(
303
 
                                   _mod_revision.NULL_REVISION)
304
 
        else:
305
 
            if parents_list[0][1] is None and not allow_leftmost_as_ghost:
306
 
                # a ghost in the left most parent
307
 
                raise errors.GhostRevisionUnusableHere(parents_list[0][0])
308
 
            self._parent_ids = [parent_id for parent_id, tree in parents_list]
309
 
            if parents_list[0][1] is None or parents_list[0][1] == 'null:':
310
 
                self._basis_tree = self.branch.repository.revision_tree(
311
 
                                       _mod_revision.NULL_REVISION)
312
 
            else:
313
 
                self._basis_tree = parents_list[0][1]
314
 
            self._branch_revision_id = parents_list[0][0]