~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/mutabletree.py

  • Committer: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 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
20
20
"""
21
21
 
22
22
 
23
 
from bzrlib import tree
 
23
from bzrlib import (
 
24
    errors,
 
25
    osutils,
 
26
    tree,
 
27
    )
24
28
from bzrlib.decorators import needs_read_lock, needs_write_lock
25
29
from bzrlib.osutils import splitpath
26
30
from bzrlib.symbol_versioning import DEPRECATED_PARAMETER
58
62
    branch and bzrdir attributes.
59
63
    """
60
64
 
61
 
    @needs_write_lock
 
65
    @needs_tree_write_lock
62
66
    def add(self, files, ids=None, kinds=None):
63
67
        """Add paths to the set of versioned paths.
64
68
 
86
90
            if kinds is not None:
87
91
                kinds = [kinds]
88
92
 
 
93
        files = [path.strip('/') for path in files]
 
94
 
89
95
        if ids is None:
90
96
            ids = [None] * len(files)
91
97
        else:
92
98
            assert(len(ids) == len(files))
 
99
            ids = [osutils.safe_file_id(file_id) for file_id in ids]
93
100
 
94
101
        if kinds is None:
95
102
            kinds = [None] * len(files)
100
107
            if self.is_control_filename(f):
101
108
                raise errors.ForbiddenControlFileError(filename=f)
102
109
            fp = splitpath(f)
103
 
            if len(fp) == 0:
104
 
                raise BzrError("cannot add top-level %r" % f)
105
110
        # fill out file kinds for all files [not needed when we stop 
106
111
        # caring about the instantaneous file kind within a uncommmitted tree
107
112
        #
108
113
        self._gather_kinds(files, kinds)
109
114
        self._add(files, ids, kinds)
110
115
 
 
116
    def add_reference(self, sub_tree):
 
117
        """Add a TreeReference to the tree, pointing at sub_tree"""
 
118
        raise errors.UnsupportedOperation(self.add_reference, self)
 
119
 
 
120
    def _add_reference(self, sub_tree):
 
121
        """Standard add_reference implementation, for use by subclasses"""
 
122
        try:
 
123
            sub_tree_path = self.relpath(sub_tree.basedir)
 
124
        except errors.PathNotChild:
 
125
            raise errors.BadReferenceTarget(self, sub_tree,
 
126
                                            'Target not inside tree.')
 
127
        sub_tree_id = sub_tree.get_root_id()
 
128
        if sub_tree_id == self.get_root_id():
 
129
            raise errors.BadReferenceTarget(self, sub_tree,
 
130
                                     'Trees have the same root id.')
 
131
        if sub_tree_id in self.inventory:
 
132
            raise errors.BadReferenceTarget(self, sub_tree,
 
133
                                            'Root id already present in tree')
 
134
        self._add([sub_tree_path], [sub_tree_id], ['tree-reference'])
 
135
 
111
136
    def _add(self, files, ids, kinds):
112
 
        """Helper function for add - updates the inventory."""
 
137
        """Helper function for add - updates the inventory.
 
138
 
 
139
        :param files: sequence of pathnames, relative to the tree root
 
140
        :param ids: sequence of suggested ids for the files (may be None)
 
141
        :param kinds: sequence of  inventory kinds of the files (i.e. may
 
142
            contain "tree-reference")
 
143
        """
113
144
        raise NotImplementedError(self._add)
114
145
 
 
146
    @needs_tree_write_lock
 
147
    def apply_inventory_delta(self, changes):
 
148
        """Apply changes to the inventory as an atomic operation.
 
149
 
 
150
        The argument is a set of changes to apply.  It must describe a
 
151
        valid result, but the order is not important.  Specifically,
 
152
        intermediate stages *may* be invalid, such as when two files
 
153
        swap names.
 
154
 
 
155
        The changes should be structured as a list of tuples, of the form
 
156
        (old_path, new_path, file_id, new_entry).  For creation, old_path
 
157
        must be None.  For deletion, new_path and new_entry must be None.
 
158
        file_id is always non-None.  For renames and other mutations, all
 
159
        values must be non-None.
 
160
 
 
161
        If the new_entry is a directory, its children should be an empty
 
162
        dict.  Children are handled by apply_inventory_delta itself.
 
163
 
 
164
        :param changes: A list of tuples for the change to apply:
 
165
            [(old_path, new_path, file_id, new_inventory_entry), ...]
 
166
        """
 
167
        self.flush()
 
168
        inv = self.inventory
 
169
        children = {}
 
170
        for old_path, file_id in sorted(((op, f) for op, np, f, e in changes
 
171
                                        if op is not None), reverse=True):
 
172
            if file_id not in inv:
 
173
                continue
 
174
            children[file_id] = getattr(inv[file_id], 'children', {})
 
175
            inv.remove_recursive_id(file_id)
 
176
        for new_path, new_entry in sorted((np, e) for op, np, f, e in
 
177
                                          changes if np is not None):
 
178
            if getattr(new_entry, 'children', None) is not None:
 
179
                new_entry.children = children.get(new_entry.file_id, {})
 
180
            inv.add(new_entry)
 
181
        self._write_inventory(inv)
 
182
 
115
183
    @needs_write_lock
116
 
    def commit(self, message=None, revprops=None, *args, **kwargs):
 
184
    def commit(self, message=None, revprops=None, *args,
 
185
               **kwargs):
117
186
        # avoid circular imports
118
187
        from bzrlib import commit
119
188
        if revprops is None:
121
190
        if not 'branch-nick' in revprops:
122
191
            revprops['branch-nick'] = self.branch.nick
123
192
        # args for wt.commit start at message from the Commit.commit method,
124
 
        # but with branch a kwarg now, passing in args as is results in the
125
 
        #message being used for the branch
126
 
        args = (DEPRECATED_PARAMETER, message, ) + args
 
193
        args = (message, ) + args
127
194
        committed_id = commit.Commit().commit(working_tree=self,
128
195
            revprops=revprops, *args, **kwargs)
129
196
        return committed_id
178
245
        """
179
246
        raise NotImplementedError(self.mkdir)
180
247
 
 
248
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
 
249
        """Set the parents ids of the working tree.
 
250
 
 
251
        :param revision_ids: A list of revision_ids.
 
252
        """
 
253
        raise NotImplementedError(self.set_parent_ids)
 
254
 
181
255
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
182
256
        """Set the parents of the working tree.
183
257