/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.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
290
    """A CommitHandler that builds and saves Inventory objects."""
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
0.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
420
class CHKInventoryCommitHandler(GenericCommitHandler):
421
    """A CommitHandler that builds and saves CHKInventory objects."""
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
422
423
    def pre_process_files(self):
0.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
424
        super(CHKInventoryCommitHandler, self).pre_process_files()
425
        if len(self.parents) == 0 or not self.rev_store.expects_rich_root():
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
426
            # Need to explicitly add the root entry for the first revision
0.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
427
            # and for non rich-root inventories
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
428
            root_id = inventory.ROOT_ID
429
            # XXX: We *could* make this a CHKInventoryDirectory but it
430
            # seems that deltas ought to use normal InventoryDirectory's
431
            # because they simply don't know the chk_inventory that they
432
            # are about to become a part of.
433
            root_ie = inventory.InventoryDirectory(root_id, u'', None)
434
            root_ie.revision = self.revision_id
435
            self.delta = [(None, '', root_id, root_ie)]
0.84.7 by Ian Clatworthy
CHKInventory support for non rich-root repos working, for simple imports at least
436
        else:
437
            self.delta = []
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
438
439
    def post_process_files(self):
440
        """Save the revision."""
441
        rev = self.build_revision()
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
442
        inv = self.rev_store.chk_load(rev, self.basis_inventory,
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
443
            self.delta, None,
444
            lambda file_id: self._get_lines(file_id),
445
            lambda revision_ids: self._get_inventories(revision_ids))
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
446
        self.cache_mgr.inventories[self.revision_id] = inv
447
448
    def record_new(self, path, ie):
449
        self.delta.append((None, path, ie.file_id, ie))
450
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
451
    def record_changed(self, path, ie, parent_id=None):
0.81.5 by Ian Clatworthy
basic DeltaCommitHandler generating deltas
452
        self.delta.append((path, path, ie.file_id, ie))
453
0.81.9 by Ian Clatworthy
refactor delete_item
454
    def record_delete(self, path, ie):
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
455
        self.delta.append((path, None, ie.file_id, None))
456
        if ie.kind == 'directory':
457
            for child_path, entry in \
458
                self.basis_inventory.iter_entries_by_dir(from_dir=ie):
459
                #print "deleting child %s" % child_path
460
                self.delta.append((child_path, None, entry.file_id, None))
0.81.8 by Ian Clatworthy
refactor rename_item
461
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
462
    def record_rename(self, old_path, new_path, file_id, old_ie):
463
        new_ie = old_ie.copy()
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
464
        new_basename, new_parent_id = self._ensure_directory(new_path,
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
465
            self.basis_inventory)
466
        new_ie.name = new_basename
0.84.5 by Ian Clatworthy
_ensure_directory to return parent_id, not parent_ie
467
        new_ie.parent_id = new_parent_id
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
468
        new_ie.revision = self.revision_id
469
        self.delta.append((old_path, new_path, file_id, new_ie))
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
470
471
    def modify_handler(self, filecmd):
472
        if filecmd.dataref is not None:
473
            data = self.cache_mgr.fetch_blob(filecmd.dataref)
474
        else:
475
            data = filecmd.data
476
        self.debug("modifying %s", filecmd.path)
477
        self._modify_item(filecmd.path, filecmd.kind,
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
478
            filecmd.is_executable, data, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
479
480
    def delete_handler(self, filecmd):
481
        self.debug("deleting %s", filecmd.path)
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
482
        self._delete_item(filecmd.path, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
483
484
    def copy_handler(self, filecmd):
485
        src_path = filecmd.src_path
486
        dest_path = filecmd.dest_path
487
        self.debug("copying %s to %s", src_path, dest_path)
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
488
        self._copy_item(src_path, dest_path, self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
489
490
    def rename_handler(self, filecmd):
491
        old_path = filecmd.old_path
492
        new_path = filecmd.new_path
493
        self.debug("renaming %s to %s", old_path, new_path)
494
        self._rename_item(old_path, new_path, self.basis_inventory)
495
496
    def deleteall_handler(self, filecmd):
497
        self.debug("deleting all files (and also all directories)")
498
        # I'm not 100% sure this will work in the delta case.
499
        # But clearing out the basis inventory so that everything
500
        # is added sounds ok in theory ...
501
        # We grab a copy as the basis is likely to be cached and
502
        # we don't want to destroy the cached version
0.84.3 by Ian Clatworthy
fix inventory copying when using deltas
503
        self.basis_inventory = copy_inventory(self.basis_inventory)
0.81.6 by Ian Clatworthy
basic DeltaCommitHandler mostly going bar rename
504
        self._delete_all_items(self.basis_inventory)