~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-09-06 03:41:24 UTC
  • mfrom: (2794.1.3 knits)
  • Revision ID: pqm@pqm.ubuntu.com-20070906034124-gf4re7orinpud4to
(robertc) Nuke VersionedFile add/get delta support which was never used, and reduce memory copies during commits of unannotated file such as inventory. (Robert Collins).

Show diffs side-by-side

added added

removed removed

Lines of Context:
245
245
 
246
246
    __contains__ = has_version
247
247
 
248
 
    def get_delta(self, version_id):
249
 
        """See VersionedFile.get_delta."""
250
 
        return self.get_deltas([version_id])[version_id]
251
 
 
252
 
    def get_deltas(self, version_ids):
253
 
        """See VersionedFile.get_deltas."""
254
 
        version_ids = self.get_ancestry(version_ids)
255
 
        for version_id in version_ids:
256
 
            if not self.has_version(version_id):
257
 
                raise RevisionNotPresent(version_id, self)
258
 
        # try extracting all versions; parallel extraction is used
259
 
        nv = self.num_versions()
260
 
        sha1s = {}
261
 
        deltas = {}
262
 
        texts = {}
263
 
        inclusions = {}
264
 
        noeols = {}
265
 
        last_parent_lines = {}
266
 
        parents = {}
267
 
        parent_inclusions = {}
268
 
        parent_linenums = {}
269
 
        parent_noeols = {}
270
 
        current_hunks = {}
271
 
        diff_hunks = {}
272
 
        # its simplest to generate a full set of prepared variables.
273
 
        for i in range(nv):
274
 
            name = self._names[i]
275
 
            sha1s[name] = self.get_sha1(name)
276
 
            parents_list = self.get_parents(name)
277
 
            try:
278
 
                parent = parents_list[0]
279
 
                parents[name] = parent
280
 
                parent_inclusions[name] = inclusions[parent]
281
 
            except IndexError:
282
 
                parents[name] = None
283
 
                parent_inclusions[name] = set()
284
 
            # we want to emit start, finish, replacement_length, replacement_lines tuples.
285
 
            diff_hunks[name] = []
286
 
            current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
287
 
            parent_linenums[name] = 0
288
 
            noeols[name] = False
289
 
            parent_noeols[name] = False
290
 
            last_parent_lines[name] = None
291
 
            new_inc = set([name])
292
 
            for p in self._parents[i]:
293
 
                new_inc.update(inclusions[self._idx_to_name(p)])
294
 
            # debug only, known good so far.
295
 
            #assert set(new_inc) == set(self.get_ancestry(name)), \
296
 
            #    'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
297
 
            inclusions[name] = new_inc
298
 
 
299
 
        nlines = len(self._weave)
300
 
 
301
 
        for lineno, inserted, deletes, line in self._walk_internal():
302
 
            # a line is active in a version if:
303
 
            # insert is in the versions inclusions
304
 
            # and
305
 
            # deleteset & the versions inclusions is an empty set.
306
 
            # so - if we have a included by mapping - version is included by
307
 
            # children, we get a list of children to examine for deletes affect
308
 
            # ing them, which is less than the entire set of children.
309
 
            for version_id in version_ids:  
310
 
                # The active inclusion must be an ancestor,
311
 
                # and no ancestors must have deleted this line,
312
 
                # because we don't support resurrection.
313
 
                parent_inclusion = parent_inclusions[version_id]
314
 
                inclusion = inclusions[version_id]
315
 
                parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
316
 
                version_active = inserted in inclusion and not (deletes & inclusion)
317
 
                if not parent_active and not version_active:
318
 
                    # unrelated line of ancestry
319
 
                    continue
320
 
                elif parent_active and version_active:
321
 
                    # shared line
322
 
                    parent_linenum = parent_linenums[version_id]
323
 
                    if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
324
 
                        diff_hunks[version_id].append(tuple(current_hunks[version_id]))
325
 
                    parent_linenum += 1
326
 
                    current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
327
 
                    parent_linenums[version_id] = parent_linenum
328
 
                    try:
329
 
                        if line[-1] != '\n':
330
 
                            noeols[version_id] = True
331
 
                    except IndexError:
332
 
                        pass
333
 
                elif parent_active and not version_active:
334
 
                    # deleted line
335
 
                    current_hunks[version_id][1] += 1
336
 
                    parent_linenums[version_id] += 1
337
 
                    last_parent_lines[version_id] = line
338
 
                elif not parent_active and version_active:
339
 
                    # replacement line
340
 
                    # noeol only occurs at the end of a file because we 
341
 
                    # diff linewise. We want to show noeol changes as a
342
 
                    # empty diff unless the actual eol-less content changed.
343
 
                    theline = line
344
 
                    try:
345
 
                        if last_parent_lines[version_id][-1] != '\n':
346
 
                            parent_noeols[version_id] = True
347
 
                    except (TypeError, IndexError):
348
 
                        pass
349
 
                    try:
350
 
                        if theline[-1] != '\n':
351
 
                            noeols[version_id] = True
352
 
                    except IndexError:
353
 
                        pass
354
 
                    new_line = False
355
 
                    parent_should_go = False
356
 
 
357
 
                    if parent_noeols[version_id] == noeols[version_id]:
358
 
                        # no noeol toggle, so trust the weaves statement
359
 
                        # that this line is changed.
360
 
                        new_line = True
361
 
                        if parent_noeols[version_id]:
362
 
                            theline = theline + '\n'
363
 
                    elif parent_noeols[version_id]:
364
 
                        # parent has no eol, we do:
365
 
                        # our line is new, report as such..
366
 
                        new_line = True
367
 
                    elif noeols[version_id]:
368
 
                        # append a eol so that it looks like
369
 
                        # a normalised delta
370
 
                        theline = theline + '\n'
371
 
                        if parents[version_id] is not None:
372
 
                        #if last_parent_lines[version_id] is not None:
373
 
                            parent_should_go = True
374
 
                        if last_parent_lines[version_id] != theline:
375
 
                            # but changed anyway
376
 
                            new_line = True
377
 
                            #parent_should_go = False
378
 
                    if new_line:
379
 
                        current_hunks[version_id][2] += 1
380
 
                        current_hunks[version_id][3].append((inserted, theline))
381
 
                    if parent_should_go:
382
 
                        # last hunk last parent line is not eaten
383
 
                        current_hunks[version_id][1] -= 1
384
 
                    if current_hunks[version_id][1] < 0:
385
 
                        current_hunks[version_id][1] = 0
386
 
                        # import pdb;pdb.set_trace()
387
 
                    # assert current_hunks[version_id][1] >= 0
388
 
 
389
 
        # flush last hunk
390
 
        for i in range(nv):
391
 
            version = self._idx_to_name(i)
392
 
            if current_hunks[version] != [0, 0, 0, []]:
393
 
                diff_hunks[version].append(tuple(current_hunks[version]))
394
 
        result = {}
395
 
        for version_id in version_ids:
396
 
            result[version_id] = (
397
 
                                  parents[version_id],
398
 
                                  sha1s[version_id],
399
 
                                  noeols[version_id],
400
 
                                  diff_hunks[version_id],
401
 
                                  )
402
 
        return result
403
 
 
404
248
    def get_parents(self, version_id):
405
249
        """See VersionedFile.get_parent."""
406
250
        return map(self._idx_to_name, self._parents[self._lookup(version_id)])
417
261
        return idx
418
262
 
419
263
    def _add_lines(self, version_id, parents, lines, parent_texts,
420
 
                   left_matching_blocks=None):
 
264
       left_matching_blocks, nostore_sha):
421
265
        """See VersionedFile.add_lines."""
422
 
        idx = self._add(version_id, lines, map(self._lookup, parents))
 
266
        idx = self._add(version_id, lines, map(self._lookup, parents),
 
267
            nostore_sha=nostore_sha)
423
268
        return sha_strings(lines), sum(map(len, lines)), idx
424
269
 
425
 
    def _add(self, version_id, lines, parents, sha1=None):
 
270
    def _add(self, version_id, lines, parents, sha1=None, nostore_sha=None):
426
271
        """Add a single text on top of the weave.
427
272
  
428
273
        Returns the index number of the newly added version.
436
281
            
437
282
        lines
438
283
            Sequence of lines to be added in the new version.
 
284
 
 
285
        :param nostore_sha: See VersionedFile.add_lines.
439
286
        """
440
 
 
441
287
        assert isinstance(version_id, basestring)
442
288
        self._check_lines_not_unicode(lines)
443
289
        self._check_lines_are_lines(lines)
444
290
        if not sha1:
445
291
            sha1 = sha_strings(lines)
 
292
        if sha1 == nostore_sha:
 
293
            raise errors.ExistingContent
446
294
        if version_id in self._name_map:
447
295
            return self._check_repeated_add(version_id, parents, lines, sha1)
448
296
 
1022
870
            self._save()
1023
871
 
1024
872
    def _add_lines(self, version_id, parents, lines, parent_texts,
1025
 
        left_matching_blocks=None):
 
873
        left_matching_blocks, nostore_sha):
1026
874
        """Add a version and save the weave."""
1027
875
        self.check_not_reserved_id(version_id)
1028
876
        result = super(WeaveFile, self)._add_lines(version_id, parents, lines,
1029
 
                                                   parent_texts)
 
877
            parent_texts, left_matching_blocks, nostore_sha)
1030
878
        self._save()
1031
879
        return result
1032
880