~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Aaron Bentley
  • Date: 2009-11-03 15:45:56 UTC
  • mto: (4634.97.2 2.0)
  • mto: This revision was merged to the branch mainline in revision 4798.
  • Revision ID: aaron@aaronbentley.com-20091103154556-e953dmegqbinyokq
Improve patch binary section handling.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
24
24
    bzrdir,
25
25
    check,
26
26
    chk_map,
27
 
    config,
28
27
    debug,
29
28
    errors,
30
 
    fetch as _mod_fetch,
31
29
    fifo_cache,
32
30
    generate_ids,
33
31
    gpg,
41
39
    osutils,
42
40
    revision as _mod_revision,
43
41
    symbol_versioning,
44
 
    trace,
45
42
    tsort,
46
43
    ui,
47
44
    versionedfile,
52
49
from bzrlib.testament import Testament
53
50
""")
54
51
 
55
 
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
56
53
from bzrlib.inter import InterObject
57
54
from bzrlib.inventory import (
58
55
    Inventory,
60
57
    ROOT_ID,
61
58
    entry_factory,
62
59
    )
63
 
from bzrlib.lock import _RelockDebugMixin
64
60
from bzrlib import registry
65
61
from bzrlib.trace import (
66
62
    log_exception_quietly, note, mutter, mutter_callsite, warning)
209
205
            # an inventory delta was accumulated without creating a new
210
206
            # inventory.
211
207
            basis_id = self.basis_delta_revision
212
 
            # We ignore the 'inventory' returned by add_inventory_by_delta
213
 
            # because self.new_inventory is used to hint to the rest of the
214
 
            # system what code path was taken
215
 
            self.inv_sha1, _ = self.repository.add_inventory_by_delta(
 
208
            self.inv_sha1 = self.repository.add_inventory_by_delta(
216
209
                basis_id, self._basis_delta, self._new_revision_id,
217
210
                self.parents)
218
211
        else:
863
856
# Repositories
864
857
 
865
858
 
866
 
class Repository(_RelockDebugMixin):
 
859
class Repository(object):
867
860
    """Repository holding history for one or more branches.
868
861
 
869
862
    The repository holds and retrieves historical information including
1027
1020
 
1028
1021
        :seealso: add_inventory, for the contract.
1029
1022
        """
1030
 
        inv_lines = self._serializer.write_inventory_to_lines(inv)
 
1023
        inv_lines = self._serialise_inventory_to_lines(inv)
1031
1024
        return self._inventory_add_lines(revision_id, parents,
1032
1025
            inv_lines, check_content=False)
1033
1026
 
1240
1233
        """Check a single text from this repository."""
1241
1234
        if kind == 'inventories':
1242
1235
            rev_id = record.key[0]
1243
 
            inv = self._deserialise_inventory(rev_id,
 
1236
            inv = self.deserialise_inventory(rev_id,
1244
1237
                record.get_bytes_as('fulltext'))
1245
1238
            if last_object is not None:
1246
1239
                delta = inv._make_delta(last_object)
1306
1299
        self._reconcile_does_inventory_gc = True
1307
1300
        self._reconcile_fixes_text_parents = False
1308
1301
        self._reconcile_backsup_inventory = True
 
1302
        # not right yet - should be more semantically clear ?
 
1303
        #
 
1304
        # TODO: make sure to construct the right store classes, etc, depending
 
1305
        # on whether escaping is required.
 
1306
        self._warn_if_deprecated()
1309
1307
        self._write_group = None
1310
1308
        # Additional places to query for data.
1311
1309
        self._fallback_repositories = []
1312
1310
        # An InventoryEntry cache, used during deserialization
1313
1311
        self._inventory_entry_cache = fifo_cache.FIFOCache(10*1024)
1314
 
        # Is it safe to return inventory entries directly from the entry cache,
1315
 
        # rather copying them?
1316
 
        self._safe_to_return_from_cache = False
1317
1312
 
1318
1313
    def __repr__(self):
1319
1314
        if self._fallback_repositories:
1386
1381
        locked = self.is_locked()
1387
1382
        result = self.control_files.lock_write(token=token)
1388
1383
        if not locked:
1389
 
            self._warn_if_deprecated()
1390
 
            self._note_lock('w')
1391
1384
            for repo in self._fallback_repositories:
1392
1385
                # Writes don't affect fallback repos
1393
1386
                repo.lock_read()
1398
1391
        locked = self.is_locked()
1399
1392
        self.control_files.lock_read()
1400
1393
        if not locked:
1401
 
            self._warn_if_deprecated()
1402
 
            self._note_lock('r')
1403
1394
            for repo in self._fallback_repositories:
1404
1395
                repo.lock_read()
1405
1396
            self._refresh_data()
1484
1475
        :param using: If True, list only branches using this repository.
1485
1476
        """
1486
1477
        if using and not self.is_shared():
1487
 
            return self.bzrdir.list_branches()
 
1478
            try:
 
1479
                return [self.bzrdir.open_branch()]
 
1480
            except errors.NotBranchError:
 
1481
                return []
1488
1482
        class Evaluator(object):
1489
1483
 
1490
1484
            def __init__(self):
1499
1493
                    except errors.NoRepositoryPresent:
1500
1494
                        pass
1501
1495
                    else:
1502
 
                        return False, ([], repository)
 
1496
                        return False, (None, repository)
1503
1497
                self.first_call = False
1504
 
                value = (bzrdir.list_branches(), None)
 
1498
                try:
 
1499
                    value = (bzrdir.open_branch(), None)
 
1500
                except errors.NotBranchError:
 
1501
                    value = (None, None)
1505
1502
                return True, value
1506
1503
 
1507
 
        ret = []
1508
 
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
 
1504
        branches = []
 
1505
        for branch, repository in bzrdir.BzrDir.find_bzrdirs(
1509
1506
                self.bzrdir.root_transport, evaluate=Evaluator()):
1510
 
            if branches is not None:
1511
 
                ret.extend(branches)
 
1507
            if branch is not None:
 
1508
                branches.append(branch)
1512
1509
            if not using and repository is not None:
1513
 
                ret.extend(repository.find_branches())
1514
 
        return ret
 
1510
                branches.extend(repository.find_branches())
 
1511
        return branches
1515
1512
 
1516
1513
    @needs_read_lock
1517
1514
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1723
1720
        self.start_write_group()
1724
1721
        return result
1725
1722
 
1726
 
    @only_raises(errors.LockNotHeld, errors.LockBroken)
1727
1723
    def unlock(self):
1728
1724
        if (self.control_files._lock_count == 1 and
1729
1725
            self.control_files._lock_mode == 'w'):
1895
1891
                rev = self._serializer.read_revision_from_string(text)
1896
1892
                yield (revid, rev)
1897
1893
 
 
1894
    @needs_read_lock
 
1895
    def get_revision_xml(self, revision_id):
 
1896
        # TODO: jam 20070210 This shouldn't be necessary since get_revision
 
1897
        #       would have already do it.
 
1898
        # TODO: jam 20070210 Just use _serializer.write_revision_to_string()
 
1899
        # TODO: this can't just be replaced by:
 
1900
        # return self._serializer.write_revision_to_string(
 
1901
        #     self.get_revision(revision_id))
 
1902
        # as cStringIO preservers the encoding unlike write_revision_to_string
 
1903
        # or some other call down the path.
 
1904
        rev = self.get_revision(revision_id)
 
1905
        rev_tmp = cStringIO.StringIO()
 
1906
        # the current serializer..
 
1907
        self._serializer.write_revision(rev, rev_tmp)
 
1908
        rev_tmp.seek(0)
 
1909
        return rev_tmp.getvalue()
 
1910
 
1898
1911
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
1899
1912
        """Produce a generator of revision deltas.
1900
1913
 
2142
2155
        """
2143
2156
        selected_keys = set((revid,) for revid in revision_ids)
2144
2157
        w = _inv_weave or self.inventories
2145
 
        return self._find_file_ids_from_xml_inventory_lines(
2146
 
            w.iter_lines_added_or_present_in_keys(
2147
 
                selected_keys, pb=None),
2148
 
            selected_keys)
 
2158
        pb = ui.ui_factory.nested_progress_bar()
 
2159
        try:
 
2160
            return self._find_file_ids_from_xml_inventory_lines(
 
2161
                w.iter_lines_added_or_present_in_keys(
 
2162
                    selected_keys, pb=pb),
 
2163
                selected_keys)
 
2164
        finally:
 
2165
            pb.finished()
2149
2166
 
2150
2167
    def iter_files_bytes(self, desired_files):
2151
2168
        """Iterate through file versions.
2312
2329
        num_file_ids = len(file_ids)
2313
2330
        for file_id, altered_versions in file_ids.iteritems():
2314
2331
            if pb is not None:
2315
 
                pb.update("Fetch texts", count, num_file_ids)
 
2332
                pb.update("fetch texts", count, num_file_ids)
2316
2333
            count += 1
2317
2334
            yield ("file", file_id, altered_versions)
2318
2335
 
2361
2378
        """single-document based inventory iteration."""
2362
2379
        inv_xmls = self._iter_inventory_xmls(revision_ids, ordering)
2363
2380
        for text, revision_id in inv_xmls:
2364
 
            yield self._deserialise_inventory(revision_id, text)
 
2381
            yield self.deserialise_inventory(revision_id, text)
2365
2382
 
2366
2383
    def _iter_inventory_xmls(self, revision_ids, ordering):
2367
2384
        if ordering is None:
2399
2416
                        next_key = None
2400
2417
                        break
2401
2418
 
2402
 
    def _deserialise_inventory(self, revision_id, xml):
 
2419
    def deserialise_inventory(self, revision_id, xml):
2403
2420
        """Transform the xml into an inventory object.
2404
2421
 
2405
2422
        :param revision_id: The expected revision id of the inventory.
2406
2423
        :param xml: A serialised inventory.
2407
2424
        """
2408
2425
        result = self._serializer.read_inventory_from_string(xml, revision_id,
2409
 
                    entry_cache=self._inventory_entry_cache,
2410
 
                    return_from_cache=self._safe_to_return_from_cache)
 
2426
                    entry_cache=self._inventory_entry_cache)
2411
2427
        if result.revision_id != revision_id:
2412
2428
            raise AssertionError('revision id mismatch %s != %s' % (
2413
2429
                result.revision_id, revision_id))
2414
2430
        return result
2415
2431
 
 
2432
    def serialise_inventory(self, inv):
 
2433
        return self._serializer.write_inventory_to_string(inv)
 
2434
 
 
2435
    def _serialise_inventory_to_lines(self, inv):
 
2436
        return self._serializer.write_inventory_to_lines(inv)
 
2437
 
2416
2438
    def get_serializer_format(self):
2417
2439
        return self._serializer.format_num
2418
2440
 
2419
2441
    @needs_read_lock
2420
 
    def _get_inventory_xml(self, revision_id):
2421
 
        """Get serialized inventory as a string."""
 
2442
    def get_inventory_xml(self, revision_id):
 
2443
        """Get inventory XML as a file object."""
2422
2444
        texts = self._iter_inventory_xmls([revision_id], 'unordered')
2423
2445
        try:
2424
2446
            text, revision_id = texts.next()
2426
2448
            raise errors.HistoryMissing(self, 'inventory', revision_id)
2427
2449
        return text
2428
2450
 
 
2451
    @needs_read_lock
 
2452
    def get_inventory_sha1(self, revision_id):
 
2453
        """Return the sha1 hash of the inventory entry
 
2454
        """
 
2455
        return self.get_revision(revision_id).inventory_sha1
 
2456
 
2429
2457
    def get_rev_id_for_revno(self, revno, known_pair):
2430
2458
        """Return the revision id of a revno, given a later (revno, revid)
2431
2459
        pair in the same history.
2482
2510
            else:
2483
2511
                next_id = parents[0]
2484
2512
 
 
2513
    @needs_read_lock
 
2514
    def get_revision_inventory(self, revision_id):
 
2515
        """Return inventory of a past revision."""
 
2516
        # TODO: Unify this with get_inventory()
 
2517
        # bzr 0.0.6 and later imposes the constraint that the inventory_id
 
2518
        # must be the same as its revision, so this is trivial.
 
2519
        if revision_id is None:
 
2520
            # This does not make sense: if there is no revision,
 
2521
            # then it is the current tree inventory surely ?!
 
2522
            # and thus get_root_id() is something that looks at the last
 
2523
            # commit on the branch, and the get_root_id is an inventory check.
 
2524
            raise NotImplementedError
 
2525
            # return Inventory(self.get_root_id())
 
2526
        else:
 
2527
            return self.get_inventory(revision_id)
 
2528
 
2485
2529
    def is_shared(self):
2486
2530
        """Return True if this repository is flagged as a shared repository."""
2487
2531
        raise NotImplementedError(self.is_shared)
2521
2565
            return RevisionTree(self, Inventory(root_id=None),
2522
2566
                                _mod_revision.NULL_REVISION)
2523
2567
        else:
2524
 
            inv = self.get_inventory(revision_id)
 
2568
            inv = self.get_revision_inventory(revision_id)
2525
2569
            return RevisionTree(self, inv, revision_id)
2526
2570
 
2527
2571
    def revision_trees(self, revision_ids):
2617
2661
        for ((revision_id,), parent_keys) in \
2618
2662
                self.revisions.get_parent_map(query_keys).iteritems():
2619
2663
            if parent_keys:
2620
 
                result[revision_id] = tuple([parent_revid
2621
 
                    for (parent_revid,) in parent_keys])
 
2664
                result[revision_id] = tuple(parent_revid
 
2665
                    for (parent_revid,) in parent_keys)
2622
2666
            else:
2623
2667
                result[revision_id] = (_mod_revision.NULL_REVISION,)
2624
2668
        return result
2726
2770
        result.check(callback_refs)
2727
2771
        return result
2728
2772
 
2729
 
    def _warn_if_deprecated(self, branch=None):
 
2773
    def _warn_if_deprecated(self):
2730
2774
        global _deprecation_warning_done
2731
2775
        if _deprecation_warning_done:
2732
2776
            return
2733
 
        try:
2734
 
            if branch is None:
2735
 
                conf = config.GlobalConfig()
2736
 
            else:
2737
 
                conf = branch.get_config()
2738
 
            if conf.suppress_warning('format_deprecation'):
2739
 
                return
2740
 
            warning("Format %s for %s is deprecated -"
2741
 
                    " please use 'bzr upgrade' to get better performance"
2742
 
                    % (self._format, self.bzrdir.transport.base))
2743
 
        finally:
2744
 
            _deprecation_warning_done = True
 
2777
        _deprecation_warning_done = True
 
2778
        warning("Format %s for %s is deprecated - please use 'bzr upgrade' to get better performance"
 
2779
                % (self._format, self.bzrdir.transport.base))
2745
2780
 
2746
2781
    def supports_rich_root(self):
2747
2782
        return self._format.rich_root_data
3030
3065
    pack_compresses = False
3031
3066
    # Does the repository inventory storage understand references to trees?
3032
3067
    supports_tree_reference = None
3033
 
    # Is the format experimental ?
3034
 
    experimental = False
3035
3068
 
3036
3069
    def __str__(self):
3037
3070
        return "<%s>" % self.__class__.__name__
3053
3086
        """
3054
3087
        try:
3055
3088
            transport = a_bzrdir.get_repository_transport(None)
3056
 
            format_string = transport.get_bytes("format")
 
3089
            format_string = transport.get("format").read()
3057
3090
            return format_registry.get(format_string)
3058
3091
        except errors.NoSuchFile:
3059
3092
            raise errors.NoRepositoryPresent(a_bzrdir)
3368
3401
 
3369
3402
        :param revision_id: if None all content is copied, if NULL_REVISION no
3370
3403
                            content is copied.
3371
 
        :param pb: ignored.
 
3404
        :param pb: optional progress bar to use for progress reports. If not
 
3405
                   provided a default one will be created.
3372
3406
        :return: None.
3373
3407
        """
3374
 
        ui.ui_factory.warn_experimental_format_fetch(self)
3375
 
        f = _mod_fetch.RepoFetcher(to_repository=self.target,
 
3408
        from bzrlib.fetch import RepoFetcher
 
3409
        f = RepoFetcher(to_repository=self.target,
3376
3410
                               from_repository=self.source,
3377
3411
                               last_revision=revision_id,
3378
3412
                               fetch_spec=fetch_spec,
3379
 
                               find_ghosts=find_ghosts)
 
3413
                               pb=pb, find_ghosts=find_ghosts)
3380
3414
 
3381
3415
    def _walk_to_common_revisions(self, revision_ids):
3382
3416
        """Walk out from revision_ids in source to revisions target has.
3551
3585
                self.target.texts.insert_record_stream(
3552
3586
                    self.source.texts.get_record_stream(
3553
3587
                        self.source.texts.keys(), 'topological', False))
3554
 
                pb.update('Copying inventory', 0, 1)
 
3588
                pb.update('copying inventory', 0, 1)
3555
3589
                self.target.inventories.insert_record_stream(
3556
3590
                    self.source.inventories.get_record_stream(
3557
3591
                        self.source.inventories.keys(), 'topological', False))
3778
3812
                basis_id, delta, current_revision_id, parents_parents)
3779
3813
            cache[current_revision_id] = parent_tree
3780
3814
 
3781
 
    def _fetch_batch(self, revision_ids, basis_id, cache, a_graph=None):
 
3815
    def _fetch_batch(self, revision_ids, basis_id, cache):
3782
3816
        """Fetch across a few revisions.
3783
3817
 
3784
3818
        :param revision_ids: The revisions to copy
3785
3819
        :param basis_id: The revision_id of a tree that must be in cache, used
3786
3820
            as a basis for delta when no other base is available
3787
3821
        :param cache: A cache of RevisionTrees that we can use.
3788
 
        :param a_graph: A Graph object to determine the heads() of the
3789
 
            rich-root data stream.
3790
3822
        :return: The revision_id of the last converted tree. The RevisionTree
3791
3823
            for it will be in cache
3792
3824
        """
3799
3831
        pending_revisions = []
3800
3832
        parent_map = self.source.get_parent_map(revision_ids)
3801
3833
        self._fetch_parent_invs_for_stacking(parent_map, cache)
3802
 
        self.source._safe_to_return_from_cache = True
3803
3834
        for tree in self.source.revision_trees(revision_ids):
3804
3835
            # Find a inventory delta for this revision.
3805
3836
            # Find text entries that need to be copied, too.
3853
3884
            pending_revisions.append(revision)
3854
3885
            cache[current_revision_id] = tree
3855
3886
            basis_id = current_revision_id
3856
 
        self.source._safe_to_return_from_cache = False
3857
3887
        # Copy file texts
3858
3888
        from_texts = self.source.texts
3859
3889
        to_texts = self.target.texts
3860
3890
        if root_keys_to_create:
3861
 
            root_stream = _mod_fetch._new_root_data_stream(
 
3891
            from bzrlib.fetch import _new_root_data_stream
 
3892
            root_stream = _new_root_data_stream(
3862
3893
                root_keys_to_create, self._revision_id_to_root_id, parent_map,
3863
 
                self.source, graph=a_graph)
 
3894
                self.source)
3864
3895
            to_texts.insert_record_stream(root_stream)
3865
3896
        to_texts.insert_record_stream(from_texts.get_record_stream(
3866
3897
            text_keys, self.target._format._fetch_order,
3923
3954
        cache[basis_id] = basis_tree
3924
3955
        del basis_tree # We don't want to hang on to it here
3925
3956
        hints = []
3926
 
        if self._converting_to_rich_root and len(revision_ids) > 100:
3927
 
            a_graph = _mod_fetch._get_rich_root_heads_graph(self.source,
3928
 
                                                            revision_ids)
3929
 
        else:
3930
 
            a_graph = None
3931
 
 
3932
3957
        for offset in range(0, len(revision_ids), batch_size):
3933
3958
            self.target.start_write_group()
3934
3959
            try:
3935
3960
                pb.update('Transferring revisions', offset,
3936
3961
                          len(revision_ids))
3937
3962
                batch = revision_ids[offset:offset+batch_size]
3938
 
                basis_id = self._fetch_batch(batch, basis_id, cache,
3939
 
                                             a_graph=a_graph)
 
3963
                basis_id = self._fetch_batch(batch, basis_id, cache)
3940
3964
            except:
3941
 
                self.source._safe_to_return_from_cache = False
3942
3965
                self.target.abort_write_group()
3943
3966
                raise
3944
3967
            else:
3956
3979
        """See InterRepository.fetch()."""
3957
3980
        if fetch_spec is not None:
3958
3981
            raise AssertionError("Not implemented yet...")
3959
 
        # See <https://launchpad.net/bugs/456077> asking for a warning here
3960
 
        #
3961
 
        # nb this is only active for local-local fetches; other things using
3962
 
        # streaming.
3963
 
        ui.ui_factory.warn_cross_format_fetch(self.source._format,
3964
 
            self.target._format)
3965
 
        ui.ui_factory.warn_experimental_format_fetch(self)
3966
3982
        if (not self.source.supports_rich_root()
3967
3983
            and self.target.supports_rich_root()):
3968
3984
            self._converting_to_rich_root = True
4043
4059
        :param to_convert: The disk object to convert.
4044
4060
        :param pb: a progress bar to use for progress information.
4045
4061
        """
4046
 
        pb = ui.ui_factory.nested_progress_bar()
 
4062
        self.pb = pb
4047
4063
        self.count = 0
4048
4064
        self.total = 4
4049
4065
        # this is only useful with metadir layouts - separated repo content.
4050
4066
        # trigger an assertion if not such
4051
4067
        repo._format.get_format_string()
4052
4068
        self.repo_dir = repo.bzrdir
4053
 
        pb.update('Moving repository to repository.backup')
 
4069
        self.step('Moving repository to repository.backup')
4054
4070
        self.repo_dir.transport.move('repository', 'repository.backup')
4055
4071
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
4056
4072
        repo._format.check_conversion_target(self.target_format)
4057
4073
        self.source_repo = repo._format.open(self.repo_dir,
4058
4074
            _found=True,
4059
4075
            _override_transport=backup_transport)
4060
 
        pb.update('Creating new repository')
 
4076
        self.step('Creating new repository')
4061
4077
        converted = self.target_format.initialize(self.repo_dir,
4062
4078
                                                  self.source_repo.is_shared())
4063
4079
        converted.lock_write()
4064
4080
        try:
4065
 
            pb.update('Copying content')
 
4081
            self.step('Copying content into repository.')
4066
4082
            self.source_repo.copy_content_into(converted)
4067
4083
        finally:
4068
4084
            converted.unlock()
4069
 
        pb.update('Deleting old repository content')
 
4085
        self.step('Deleting old repository content.')
4070
4086
        self.repo_dir.transport.delete_tree('repository.backup')
4071
 
        ui.ui_factory.note('repository converted')
4072
 
        pb.finished()
 
4087
        self.pb.note('repository converted')
 
4088
 
 
4089
    def step(self, message):
 
4090
        """Update the pb by a step."""
 
4091
        self.count +=1
 
4092
        self.pb.update(message, self.count, self.total)
4073
4093
 
4074
4094
 
4075
4095
_unescape_map = {
4257
4277
                    self._extract_and_insert_inventories(
4258
4278
                        substream, src_serializer)
4259
4279
            elif substream_type == 'inventory-deltas':
4260
 
                ui.ui_factory.warn_cross_format_fetch(src_format,
4261
 
                    self.target_repo._format)
4262
4280
                self._extract_and_insert_inventory_deltas(
4263
4281
                    substream, src_serializer)
4264
4282
            elif substream_type == 'chk_bytes':
4297
4315
                ):
4298
4316
                if versioned_file is None:
4299
4317
                    continue
4300
 
                # TODO: key is often going to be a StaticTuple object
4301
 
                #       I don't believe we can define a method by which
4302
 
                #       (prefix,) + StaticTuple will work, though we could
4303
 
                #       define a StaticTuple.sq_concat that would allow you to
4304
 
                #       pass in either a tuple or a StaticTuple as the second
4305
 
                #       object, so instead we could have:
4306
 
                #       StaticTuple(prefix) + key here...
4307
4318
                missing_keys.update((prefix,) + key for key in
4308
4319
                    versioned_file.get_missing_compression_parent_keys())
4309
4320
        except NotImplementedError:
4421
4432
        fetching the inventory weave.
4422
4433
        """
4423
4434
        if self._rich_root_upgrade():
4424
 
            return _mod_fetch.Inter1and2Helper(
 
4435
            import bzrlib.fetch
 
4436
            return bzrlib.fetch.Inter1and2Helper(
4425
4437
                self.from_repository).generate_root_texts(revs)
4426
4438
        else:
4427
4439
            return []
4569
4581
 
4570
4582
    def _get_convertable_inventory_stream(self, revision_ids,
4571
4583
                                          delta_versus_null=False):
4572
 
        # The two formats are sufficiently different that there is no fast
4573
 
        # path, so we need to send just inventorydeltas, which any
4574
 
        # sufficiently modern client can insert into any repository.
4575
 
        # The StreamSink code expects to be able to
 
4584
        # The source is using CHKs, but the target either doesn't or it has a
 
4585
        # different serializer.  The StreamSink code expects to be able to
4576
4586
        # convert on the target, so we need to put bytes-on-the-wire that can
4577
4587
        # be converted.  That means inventory deltas (if the remote is <1.19,
4578
4588
        # RemoteStreamSink will fallback to VFS to insert the deltas).