/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
1
# Copyright (C) 2008 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
"""CommitHandlers that build and save revisions & their inventories."""
18
19
20
from bzrlib import (
21
    errors,
22
    generate_ids,
23
    inventory,
24
    osutils,
25
    revision,
26
    )
27
from bzrlib.plugins.fastimport import helpers, processor
28
29
0.84.3 by Ian Clatworthy
fix inventory copying when using deltas
30
def copy_inventory(inv):
31
    if hasattr(inv, "_get_mutable_inventory"):
32
        # TODO: Make this a public API on inventory
33
        return inv._get_mutable_inventory()
34
    else:
35
        # TODO: Shallow copy - deep inventory copying is expensive
36
        return inv.copy()
37
38
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
39
class GenericCommitHandler(processor.CommitHandler):
40
    """Base class for Bazaar CommitHandlers."""
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
41
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
42
    def __init__(self, command, cache_mgr, rev_store, verbose=False):
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
43
        super(GenericCommitHandler, self).__init__(command)
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
44
        self.cache_mgr = cache_mgr
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
45
        self.rev_store = rev_store
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
46
        self.verbose = verbose
47
48
    def pre_process_files(self):
49
        """Prepare for committing."""
50
        self.revision_id = self.gen_revision_id()
51
        # cache of texts for this commit, indexed by file-id
52
        self.lines_for_commit = {}
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
53
        if self.rev_store.expects_rich_root():
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
54
            self.lines_for_commit[inventory.ROOT_ID] = []
55
56
        # Track the heads and get the real parent list
57
        parents = self.cache_mgr.track_heads(self.command)
58
59
        # Convert the parent commit-ids to bzr revision-ids
60
        if parents:
61
            self.parents = [self.cache_mgr.revision_ids[p]
62
                for p in parents]
63
        else:
64
            self.parents = []
65
        self.debug("%s id: %s, parents: %s", self.command.id,
66
            self.revision_id, str(self.parents))
67
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
68
        # Keep the basis inventory. This needs to be treated as read-only.
69
        if len(self.parents) == 0:
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
70
            self.basis_inventory = self._init_inventory()
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
71
        else:
72
            self.basis_inventory = self.get_inventory(self.parents[0])
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
73
        if hasattr(self.basis_inventory, "root_id"):
74
            self.inventory_root_id = self.basis_inventory.root_id
75
        else:
76
            self.inventory_root_id = self.basis_inventory.root.file_id
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
77
78
        # directory-path -> inventory-entry for current inventory
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
79
        if self.parents:
80
            self.directory_entries = dict(self.basis_inventory.directories())
81
        else:
82
            self.directory_entries = {}
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
83
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
84
    def _init_inventory(self):
85
        return self.rev_store.init_inventory(self.revision_id)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
86
87
    def get_inventory(self, revision_id):
88
        """Get the inventory for a revision id."""
89
        try:
90
            inv = self.cache_mgr.inventories[revision_id]
91
        except KeyError:
92
            if self.verbose:
93
                self.note("get_inventory cache miss for %s", revision_id)
94
            # Not cached so reconstruct from the RevisionStore
95
            inv = self.rev_store.get_inventory(revision_id)
96
            self.cache_mgr.inventories[revision_id] = inv
97
        return inv
98
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
99
    def _get_lines(self, file_id):
100
        """Get the lines for a file-id."""
101
        return self.lines_for_commit[file_id]
102
103
    def _get_inventories(self, revision_ids):
104
        """Get the inventories for revision-ids.
105
        
106
        This is a callback used by the RepositoryStore to
107
        speed up inventory reconstruction.
108
        """
109
        present = []
110
        inventories = []
111
        # If an inventory is in the cache, we assume it was
112
        # successfully loaded into the revision store
113
        for revision_id in revision_ids:
114
            try:
115
                inv = self.cache_mgr.inventories[revision_id]
116
                present.append(revision_id)
117
            except KeyError:
118
                if self.verbose:
119
                    self.note("get_inventories cache miss for %s", revision_id)
120
                # Not cached so reconstruct from the revision store
121
                try:
122
                    inv = self.get_inventory(revision_id)
123
                    present.append(revision_id)
124
                except:
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
125
                    inv = self._init_inventory()
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
126
                self.cache_mgr.inventories[revision_id] = inv
127
            inventories.append(inv)
128
        return present, inventories
129
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
130
    def bzr_file_id_and_new(self, path):
131
        """Get a Bazaar file identifier and new flag for a path.
132
        
133
        :return: file_id, is_new where
134
          is_new = True if the file_id is newly created
135
        """
136
        try:
137
            id = self.cache_mgr.file_ids[path]
138
            return id, False
139
        except KeyError:
140
            id = generate_ids.gen_file_id(path)
141
            self.cache_mgr.file_ids[path] = id
142
            self.debug("Generated new file id %s for '%s'", id, path)
143
            return id, True
144
145
    def bzr_file_id(self, path):
146
        """Get a Bazaar file identifier for a path."""
147
        return self.bzr_file_id_and_new(path)[0]
148
149
    def gen_revision_id(self):
150
        """Generate a revision id.
151
152
        Subclasses may override this to produce deterministic ids say.
153
        """
154
        committer = self.command.committer
155
        # Perhaps 'who' being the person running the import is ok? If so,
156
        # it might be a bit quicker and give slightly better compression?
157
        who = "%s <%s>" % (committer[0],committer[1])
158
        timestamp = committer[2]
159
        return generate_ids.gen_revision_id(who, timestamp)
160
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
161
    def build_revision(self):
162
        rev_props = {}
163
        committer = self.command.committer
164
        who = "%s <%s>" % (committer[0],committer[1])
165
        author = self.command.author
166
        if author is not None:
167
            author_id = "%s <%s>" % (author[0],author[1])
168
            if author_id != who:
169
                rev_props['author'] = author_id
170
        return revision.Revision(
171
           timestamp=committer[2],
172
           timezone=committer[3],
173
           committer=who,
174
           message=helpers.escape_commit_message(self.command.message),
175
           revision_id=self.revision_id,
176
           properties=rev_props,
177
           parent_ids=self.parents)
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
178
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
179
    def _modify_item(self, path, kind, is_executable, data, inv):
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
180
        """Add to or change an item in the inventory."""
181
        # Create the new InventoryEntry
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
182
        basename, parent_id = self._ensure_directory(path, inv)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
183
        file_id = self.bzr_file_id(path)
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
184
        ie = inventory.make_entry(kind, basename, parent_id, file_id)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
185
        ie.revision = self.revision_id
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
186
        if kind == 'file':
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
187
            ie.executable = is_executable
188
            lines = osutils.split_lines(data)
189
            ie.text_sha1 = osutils.sha_strings(lines)
190
            ie.text_size = sum(map(len, lines))
191
            self.lines_for_commit[file_id] = lines
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
192
        elif kind == 'symlink':
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
193
            ie.symlink_target = data.encode('utf8')
194
            # There are no lines stored for a symlink so
195
            # make sure the cache used by get_lines knows that
196
            self.lines_for_commit[file_id] = []
197
        else:
198
            raise errors.BzrError("Cannot import items of kind '%s' yet" %
199
                (kind,))
200
        # Record it
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
201
        if file_id in inv:
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
202
            old_ie = inv[file_id]
203
            if old_ie.kind == 'directory':
204
                self.record_delete(path, old_ie)
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
205
            self.record_changed(path, ie, parent_id)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
206
        else:
207
            self.record_new(path, ie)
208
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
209
    def _ensure_directory(self, path, inv):
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
210
        """Ensure that the containing directory exists for 'path'"""
211
        dirname, basename = osutils.split(path)
212
        if dirname == '':
213
            # the root node doesn't get updated
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
214
            return basename, self.inventory_root_id
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
215
        try:
216
            ie = self.directory_entries[dirname]
217
        except KeyError:
218
            # We will create this entry, since it doesn't exist
219
            pass
220
        else:
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
221
            return basename, ie.file_id
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
222
223
        # No directory existed, we will just create one, first, make sure
224
        # the parent exists
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
225
        dir_basename, parent_id = self._ensure_directory(dirname, inv)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
226
        dir_file_id = self.bzr_file_id(dirname)
227
        ie = inventory.entry_factory['directory'](dir_file_id,
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
228
            dir_basename, parent_id)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
229
        ie.revision = self.revision_id
230
        self.directory_entries[dirname] = ie
231
        # There are no lines stored for a directory so
232
        # make sure the cache used by get_lines knows that
233
        self.lines_for_commit[dir_file_id] = []
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
234
235
        # It's possible that a file or symlink with that file-id
236
        # already exists. If it does, we need to delete it.
237
        if dir_file_id in inv:
238
            self.record_delete(dirname, ie)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
239
        self.record_new(dirname, ie)
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
240
        return basename, ie.file_id
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
241
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
242
    def _delete_item(self, path, inv):
243
        file_id = inv.path2id(path)
244
        ie = inv[file_id]
0.81.9 by Ian Clatworthy
refactor delete_item
245
        self.record_delete(path, ie)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
246
247
    def _copy_item(self, src_path, dest_path, inv):
248
        if not self.parents:
249
            self.warning("ignoring copy of %s to %s - no parent revisions",
250
                src_path, dest_path)
251
            return
252
        file_id = inv.path2id(src_path)
253
        if file_id is None:
254
            self.warning("ignoring copy of %s to %s - source does not exist",
255
                src_path, dest_path)
256
            return
257
        ie = inv[file_id]
258
        kind = ie.kind
259
        if kind == 'file':
260
            content = self.rev_store.get_file_text(self.parents[0], file_id)
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
261
            self._modify_item(dest_path, kind, ie.executable, content, inv)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
262
        elif kind == 'symlink':
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
263
            self._modify_item(dest_path, kind, False, ie.symlink_target, inv)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
264
        else:
265
            self.warning("ignoring copy of %s %s - feature not yet supported",
266
                kind, path)
267
268
    def _rename_item(self, old_path, new_path, inv):
0.81.8 by Ian Clatworthy
refactor rename_item
269
        file_id = inv.path2id(old_path)
270
        ie = inv[file_id]
271
        rev_id = ie.revision
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
272
        new_file_id = inv.path2id(new_path)
273
        if new_file_id is not None:
0.81.9 by Ian Clatworthy
refactor delete_item
274
            self.record_delete(new_path, inv[new_file_id])
0.81.8 by Ian Clatworthy
refactor rename_item
275
        self.record_rename(old_path, new_path, file_id, ie)
276
        self.cache_mgr.rename_path(old_path, new_path)
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
277
0.81.8 by Ian Clatworthy
refactor rename_item
278
        # The revision-id for this entry will be/has been updated and
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
279
        # that means the loader then needs to know what the "new" text is.
280
        # We therefore must go back to the revision store to get it.
0.81.8 by Ian Clatworthy
refactor rename_item
281
        lines = self.rev_store.get_file_lines(rev_id, file_id)
282
        self.lines_for_commit[file_id] = lines
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
283
284
    def _delete_all_items(self, inv):
285
        for name, root_item in inv.root.children.iteritems():
286
            inv.remove_recursive_id(root_item.file_id)
287
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
288
289
class InventoryCommitHandler(GenericCommitHandler):
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
290
    """A CommitHandler that builds and saves full inventories."""
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
291
292
    def pre_process_files(self):
293
        super(InventoryCommitHandler, self).pre_process_files()
294
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
295
        # Seed the inventory from the previous one
296
        if len(self.parents) == 0:
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
297
            self.inventory = self.basis_inventory
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
298
        else:
0.84.3 by Ian Clatworthy
fix inventory copying when using deltas
299
            self.inventory = copy_inventory(self.basis_inventory)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
300
        self.inventory_root = self.inventory.root
301
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
302
        # directory-path -> inventory-entry for current inventory
303
        self.directory_entries = dict(self.inventory.directories())
304
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
305
        # Initialise the inventory revision info as required
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
306
        if self.rev_store.expects_rich_root():
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
307
            self.inventory.revision_id = self.revision_id
308
        else:
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
309
            # In this revision store, root entries have no knit or weave.
310
            # When serializing out to disk and back in, root.revision is
311
            # always the new revision_id.
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
312
            self.inventory.root.revision = self.revision_id
313
314
    def post_process_files(self):
315
        """Save the revision."""
316
        self.cache_mgr.inventories[self.revision_id] = self.inventory
0.81.2 by Ian Clatworthy
refactor InventoryCommitHandler general stuff into parent class
317
        rev = self.build_revision()
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
318
        self.rev_store.load(rev, self.inventory, None,
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
319
            lambda file_id: self._get_lines(file_id),
320
            lambda revision_ids: self._get_inventories(revision_ids))
321
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
322
    def record_new(self, path, ie):
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
323
        try:
324
            self.inventory.add(ie)
325
        except errors.DuplicateFileId:
326
            # Directory already exists as a file or symlink
327
            del self.inventory[ie.file_id]
328
            # Try again
329
            self.inventory.add(ie)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
330
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
331
    def record_changed(self, path, ie, parent_id):
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
332
        # HACK: no API for this (del+add does more than it needs to)
333
        self.inventory._byid[ie.file_id] = ie
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
334
        parent_ie = self.inventory._byid[parent_id]
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
335
        parent_ie.children[ie.name] = ie
336
0.81.9 by Ian Clatworthy
refactor delete_item
337
    def record_delete(self, path, ie):
338
        self.inventory.remove_recursive_id(ie.file_id)
0.81.8 by Ian Clatworthy
refactor rename_item
339
340
    def record_rename(self, old_path, new_path, file_id, ie):
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
341
        new_basename, new_parent_id = self._ensure_directory(new_path,
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
342
            self.inventory)
0.81.8 by Ian Clatworthy
refactor rename_item
343
        self.inventory.rename(file_id, new_parent_id, new_basename)
344
        self.inventory[file_id].revision = self.revision_id
345
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
346
    def _delete_item(self, path):
347
        # NOTE: I'm retaining this method for now, instead of using the
348
        # one in the superclass, because it's taken quite a lot of tweaking
349
        # to cover all the edge cases seen in the wild. Long term, it can
350
        # probably go once the higher level method does "warn_unless_in_merges"
351
        # and handles all the various special cases ...
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
352
        fileid = self.bzr_file_id(path)
353
        dirname, basename = osutils.split(path)
354
        if (fileid in self.inventory and
355
            isinstance(self.inventory[fileid], inventory.InventoryDirectory)):
356
            for child_path in self.inventory[fileid].children.keys():
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
357
                self._delete_item(osutils.pathjoin(path, child_path))
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
358
        try:
359
            if self.inventory.id2path(fileid) == path:
360
                del self.inventory[fileid]
361
            else:
362
                # already added by some other name?
363
                if dirname in self.cache_mgr.file_ids:
364
                    parent_id = self.cache_mgr.file_ids[dirname]
365
                    del self.inventory[parent_id].children[basename]
366
        except KeyError:
367
            self._warn_unless_in_merges(fileid, path)
368
        except errors.NoSuchId:
369
            self._warn_unless_in_merges(fileid, path)
370
        except AttributeError, ex:
371
            if ex.args[0] == 'children':
372
                # A directory has changed into a file and then one
373
                # of it's children is being deleted!
374
                self._warn_unless_in_merges(fileid, path)
375
            else:
376
                raise
377
        try:
378
            self.cache_mgr.delete_path(path)
379
        except KeyError:
380
            pass
381
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
382
    def _warn_unless_in_merges(self, fileid, path):
383
        if len(self.parents) <= 1:
384
            return
385
        for parent in self.parents[1:]:
386
            if fileid in self.get_inventory(parent):
387
                return
388
        self.warning("ignoring delete of %s as not in parent inventories", path)
389
390
    def modify_handler(self, filecmd):
391
        if filecmd.dataref is not None:
392
            data = self.cache_mgr.fetch_blob(filecmd.dataref)
393
        else:
394
            data = filecmd.data
395
        self.debug("modifying %s", filecmd.path)
396
        self._modify_item(filecmd.path, filecmd.kind,
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
397
            filecmd.is_executable, data, self.inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
398
399
    def delete_handler(self, filecmd):
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
400
        self.debug("deleting %s", filecmd.path)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
401
        self._delete_item(filecmd.path)
402
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
403
    def copy_handler(self, filecmd):
404
        src_path = filecmd.src_path
405
        dest_path = filecmd.dest_path
406
        self.debug("copying %s to %s", src_path, dest_path)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
407
        self._copy_item(src_path, dest_path, self.inventory)
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
408
409
    def rename_handler(self, filecmd):
410
        old_path = filecmd.old_path
411
        new_path = filecmd.new_path
412
        self.debug("renaming %s to %s", old_path, new_path)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
413
        self._rename_item(old_path, new_path, self.inventory)
0.81.1 by Ian Clatworthy
move GenericCommitHandler into its own module in prep for a delta-based one
414
415
    def deleteall_handler(self, filecmd):
416
        self.debug("deleting all files (and also all directories)")
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
417
        self._delete_all_items(self.inventory)
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
418
419
420
class DeltaCommitHandler(GenericCommitHandler):
421
    """A CommitHandler that builds and saves inventory deltas."""
422
423
    def pre_process_files(self):
424
        super(DeltaCommitHandler, self).pre_process_files()
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
425
        if self.parents:
426
            self.delta = []
427
        else:
428
            # Need to explicitly add the root entry for the first revision
429
            root_id = inventory.ROOT_ID
430
            # XXX: We *could* make this a CHKInventoryDirectory but it
431
            # seems that deltas ought to use normal InventoryDirectory's
432
            # because they simply don't know the chk_inventory that they
433
            # are about to become a part of.
434
            root_ie = inventory.InventoryDirectory(root_id, u'', None)
435
            root_ie.revision = self.revision_id
436
            self.delta = [(None, '', root_id, root_ie)]
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
437
438
    def post_process_files(self):
439
        """Save the revision."""
440
        rev = self.build_revision()
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
441
        inv = self.rev_store.chk_load(rev, self.basis_inventory,
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
442
            self.delta, None,
443
            lambda file_id: self._get_lines(file_id),
444
            lambda revision_ids: self._get_inventories(revision_ids))
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
445
        self.cache_mgr.inventories[self.revision_id] = inv
446
447
    def record_new(self, path, ie):
448
        self.delta.append((None, path, ie.file_id, ie))
449
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
450
    def record_changed(self, path, ie, parent_id=None):
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
451
        self.delta.append((path, path, ie.file_id, ie))
452
0.81.9 by Ian Clatworthy
refactor delete_item
453
    def record_delete(self, path, ie):
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
454
        self.delta.append((path, None, ie.file_id, None))
455
        if ie.kind == 'directory':
456
            for child_path, entry in \
457
                self.basis_inventory.iter_entries_by_dir(from_dir=ie):
458
                #print "deleting child %s" % child_path
459
                self.delta.append((child_path, None, entry.file_id, None))
0.81.8 by Ian Clatworthy
refactor rename_item
460
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
461
    def record_rename(self, old_path, new_path, file_id, old_ie):
462
        new_ie = old_ie.copy()
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
463
        new_basename, new_parent_id = self._ensure_directory(new_path,
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
464
            self.basis_inventory)
465
        new_ie.name = new_basename
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
466
        new_ie.parent_id = new_parent_id
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
467
        new_ie.revision = self.revision_id
468
        self.delta.append((old_path, new_path, file_id, new_ie))
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
469
470
    def modify_handler(self, filecmd):
471
        if filecmd.dataref is not None:
472
            data = self.cache_mgr.fetch_blob(filecmd.dataref)
473
        else:
474
            data = filecmd.data
475
        self.debug("modifying %s", filecmd.path)
476
        self._modify_item(filecmd.path, filecmd.kind,
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
477
            filecmd.is_executable, data, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
478
479
    def delete_handler(self, filecmd):
480
        self.debug("deleting %s", filecmd.path)
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
481
        self._delete_item(filecmd.path, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
482
483
    def copy_handler(self, filecmd):
484
        src_path = filecmd.src_path
485
        dest_path = filecmd.dest_path
486
        self.debug("copying %s to %s", src_path, dest_path)
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
487
        self._copy_item(src_path, dest_path, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
488
489
    def rename_handler(self, filecmd):
490
        old_path = filecmd.old_path
491
        new_path = filecmd.new_path
492
        self.debug("renaming %s to %s", old_path, new_path)
493
        self._rename_item(old_path, new_path, self.basis_inventory)
494
495
    def deleteall_handler(self, filecmd):
496
        self.debug("deleting all files (and also all directories)")
497
        # I'm not 100% sure this will work in the delta case.
498
        # But clearing out the basis inventory so that everything
499
        # is added sounds ok in theory ...
500
        # We grab a copy as the basis is likely to be cached and
501
        # we don't want to destroy the cached version
0.84.3 by Ian Clatworthy
fix inventory copying when using deltas
502
        self.basis_inventory = copy_inventory(self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
503
        self._delete_all_items(self.basis_inventory)