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