/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
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
"""Import processor that supports all Bazaar repository formats."""
18
19
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
20
import re
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
21
import time
0.64.5 by Ian Clatworthy
first cut at generic processing method
22
from bzrlib import (
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
23
    delta,
0.64.5 by Ian Clatworthy
first cut at generic processing method
24
    errors,
25
    generate_ids,
26
    inventory,
27
    lru_cache,
28
    osutils,
29
    revision,
30
    revisiontree,
31
    )
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
32
from bzrlib.trace import (
33
    note,
34
    warning,
35
    )
0.64.5 by Ian Clatworthy
first cut at generic processing method
36
from bzrlib.plugins.fastimport import (
37
    processor,
38
    revisionloader,
39
    )
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
40
41
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
42
def _single_plural(n, single, plural):
43
    """Return a single or plural form of a noun based on number."""
44
    if n == 1:
45
        return single
46
    else:
47
        return plural
48
49
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
50
class GenericProcessor(processor.ImportProcessor):
51
    """An import processor that handles basic imports.
52
53
    Current features supported:
54
0.64.5 by Ian Clatworthy
first cut at generic processing method
55
    * timestamped progress reporting
0.64.16 by Ian Clatworthy
safe processing tweaks
56
    * blobs are cached in memory
57
    * commits are processed
58
    * tags are stored in the current branch
59
    * LATER: named branch support
60
    * checkpoints are ignored
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
61
    * some basic statistics are dumped on completion.
62
    """
63
64
    def pre_process(self):
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
65
        self.cache_mgr = GenericCacheManager()
0.64.7 by Ian Clatworthy
start of multiple commit handling
66
        self.active_branch = self.branch
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
67
        self.init_stats()
0.64.11 by Ian Clatworthy
tag support
68
        # mapping of tag name to revision_id
69
        self.tags = {}
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
70
71
    def post_process(self):
72
        self.dump_stats()
0.64.7 by Ian Clatworthy
start of multiple commit handling
73
        # Update the branches, assuming the last revision is the head
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
74
        note("Updating branch information ...")
0.64.7 by Ian Clatworthy
start of multiple commit handling
75
        # TODO - loop over the branches created/modified
76
        last_rev_id = self.cache_mgr.last_revision_ids[self.branch]
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
77
        revno = len(list(self.repo.iter_reverse_revision_history(last_rev_id)))
78
        self.branch.set_last_revision_info(revno, last_rev_id)
0.64.11 by Ian Clatworthy
tag support
79
        if self.tags:
80
            self.branch.tags._set_tag_dict(self.tags)
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
81
        # Update the working tree, if any
82
        if self.working_tree:
83
            self.working_tree.update(delta._ChangeReporter())
84
85
    def init_stats(self):
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
86
        self._revision_count = 0
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
87
        self._branch_count = 1
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
88
        self._tag_count = 0
0.64.5 by Ian Clatworthy
first cut at generic processing method
89
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
90
    def dump_stats(self):
91
        rc = self._revision_count
92
        bc = self._branch_count
93
        tc = self._tag_count
94
        note("Imported %d %s into %d %s with %d %s.",
95
            rc, _single_plural(rc, "revision", "revisions"),
96
            bc, _single_plural(bc, "branch", "branches"),
97
            tc, _single_plural(tc, "tag", "tags"))
0.64.5 by Ian Clatworthy
first cut at generic processing method
98
99
    def blob_handler(self, cmd):
100
        """Process a BlobCommand."""
101
        if cmd.mark is not None:
102
            dataref = ":%s" % (cmd.mark,)
103
        else:
104
            dataref = osutils.sha_strings(cmd.data)
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
105
        self.cache_mgr.blobs[dataref] = cmd.data
0.64.5 by Ian Clatworthy
first cut at generic processing method
106
107
    def checkpoint_handler(self, cmd):
108
        """Process a CheckpointCommand."""
109
        warning("ignoring checkpoint")
110
111
    def commit_handler(self, cmd):
112
        """Process a CommitCommand."""
0.64.7 by Ian Clatworthy
start of multiple commit handling
113
        handler = GenericCommitHandler(cmd, self.repo, self.cache_mgr,
0.64.14 by Ian Clatworthy
commit of modified files working
114
            self.active_branch, self.verbose)
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
115
        # For now, put a write group around every commit. In the future,
116
        # we might only start/commit one every N to sppeed things up
117
        self.repo.start_write_group()
118
        try:
119
            handler.process()
0.64.16 by Ian Clatworthy
safe processing tweaks
120
            rev_id = handler.revision_id
121
            self.cache_mgr.revision_ids[cmd.ref] = rev_id
122
            if cmd.mark is not None:
123
                self.cache_mgr.revision_ids[":" + cmd.mark] = rev_id
124
            self.cache_mgr.last_revision_ids[self.active_branch] = rev_id
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
125
            self._revision_count += 1
0.64.18 by Ian Clatworthy
timestamp loaded commit messages
126
            note("%s loaded commit %d (%s)" % (self._time_of_day(),
127
                self._revision_count, cmd.mark or cmd.ref))
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
128
        except:
129
            self.repo.abort_write_group()
130
            raise
131
        else:
132
            self.repo.commit_write_group()
0.64.1 by Ian Clatworthy
1st cut: gfi parser + --info processing method
133
134
    def progress_handler(self, cmd):
135
        """Process a ProgressCommand."""
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
136
        # We could use a progress bar here but timestamped messages
137
        # is more useful for determining when things might complete
0.64.5 by Ian Clatworthy
first cut at generic processing method
138
        note("%s progress %s" % (self._time_of_day(), cmd.message))
139
140
    def _time_of_day(self):
141
        """Time of day as a string."""
142
        # Note: this is a separate method so tests can patch in a fixed value
0.64.18 by Ian Clatworthy
timestamp loaded commit messages
143
        return time.strftime("%H:%M:%S")
0.64.5 by Ian Clatworthy
first cut at generic processing method
144
145
    def reset_handler(self, cmd):
146
        """Process a ResetCommand."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
147
        if cmd.ref.startswith('refs/tags/'):
148
            self._set_tag(cmd.ref[len('refs/tags/'):], cmd.from_)
149
        else:
0.64.16 by Ian Clatworthy
safe processing tweaks
150
            warning("named branches are not supported yet"
151
                " - ignoring reset of '%s'", cmd.ref)
0.64.5 by Ian Clatworthy
first cut at generic processing method
152
153
    def tag_handler(self, cmd):
154
        """Process a TagCommand."""
0.64.12 by Ian Clatworthy
lightweight tags, filter processor and param validation
155
        self._set_tag(cmd.id, cmd.from_)
156
157
    def _set_tag(self, name, from_):
158
        """Define a tag given a name an import 'from' reference."""
159
        bzr_tag_name = name.decode('utf-8', 'replace')
160
        bzr_rev_id = self.cache_mgr.revision_ids[from_]
0.64.11 by Ian Clatworthy
tag support
161
        self.tags[bzr_tag_name] = bzr_rev_id
162
        self._tag_count += 1
0.64.5 by Ian Clatworthy
first cut at generic processing method
163
164
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
165
class GenericCacheManager(object):
166
    """A manager of caches for the GenericProcessor."""
167
168
    def __init__(self, inventory_cache_size=100):
169
        # dataref -> data. datref is either :mark or the sha-1.
170
        self.blobs = {}
171
172
        # revision-id -> Inventory cache
173
        # these are large and we probably don't need too many as
174
        # most parents are recent in history
175
        self.inventories = lru_cache.LRUCache(inventory_cache_size)
176
177
        # import-ref -> revision-id lookup table
178
        # we need to keep all of these but they are small
179
        self.revision_ids = {}
180
0.64.7 by Ian Clatworthy
start of multiple commit handling
181
        # branch -> last revision-id lookup table
182
        self.last_revision_ids = {}
183
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
184
        # path -> file-ids - as generated
0.64.14 by Ian Clatworthy
commit of modified files working
185
        self.file_ids = {}
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
186
0.64.16 by Ian Clatworthy
safe processing tweaks
187
    def _delete_path(self, path):
188
        """Remove a path from caches."""
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
189
        # we actually want to remember what file-id we gave a path,
190
        # even when that file is deleted, so doing nothing is correct
191
        pass
0.64.16 by Ian Clatworthy
safe processing tweaks
192
193
    def _rename_path(self, old_path, new_path):
194
        """Rename a path in the caches."""
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
195
        # we actually want to remember what file-id we gave a path,
196
        # even when that file is renamed, so both paths should have
197
        # the same value and we don't delete any information
0.64.16 by Ian Clatworthy
safe processing tweaks
198
        self.file_ids[new_path] = self.file_ids[old_path]
199
200
0.64.5 by Ian Clatworthy
first cut at generic processing method
201
class GenericCommitHandler(processor.CommitHandler):
202
0.64.14 by Ian Clatworthy
commit of modified files working
203
    def __init__(self, command, repo, cache_mgr, active_branch, verbose=False):
0.64.5 by Ian Clatworthy
first cut at generic processing method
204
        processor.CommitHandler.__init__(self, command)
205
        self.repo = repo
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
206
        self.cache_mgr = cache_mgr
0.64.7 by Ian Clatworthy
start of multiple commit handling
207
        self.active_branch = active_branch
0.64.14 by Ian Clatworthy
commit of modified files working
208
        self.verbose = verbose
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
209
        # smart loader that uses these caches
0.64.5 by Ian Clatworthy
first cut at generic processing method
210
        self.loader = revisionloader.RevisionLoader(repo,
211
            lambda revision_ids: self._get_inventories(revision_ids))
212
213
    def pre_process_files(self):
214
        """Prepare for committing."""
215
        self.revision_id = self.gen_revision_id()
216
        self.inv_delta = []
217
        # cache of texts for this commit, indexed by file-id
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
218
        self.lines_for_commit = {}
0.64.5 by Ian Clatworthy
first cut at generic processing method
219
0.64.14 by Ian Clatworthy
commit of modified files working
220
        # Get the parent inventories
0.64.7 by Ian Clatworthy
start of multiple commit handling
221
        if self.command.parents:
0.64.14 by Ian Clatworthy
commit of modified files working
222
            self.parents = [self.cache_mgr.revision_ids[ref]
0.64.7 by Ian Clatworthy
start of multiple commit handling
223
                for ref in self.command.parents]
224
        else:
225
            # if no parents are given, the last revision on
226
            # the current branch is assumed according to the spec
227
            last_rev = self.cache_mgr.last_revision_ids.get(
228
                    self.active_branch)
229
            if last_rev:
0.64.14 by Ian Clatworthy
commit of modified files working
230
                self.parents = [last_rev]
0.64.7 by Ian Clatworthy
start of multiple commit handling
231
            else:
0.64.14 by Ian Clatworthy
commit of modified files working
232
                self.parents = []
0.64.7 by Ian Clatworthy
start of multiple commit handling
233
0.64.14 by Ian Clatworthy
commit of modified files working
234
        # Seed the inventory from the previous one
235
        if len(self.parents) == 0:
236
            self.inventory = self.gen_initial_inventory()
0.64.5 by Ian Clatworthy
first cut at generic processing method
237
        else:
238
            # use the bzr_revision_id to lookup the inv cache
0.64.14 by Ian Clatworthy
commit of modified files working
239
            self.inventory = self.get_inventory(self.parents[0]).copy()
0.64.13 by Ian Clatworthy
commit of new files working
240
        if not self.repo.supports_rich_root():
241
            # In this repository, root entries have no knit or weave. When
242
            # serializing out to disk and back in, root.revision is always
243
            # the new revision_id.
0.64.14 by Ian Clatworthy
commit of modified files working
244
            self.inventory.root.revision = self.revision_id
0.64.5 by Ian Clatworthy
first cut at generic processing method
245
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
246
        # directory-path -> inventory-entry for current inventory
247
        self.directory_entries = dict(self.inventory.directories())
248
0.64.14 by Ian Clatworthy
commit of modified files working
249
    def post_process_files(self):
250
        """Save the revision."""
251
        if self.verbose:
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
252
            note("applying inventory delta ...")
0.64.14 by Ian Clatworthy
commit of modified files working
253
            for entry in self.inv_delta:
0.64.16 by Ian Clatworthy
safe processing tweaks
254
                note("  %r" % (entry,))
0.64.14 by Ian Clatworthy
commit of modified files working
255
        self.inventory.apply_delta(self.inv_delta)
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
256
        self.cache_mgr.inventories[self.revision_id] = self.inventory
0.64.14 by Ian Clatworthy
commit of modified files working
257
        if self.verbose:
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
258
            note("created inventory ...")
0.64.14 by Ian Clatworthy
commit of modified files working
259
            for entry in self.inventory:
0.64.16 by Ian Clatworthy
safe processing tweaks
260
                note("  %r" % (entry,))
0.64.5 by Ian Clatworthy
first cut at generic processing method
261
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
262
        # Load the revision into the repository
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
263
        rev_props = {}
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
264
        committer = self.command.committer
265
        who = "%s <%s>" % (committer[0],committer[1])
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
266
        author = self.command.author
267
        if author is not None:
268
            author_id = "%s <%s>" % (author[0],author[1])
269
            if author_id != who:
270
                rev_props['author'] = author_id
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
271
        rev = revision.Revision(
272
           timestamp=committer[2],
273
           timezone=committer[3],
274
           committer=who,
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
275
           message=self._escape_commit_message(self.command.message),
276
           revision_id=self.revision_id,
277
           properties=rev_props,
278
           parent_ids=self.parents)
0.64.14 by Ian Clatworthy
commit of modified files working
279
        self.loader.load(rev, self.inventory, None,
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
280
            lambda file_id: self._get_lines(file_id))
281
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
282
    def _escape_commit_message(self, message):
283
        """Replace xml-incompatible control characters."""
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
284
        # It's crap that we need to do this at this level (but we do)
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
285
        # Code copied from bzrlib.commit.
286
        
287
        # Python strings can include characters that can't be
288
        # represented in well-formed XML; escape characters that
289
        # aren't listed in the XML specification
290
        # (http://www.w3.org/TR/REC-xml/#NT-Char).
291
        message, _ = re.subn(
292
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
293
            lambda match: match.group(0).encode('unicode_escape'),
294
            message)
295
        return message
0.64.5 by Ian Clatworthy
first cut at generic processing method
296
297
    def modify_handler(self, filecmd):
298
        if filecmd.dataref is not None:
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
299
            data = self.cache_mgr.blobs[filecmd.dataref]
0.64.16 by Ian Clatworthy
safe processing tweaks
300
            ## Conserve memory, assuming blobs aren't referenced twice
301
            #del self.cache_mgr.blobs[filecmd.dataref]
0.64.5 by Ian Clatworthy
first cut at generic processing method
302
        else:
303
            data = filecmd.data
304
        self._modify_inventory(filecmd.path, filecmd.kind,
305
            filecmd.is_executable, data)
306
307
    def delete_handler(self, filecmd):
308
        path = filecmd.path
0.64.21 by Ian Clatworthy
fix one inventory lookup bug
309
        try:
310
            del self.inventory[self.bzr_file_id(path)]
311
        except errors.NoSuchId:
312
            warning("ignoring delete of %s - not in inventory" % (path,))
313
        finally:
314
            try:
315
                self.cache_mgr._delete_path(path)
316
            except KeyError:
317
                pass
0.64.5 by Ian Clatworthy
first cut at generic processing method
318
319
    def copy_handler(self, filecmd):
320
        raise NotImplementedError(self.copy_handler)
321
322
    def rename_handler(self, filecmd):
0.64.16 by Ian Clatworthy
safe processing tweaks
323
        old_path = filecmd.old_path
324
        new_path = filecmd.new_path
325
        file_id = self.bzr_file_id(old_path)
326
        ie = self.inventory[file_id]
327
        self.inv_delta.append((old_path, new_path, file_id, ie))
328
        self.cache_mgr._rename_path(old_path, new_path)
0.64.5 by Ian Clatworthy
first cut at generic processing method
329
330
    def deleteall_handler(self, filecmd):
331
        raise NotImplementedError(self.deleteall_handler)
332
0.64.16 by Ian Clatworthy
safe processing tweaks
333
    def bzr_file_id_and_new(self, path):
334
        """Get a Bazaar file identifier and new flag for a path.
335
        
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
336
        :return: file_id, is_new where
337
          is_new = True if the file_id is newly created
0.64.16 by Ian Clatworthy
safe processing tweaks
338
        """
339
        try:
340
            return self.cache_mgr.file_ids[path], False
341
        except KeyError:
342
            id = generate_ids.gen_file_id(path)
343
            self.cache_mgr.file_ids[path] = id
344
            return id, True
345
0.64.5 by Ian Clatworthy
first cut at generic processing method
346
    def bzr_file_id(self, path):
0.64.14 by Ian Clatworthy
commit of modified files working
347
        """Get a Bazaar file identifier for a path."""
0.64.16 by Ian Clatworthy
safe processing tweaks
348
        return self.bzr_file_id_and_new(path)[0]
0.64.5 by Ian Clatworthy
first cut at generic processing method
349
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
350
    def gen_initial_inventory(self):
351
        """Generate an inventory for a parentless revision."""
352
        inv = inventory.Inventory(revision_id=self.revision_id)
353
        return inv
354
0.64.5 by Ian Clatworthy
first cut at generic processing method
355
    def gen_revision_id(self):
356
        """Generate a revision id.
357
358
        Subclasses may override this to produce deterministic ids say.
359
        """
360
        committer = self.command.committer
0.64.16 by Ian Clatworthy
safe processing tweaks
361
        # Perhaps 'who' being the person running the import is ok? If so,
362
        # it might be a bit quicker and give slightly better compression?
0.64.5 by Ian Clatworthy
first cut at generic processing method
363
        who = "%s <%s>" % (committer[0],committer[1])
364
        timestamp = committer[2]
365
        return generate_ids.gen_revision_id(who, timestamp)
366
0.64.7 by Ian Clatworthy
start of multiple commit handling
367
    def get_inventory(self, revision_id):
368
        """Get the inventory for a revision id."""
369
        try:
370
            inv = self.cache_mgr.inventories[revision_id]
371
        except KeyError:
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
372
            print "Hmm - get_inventory cache miss for %s" % revision_id
0.64.7 by Ian Clatworthy
start of multiple commit handling
373
            # Not cached so reconstruct from repository
374
            inv = self.repo.revision_tree(revision_id).inventory
375
            self.cache_mgr.inventories[revision_id] = inv
376
        return inv
377
0.64.5 by Ian Clatworthy
first cut at generic processing method
378
    def _get_inventories(self, revision_ids):
379
        """Get the inventories for revision-ids.
380
        
381
        This is a callback used by the RepositoryLoader to
382
        speed up inventory reconstruction."""
383
        present = []
384
        inventories = []
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
385
        # If an inventory is in the cache, we assume it was
0.64.5 by Ian Clatworthy
first cut at generic processing method
386
        # successfully loaded into the repsoitory
387
        for revision_id in revision_ids:
388
            try:
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
389
                inv = self.cache_mgr.inventories[revision_id]
0.64.5 by Ian Clatworthy
first cut at generic processing method
390
                present.append(revision_id)
391
            except KeyError:
0.64.17 by Ian Clatworthy
escape commit messages, diff author to committer and cache fixes
392
                print "Hmm - get_inventories cache miss for %s" % revision_id
0.64.5 by Ian Clatworthy
first cut at generic processing method
393
                # Not cached so reconstruct from repository
394
                if self.repo.has_revision(revision_id):
395
                    rev_tree = self.repo.revision_tree(revision_id)
396
                    present.append(revision_id)
397
                else:
398
                    rev_tree = self.repo.revision_tree(None)
399
                inv = rev_tree.inventory
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
400
                self.cache_mgr.inventories[revision_id] = inv
401
            inventories.append(inv)
0.64.5 by Ian Clatworthy
first cut at generic processing method
402
        return present, inventories
403
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
404
    def _get_lines(self, file_id):
405
        """Get the lines for a file-id."""
406
        return self.lines_for_commit[file_id]
0.64.5 by Ian Clatworthy
first cut at generic processing method
407
408
    def _modify_inventory(self, path, kind, is_executable, data):
409
        """Add to or change an item in the inventory."""
410
        # Create the new InventoryEntry
411
        basename, parent_ie = self._ensure_directory(path)
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
412
        file_id = self.bzr_file_id(path)
0.64.16 by Ian Clatworthy
safe processing tweaks
413
        ie = inventory.make_entry(kind, basename, parent_ie.file_id, file_id)
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
414
        ie.revision = self.revision_id
0.64.5 by Ian Clatworthy
first cut at generic processing method
415
        if isinstance(ie, inventory.InventoryFile):
416
            ie.executable = is_executable
0.64.13 by Ian Clatworthy
commit of new files working
417
            lines = osutils.split_lines(data)
418
            ie.text_sha1 = osutils.sha_strings(lines)
419
            ie.text_size = sum(map(len, lines))
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
420
            self.lines_for_commit[file_id] = lines
0.64.5 by Ian Clatworthy
first cut at generic processing method
421
        elif isinstance(ie, inventory.InventoryLnk):
422
            ie.symlink_target = data
423
        else:
424
            raise errors.BzrError("Cannot import items of kind '%s' yet" %
425
                (kind,))
426
0.64.16 by Ian Clatworthy
safe processing tweaks
427
        # Record this new inventory entry
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
428
        if file_id in self.inventory:
0.64.21 by Ian Clatworthy
fix one inventory lookup bug
429
            # HACK: no API for this (del+add does more than it needs to)
430
            self.inventory._byid[file_id] = ie
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
431
        else:
432
            self.inventory.add(ie)
0.64.5 by Ian Clatworthy
first cut at generic processing method
433
434
    def _ensure_directory(self, path):
435
        """Ensure that the containing directory exists for 'path'"""
436
        dirname, basename = osutils.split(path)
437
        if dirname == '':
438
            # the root node doesn't get updated
0.64.16 by Ian Clatworthy
safe processing tweaks
439
            return basename, self.inventory.root
0.64.5 by Ian Clatworthy
first cut at generic processing method
440
        try:
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
441
            ie = self.directory_entries[dirname]
0.64.5 by Ian Clatworthy
first cut at generic processing method
442
        except KeyError:
443
            # We will create this entry, since it doesn't exist
444
            pass
445
        else:
446
            return basename, ie
447
448
        # No directory existed, we will just create one, first, make sure
449
        # the parent exists
450
        dir_basename, parent_ie = self._ensure_directory(dirname)
451
        dir_file_id = self.bzr_file_id(dirname)
452
        ie = inventory.entry_factory['directory'](dir_file_id,
453
                                                  dir_basename,
454
                                                  parent_ie.file_id)
455
        ie.revision = self.revision_id
0.64.22 by Ian Clatworthy
fix more inventory lookup bugs
456
        self.directory_entries[dirname] = ie
0.64.16 by Ian Clatworthy
safe processing tweaks
457
        # There are no lines stored for a directory so
458
        # make sure the cache used by get_lines knows that
459
        self.lines_for_commit[dir_file_id] = []
460
        #print "adding dir %s" % path
461
        self.inventory.add(ie)
0.64.5 by Ian Clatworthy
first cut at generic processing method
462
        return basename, ie