~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/memorytree.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""MemoryTree object.
18
18
 
20
20
"""
21
21
 
22
22
 
23
 
import os
 
23
from copy import deepcopy
24
24
 
25
 
from bzrlib import (
26
 
    errors,
27
 
    mutabletree,
28
 
    revision as _mod_revision,
29
 
    )
30
 
from bzrlib.decorators import needs_read_lock
 
25
from bzrlib import errors, mutabletree
 
26
from bzrlib.decorators import needs_read_lock, needs_write_lock
31
27
from bzrlib.osutils import sha_file
32
 
from bzrlib.mutabletree import needs_tree_write_lock
33
28
from bzrlib.transport.memory import MemoryTransport
34
29
 
35
30
 
36
31
class MemoryTree(mutabletree.MutableTree):
37
32
    """A MemoryTree is a specialisation of MutableTree.
38
 
 
 
33
    
39
34
    It maintains nearly no state outside of read_lock and write_lock
40
35
    transactions. (it keeps a reference to the branch, and its last-revision
41
36
    only).
49
44
        self._locks = 0
50
45
        self._lock_mode = None
51
46
 
52
 
    @needs_tree_write_lock
 
47
    @needs_write_lock
53
48
    def _add(self, files, ids, kinds):
54
49
        """See MutableTree._add."""
55
50
        for f, file_id, kind in zip(files, ids, kinds):
67
62
    @staticmethod
68
63
    def create_on_branch(branch):
69
64
        """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)
 
65
        return MemoryTree(branch, branch.last_revision())
72
66
 
73
67
    def _gather_kinds(self, files, kinds):
74
68
        """See MutableTree._gather_kinds.
75
 
 
 
69
        
76
70
        This implementation does not care about the file kind of
77
71
        missing files, so is a no-op.
78
72
        """
79
73
 
80
 
    def get_file(self, file_id, path=None):
 
74
    def get_file(self, file_id):
81
75
        """See Tree.get_file."""
82
 
        if path is None:
83
 
            path = self.id2path(file_id)
84
 
        return self._file_transport.get(path)
 
76
        return self._file_transport.get(self.id2path(file_id))
85
77
 
86
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
78
    def get_file_sha1(self, file_id, path=None):
87
79
        """See Tree.get_file_sha1()."""
88
80
        if path is None:
89
81
            path = self.id2path(file_id)
90
82
        stream = self._file_transport.get(path)
91
83
        return sha_file(stream)
92
84
 
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
85
    @needs_read_lock
137
86
    def get_parent_ids(self):
138
87
        """See Tree.get_parent_ids.
149
98
    def is_executable(self, file_id, path=None):
150
99
        return self._inventory[file_id].executable
151
100
 
152
 
    def kind(self, file_id):
153
 
        return self._inventory[file_id].kind
154
 
 
155
101
    def mkdir(self, path, file_id=None):
156
102
        """See MutableTree.mkdir()."""
157
103
        self.add(path, file_id, 'directory')
180
126
            self._locks -= 1
181
127
            raise
182
128
 
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
129
    def lock_write(self):
198
130
        """See MutableTree.lock_write()."""
199
131
        self._locks += 1
210
142
 
211
143
    def _populate_from_branch(self):
212
144
        """Populate the in-tree state from the branch."""
213
 
        self._set_basis()
214
 
        if self._branch_revision_id == _mod_revision.NULL_REVISION:
 
145
        self._basis_tree = self.branch.repository.revision_tree(
 
146
            self._branch_revision_id)
 
147
        if self._branch_revision_id is None:
215
148
            self._parent_ids = []
216
149
        else:
217
150
            self._parent_ids = [self._branch_revision_id]
218
 
        self._inventory = self._basis_tree._inventory._get_mutable_inventory()
 
151
        self._inventory = deepcopy(self._basis_tree._inventory)
219
152
        self._file_transport = MemoryTransport()
220
153
        # TODO copy the revision trees content, or do it lazy, or something.
221
154
        inventory_entries = self._inventory.iter_entries()
 
155
        inventory_entries.next()
222
156
        for path, entry in inventory_entries:
223
 
            if path == '':
224
 
                continue
225
157
            if entry.kind == 'directory':
226
158
                self._file_transport.mkdir(path)
227
159
            elif entry.kind == 'file':
252
184
        else:
253
185
            self._locks -= 1
254
186
 
255
 
    @needs_tree_write_lock
 
187
    @needs_write_lock
256
188
    def unversion(self, file_ids):
257
189
        """Remove the file ids in file_ids from the current versioned set.
258
190
 
271
203
            else:
272
204
                raise errors.NoSuchId(self, file_id)
273
205
 
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
206
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
299
207
        """See MutableTree.set_parent_trees()."""
300
208
        if len(parents_list) == 0:
301
209
            self._parent_ids = []
302
 
            self._basis_tree = self.branch.repository.revision_tree(
303
 
                                   _mod_revision.NULL_REVISION)
 
210
            self._basis_tree = self.branch.repository.revisiontree(None)
304
211
        else:
305
212
            if parents_list[0][1] is None and not allow_leftmost_as_ghost:
306
213
                # a ghost in the left most parent
307
214
                raise errors.GhostRevisionUnusableHere(parents_list[0][0])
308
215
            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)
 
216
            if parents_list[0][1] is None:
 
217
                self._basis_tree = self.branch.repository.revisiontree(None)
312
218
            else:
313
219
                self._basis_tree = parents_list[0][1]
314
220
            self._branch_revision_id = parents_list[0][0]