/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    bzrdir,
25
25
    check,
26
26
    chk_map,
 
27
    config,
27
28
    debug,
28
29
    errors,
 
30
    fetch as _mod_fetch,
29
31
    fifo_cache,
30
32
    generate_ids,
31
33
    gpg,
38
40
    lru_cache,
39
41
    osutils,
40
42
    revision as _mod_revision,
 
43
    static_tuple,
41
44
    symbol_versioning,
42
45
    trace,
43
46
    tsort,
50
53
from bzrlib.testament import Testament
51
54
""")
52
55
 
53
 
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
56
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
54
57
from bzrlib.inter import InterObject
55
58
from bzrlib.inventory import (
56
59
    Inventory,
58
61
    ROOT_ID,
59
62
    entry_factory,
60
63
    )
 
64
from bzrlib.lock import _RelockDebugMixin
61
65
from bzrlib import registry
62
66
from bzrlib.trace import (
63
67
    log_exception_quietly, note, mutter, mutter_callsite, warning)
206
210
            # an inventory delta was accumulated without creating a new
207
211
            # inventory.
208
212
            basis_id = self.basis_delta_revision
209
 
            self.inv_sha1 = self.repository.add_inventory_by_delta(
 
213
            # We ignore the 'inventory' returned by add_inventory_by_delta
 
214
            # because self.new_inventory is used to hint to the rest of the
 
215
            # system what code path was taken
 
216
            self.inv_sha1, _ = self.repository.add_inventory_by_delta(
210
217
                basis_id, self._basis_delta, self._new_revision_id,
211
218
                self.parents)
212
219
        else:
857
864
# Repositories
858
865
 
859
866
 
860
 
class Repository(object):
 
867
class Repository(_RelockDebugMixin, bzrdir.ControlComponent):
861
868
    """Repository holding history for one or more branches.
862
869
 
863
870
    The repository holds and retrieves historical information including
1021
1028
 
1022
1029
        :seealso: add_inventory, for the contract.
1023
1030
        """
1024
 
        inv_lines = self._serialise_inventory_to_lines(inv)
 
1031
        inv_lines = self._serializer.write_inventory_to_lines(inv)
1025
1032
        return self._inventory_add_lines(revision_id, parents,
1026
1033
            inv_lines, check_content=False)
1027
1034
 
1234
1241
        """Check a single text from this repository."""
1235
1242
        if kind == 'inventories':
1236
1243
            rev_id = record.key[0]
1237
 
            inv = self.deserialise_inventory(rev_id,
 
1244
            inv = self._deserialise_inventory(rev_id,
1238
1245
                record.get_bytes_as('fulltext'))
1239
1246
            if last_object is not None:
1240
1247
                delta = inv._make_delta(last_object)
1284
1291
 
1285
1292
        :param _format: The format of the repository on disk.
1286
1293
        :param a_bzrdir: The BzrDir of the repository.
1287
 
 
1288
 
        In the future we will have a single api for all stores for
1289
 
        getting file texts, inventories and revisions, then
1290
 
        this construct will accept instances of those things.
1291
1294
        """
 
1295
        # In the future we will have a single api for all stores for
 
1296
        # getting file texts, inventories and revisions, then
 
1297
        # this construct will accept instances of those things.
1292
1298
        super(Repository, self).__init__()
1293
1299
        self._format = _format
1294
1300
        # the following are part of the public API for Repository:
1300
1306
        self._reconcile_does_inventory_gc = True
1301
1307
        self._reconcile_fixes_text_parents = False
1302
1308
        self._reconcile_backsup_inventory = True
1303
 
        # not right yet - should be more semantically clear ?
1304
 
        #
1305
 
        # TODO: make sure to construct the right store classes, etc, depending
1306
 
        # on whether escaping is required.
1307
 
        self._warn_if_deprecated()
1308
1309
        self._write_group = None
1309
1310
        # Additional places to query for data.
1310
1311
        self._fallback_repositories = []
1311
1312
        # An InventoryEntry cache, used during deserialization
1312
1313
        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
 
 
1318
    @property
 
1319
    def user_transport(self):
 
1320
        return self.bzrdir.user_transport
 
1321
 
 
1322
    @property
 
1323
    def control_transport(self):
 
1324
        return self._transport
1313
1325
 
1314
1326
    def __repr__(self):
1315
1327
        if self._fallback_repositories:
1382
1394
        locked = self.is_locked()
1383
1395
        result = self.control_files.lock_write(token=token)
1384
1396
        if not locked:
 
1397
            self._warn_if_deprecated()
 
1398
            self._note_lock('w')
1385
1399
            for repo in self._fallback_repositories:
1386
1400
                # Writes don't affect fallback repos
1387
1401
                repo.lock_read()
1392
1406
        locked = self.is_locked()
1393
1407
        self.control_files.lock_read()
1394
1408
        if not locked:
 
1409
            self._warn_if_deprecated()
 
1410
            self._note_lock('r')
1395
1411
            for repo in self._fallback_repositories:
1396
1412
                repo.lock_read()
1397
1413
            self._refresh_data()
1460
1476
 
1461
1477
        # now gather global repository information
1462
1478
        # XXX: This is available for many repos regardless of listability.
1463
 
        if self.bzrdir.root_transport.listable():
 
1479
        if self.user_transport.listable():
1464
1480
            # XXX: do we want to __define len__() ?
1465
1481
            # Maybe the versionedfiles object should provide a different
1466
1482
            # method to get the number of keys.
1476
1492
        :param using: If True, list only branches using this repository.
1477
1493
        """
1478
1494
        if using and not self.is_shared():
1479
 
            try:
1480
 
                return [self.bzrdir.open_branch()]
1481
 
            except errors.NotBranchError:
1482
 
                return []
 
1495
            return self.bzrdir.list_branches()
1483
1496
        class Evaluator(object):
1484
1497
 
1485
1498
            def __init__(self):
1494
1507
                    except errors.NoRepositoryPresent:
1495
1508
                        pass
1496
1509
                    else:
1497
 
                        return False, (None, repository)
 
1510
                        return False, ([], repository)
1498
1511
                self.first_call = False
1499
 
                try:
1500
 
                    value = (bzrdir.open_branch(), None)
1501
 
                except errors.NotBranchError:
1502
 
                    value = (None, None)
 
1512
                value = (bzrdir.list_branches(), None)
1503
1513
                return True, value
1504
1514
 
1505
 
        branches = []
1506
 
        for branch, repository in bzrdir.BzrDir.find_bzrdirs(
1507
 
                self.bzrdir.root_transport, evaluate=Evaluator()):
1508
 
            if branch is not None:
1509
 
                branches.append(branch)
 
1515
        ret = []
 
1516
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
 
1517
                self.user_transport, evaluate=Evaluator()):
 
1518
            if branches is not None:
 
1519
                ret.extend(branches)
1510
1520
            if not using and repository is not None:
1511
 
                branches.extend(repository.find_branches())
1512
 
        return branches
 
1521
                ret.extend(repository.find_branches())
 
1522
        return ret
1513
1523
 
1514
1524
    @needs_read_lock
1515
1525
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1721
1731
        self.start_write_group()
1722
1732
        return result
1723
1733
 
 
1734
    @only_raises(errors.LockNotHeld, errors.LockBroken)
1724
1735
    def unlock(self):
1725
1736
        if (self.control_files._lock_count == 1 and
1726
1737
            self.control_files._lock_mode == 'w'):
1892
1903
                rev = self._serializer.read_revision_from_string(text)
1893
1904
                yield (revid, rev)
1894
1905
 
1895
 
    @needs_read_lock
1896
 
    def get_revision_xml(self, revision_id):
1897
 
        # TODO: jam 20070210 This shouldn't be necessary since get_revision
1898
 
        #       would have already do it.
1899
 
        # TODO: jam 20070210 Just use _serializer.write_revision_to_string()
1900
 
        # TODO: this can't just be replaced by:
1901
 
        # return self._serializer.write_revision_to_string(
1902
 
        #     self.get_revision(revision_id))
1903
 
        # as cStringIO preservers the encoding unlike write_revision_to_string
1904
 
        # or some other call down the path.
1905
 
        rev = self.get_revision(revision_id)
1906
 
        rev_tmp = cStringIO.StringIO()
1907
 
        # the current serializer..
1908
 
        self._serializer.write_revision(rev, rev_tmp)
1909
 
        rev_tmp.seek(0)
1910
 
        return rev_tmp.getvalue()
1911
 
 
1912
1906
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
1913
1907
        """Produce a generator of revision deltas.
1914
1908
 
2156
2150
        """
2157
2151
        selected_keys = set((revid,) for revid in revision_ids)
2158
2152
        w = _inv_weave or self.inventories
2159
 
        pb = ui.ui_factory.nested_progress_bar()
2160
 
        try:
2161
 
            return self._find_file_ids_from_xml_inventory_lines(
2162
 
                w.iter_lines_added_or_present_in_keys(
2163
 
                    selected_keys, pb=pb),
2164
 
                selected_keys)
2165
 
        finally:
2166
 
            pb.finished()
 
2153
        return self._find_file_ids_from_xml_inventory_lines(
 
2154
            w.iter_lines_added_or_present_in_keys(
 
2155
                selected_keys, pb=None),
 
2156
            selected_keys)
2167
2157
 
2168
2158
    def iter_files_bytes(self, desired_files):
2169
2159
        """Iterate through file versions.
2330
2320
        num_file_ids = len(file_ids)
2331
2321
        for file_id, altered_versions in file_ids.iteritems():
2332
2322
            if pb is not None:
2333
 
                pb.update("fetch texts", count, num_file_ids)
 
2323
                pb.update("Fetch texts", count, num_file_ids)
2334
2324
            count += 1
2335
2325
            yield ("file", file_id, altered_versions)
2336
2326
 
2379
2369
        """single-document based inventory iteration."""
2380
2370
        inv_xmls = self._iter_inventory_xmls(revision_ids, ordering)
2381
2371
        for text, revision_id in inv_xmls:
2382
 
            yield self.deserialise_inventory(revision_id, text)
 
2372
            yield self._deserialise_inventory(revision_id, text)
2383
2373
 
2384
2374
    def _iter_inventory_xmls(self, revision_ids, ordering):
2385
2375
        if ordering is None:
2417
2407
                        next_key = None
2418
2408
                        break
2419
2409
 
2420
 
    def deserialise_inventory(self, revision_id, xml):
 
2410
    def _deserialise_inventory(self, revision_id, xml):
2421
2411
        """Transform the xml into an inventory object.
2422
2412
 
2423
2413
        :param revision_id: The expected revision id of the inventory.
2424
2414
        :param xml: A serialised inventory.
2425
2415
        """
2426
2416
        result = self._serializer.read_inventory_from_string(xml, revision_id,
2427
 
                    entry_cache=self._inventory_entry_cache)
 
2417
                    entry_cache=self._inventory_entry_cache,
 
2418
                    return_from_cache=self._safe_to_return_from_cache)
2428
2419
        if result.revision_id != revision_id:
2429
2420
            raise AssertionError('revision id mismatch %s != %s' % (
2430
2421
                result.revision_id, revision_id))
2431
2422
        return result
2432
2423
 
2433
 
    def serialise_inventory(self, inv):
2434
 
        return self._serializer.write_inventory_to_string(inv)
2435
 
 
2436
 
    def _serialise_inventory_to_lines(self, inv):
2437
 
        return self._serializer.write_inventory_to_lines(inv)
2438
 
 
2439
2424
    def get_serializer_format(self):
2440
2425
        return self._serializer.format_num
2441
2426
 
2442
2427
    @needs_read_lock
2443
 
    def get_inventory_xml(self, revision_id):
2444
 
        """Get inventory XML as a file object."""
 
2428
    def _get_inventory_xml(self, revision_id):
 
2429
        """Get serialized inventory as a string."""
2445
2430
        texts = self._iter_inventory_xmls([revision_id], 'unordered')
2446
2431
        try:
2447
2432
            text, revision_id = texts.next()
2449
2434
            raise errors.HistoryMissing(self, 'inventory', revision_id)
2450
2435
        return text
2451
2436
 
2452
 
    @needs_read_lock
2453
 
    def get_inventory_sha1(self, revision_id):
2454
 
        """Return the sha1 hash of the inventory entry
2455
 
        """
2456
 
        return self.get_revision(revision_id).inventory_sha1
2457
 
 
2458
2437
    def get_rev_id_for_revno(self, revno, known_pair):
2459
2438
        """Return the revision id of a revno, given a later (revno, revid)
2460
2439
        pair in the same history.
2511
2490
            else:
2512
2491
                next_id = parents[0]
2513
2492
 
2514
 
    @needs_read_lock
2515
 
    def get_revision_inventory(self, revision_id):
2516
 
        """Return inventory of a past revision."""
2517
 
        # TODO: Unify this with get_inventory()
2518
 
        # bzr 0.0.6 and later imposes the constraint that the inventory_id
2519
 
        # must be the same as its revision, so this is trivial.
2520
 
        if revision_id is None:
2521
 
            # This does not make sense: if there is no revision,
2522
 
            # then it is the current tree inventory surely ?!
2523
 
            # and thus get_root_id() is something that looks at the last
2524
 
            # commit on the branch, and the get_root_id is an inventory check.
2525
 
            raise NotImplementedError
2526
 
            # return Inventory(self.get_root_id())
2527
 
        else:
2528
 
            return self.get_inventory(revision_id)
2529
 
 
2530
2493
    def is_shared(self):
2531
2494
        """Return True if this repository is flagged as a shared repository."""
2532
2495
        raise NotImplementedError(self.is_shared)
2566
2529
            return RevisionTree(self, Inventory(root_id=None),
2567
2530
                                _mod_revision.NULL_REVISION)
2568
2531
        else:
2569
 
            inv = self.get_revision_inventory(revision_id)
 
2532
            inv = self.get_inventory(revision_id)
2570
2533
            return RevisionTree(self, inv, revision_id)
2571
2534
 
2572
2535
    def revision_trees(self, revision_ids):
2625
2588
            keys = tsort.topo_sort(parent_map)
2626
2589
        return [None] + list(keys)
2627
2590
 
2628
 
    def pack(self, hint=None):
 
2591
    def pack(self, hint=None, clean_obsolete_packs=False):
2629
2592
        """Compress the data within the repository.
2630
2593
 
2631
2594
        This operation only makes sense for some repository types. For other
2641
2604
            obtained from the result of commit_write_group(). Out of
2642
2605
            date hints are simply ignored, because concurrent operations
2643
2606
            can obsolete them rapidly.
 
2607
 
 
2608
        :param clean_obsolete_packs: Clean obsolete packs immediately after
 
2609
            the pack operation.
2644
2610
        """
2645
2611
 
2646
2612
    def get_transaction(self):
2662
2628
        for ((revision_id,), parent_keys) in \
2663
2629
                self.revisions.get_parent_map(query_keys).iteritems():
2664
2630
            if parent_keys:
2665
 
                result[revision_id] = tuple(parent_revid
2666
 
                    for (parent_revid,) in parent_keys)
 
2631
                result[revision_id] = tuple([parent_revid
 
2632
                    for (parent_revid,) in parent_keys])
2667
2633
            else:
2668
2634
                result[revision_id] = (_mod_revision.NULL_REVISION,)
2669
2635
        return result
2671
2637
    def _make_parents_provider(self):
2672
2638
        return self
2673
2639
 
 
2640
    @needs_read_lock
 
2641
    def get_known_graph_ancestry(self, revision_ids):
 
2642
        """Return the known graph for a set of revision ids and their ancestors.
 
2643
        """
 
2644
        st = static_tuple.StaticTuple
 
2645
        revision_keys = [st(r_id).intern() for r_id in revision_ids]
 
2646
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
 
2647
        return graph.GraphThunkIdsToKeys(known_graph)
 
2648
 
2674
2649
    def get_graph(self, other_repository=None):
2675
2650
        """Return the graph walker for this repository format"""
2676
2651
        parents_provider = self._make_parents_provider()
2771
2746
        result.check(callback_refs)
2772
2747
        return result
2773
2748
 
2774
 
    def _warn_if_deprecated(self):
 
2749
    def _warn_if_deprecated(self, branch=None):
2775
2750
        global _deprecation_warning_done
2776
2751
        if _deprecation_warning_done:
2777
2752
            return
2778
 
        _deprecation_warning_done = True
2779
 
        warning("Format %s for %s is deprecated - please use 'bzr upgrade' to get better performance"
2780
 
                % (self._format, self.bzrdir.transport.base))
 
2753
        try:
 
2754
            if branch is None:
 
2755
                conf = config.GlobalConfig()
 
2756
            else:
 
2757
                conf = branch.get_config()
 
2758
            if conf.suppress_warning('format_deprecation'):
 
2759
                return
 
2760
            warning("Format %s for %s is deprecated -"
 
2761
                    " please use 'bzr upgrade' to get better performance"
 
2762
                    % (self._format, self.bzrdir.transport.base))
 
2763
        finally:
 
2764
            _deprecation_warning_done = True
2781
2765
 
2782
2766
    def supports_rich_root(self):
2783
2767
        return self._format.rich_root_data
3066
3050
    pack_compresses = False
3067
3051
    # Does the repository inventory storage understand references to trees?
3068
3052
    supports_tree_reference = None
 
3053
    # Is the format experimental ?
 
3054
    experimental = False
3069
3055
 
3070
 
    def __str__(self):
3071
 
        return "<%s>" % self.__class__.__name__
 
3056
    def __repr__(self):
 
3057
        return "%s()" % self.__class__.__name__
3072
3058
 
3073
3059
    def __eq__(self, other):
3074
3060
        # format objects are generally stateless
3087
3073
        """
3088
3074
        try:
3089
3075
            transport = a_bzrdir.get_repository_transport(None)
3090
 
            format_string = transport.get("format").read()
 
3076
            format_string = transport.get_bytes("format")
3091
3077
            return format_registry.get(format_string)
3092
3078
        except errors.NoSuchFile:
3093
3079
            raise errors.NoRepositoryPresent(a_bzrdir)
3192
3178
        """
3193
3179
        raise NotImplementedError(self.open)
3194
3180
 
 
3181
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
 
3182
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
 
3183
        hooks = BzrDir.hooks['post_repo_init']
 
3184
        if not hooks:
 
3185
            return
 
3186
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
 
3187
        for hook in hooks:
 
3188
            hook(params)
 
3189
 
3195
3190
 
3196
3191
class MetaDirRepositoryFormat(RepositoryFormat):
3197
3192
    """Common base class for the new repositories using the metadir layout."""
3402
3397
 
3403
3398
        :param revision_id: if None all content is copied, if NULL_REVISION no
3404
3399
                            content is copied.
3405
 
        :param pb: optional progress bar to use for progress reports. If not
3406
 
                   provided a default one will be created.
 
3400
        :param pb: ignored.
3407
3401
        :return: None.
3408
3402
        """
 
3403
        ui.ui_factory.warn_experimental_format_fetch(self)
3409
3404
        from bzrlib.fetch import RepoFetcher
 
3405
        # See <https://launchpad.net/bugs/456077> asking for a warning here
 
3406
        if self.source._format.network_name() != self.target._format.network_name():
 
3407
            ui.ui_factory.show_user_warning('cross_format_fetch',
 
3408
                from_format=self.source._format,
 
3409
                to_format=self.target._format)
3410
3410
        f = RepoFetcher(to_repository=self.target,
3411
3411
                               from_repository=self.source,
3412
3412
                               last_revision=revision_id,
3413
3413
                               fetch_spec=fetch_spec,
3414
 
                               pb=pb, find_ghosts=find_ghosts)
 
3414
                               find_ghosts=find_ghosts)
3415
3415
 
3416
3416
    def _walk_to_common_revisions(self, revision_ids):
3417
3417
        """Walk out from revision_ids in source to revisions target has.
3586
3586
                self.target.texts.insert_record_stream(
3587
3587
                    self.source.texts.get_record_stream(
3588
3588
                        self.source.texts.keys(), 'topological', False))
3589
 
                pb.update('copying inventory', 0, 1)
 
3589
                pb.update('Copying inventory', 0, 1)
3590
3590
                self.target.inventories.insert_record_stream(
3591
3591
                    self.source.inventories.get_record_stream(
3592
3592
                        self.source.inventories.keys(), 'topological', False))
3813
3813
                basis_id, delta, current_revision_id, parents_parents)
3814
3814
            cache[current_revision_id] = parent_tree
3815
3815
 
3816
 
    def _fetch_batch(self, revision_ids, basis_id, cache):
 
3816
    def _fetch_batch(self, revision_ids, basis_id, cache, a_graph=None):
3817
3817
        """Fetch across a few revisions.
3818
3818
 
3819
3819
        :param revision_ids: The revisions to copy
3820
3820
        :param basis_id: The revision_id of a tree that must be in cache, used
3821
3821
            as a basis for delta when no other base is available
3822
3822
        :param cache: A cache of RevisionTrees that we can use.
 
3823
        :param a_graph: A Graph object to determine the heads() of the
 
3824
            rich-root data stream.
3823
3825
        :return: The revision_id of the last converted tree. The RevisionTree
3824
3826
            for it will be in cache
3825
3827
        """
3832
3834
        pending_revisions = []
3833
3835
        parent_map = self.source.get_parent_map(revision_ids)
3834
3836
        self._fetch_parent_invs_for_stacking(parent_map, cache)
 
3837
        self.source._safe_to_return_from_cache = True
3835
3838
        for tree in self.source.revision_trees(revision_ids):
3836
3839
            # Find a inventory delta for this revision.
3837
3840
            # Find text entries that need to be copied, too.
3885
3888
            pending_revisions.append(revision)
3886
3889
            cache[current_revision_id] = tree
3887
3890
            basis_id = current_revision_id
 
3891
        self.source._safe_to_return_from_cache = False
3888
3892
        # Copy file texts
3889
3893
        from_texts = self.source.texts
3890
3894
        to_texts = self.target.texts
3891
3895
        if root_keys_to_create:
3892
 
            from bzrlib.fetch import _new_root_data_stream
3893
 
            root_stream = _new_root_data_stream(
 
3896
            root_stream = _mod_fetch._new_root_data_stream(
3894
3897
                root_keys_to_create, self._revision_id_to_root_id, parent_map,
3895
 
                self.source)
 
3898
                self.source, graph=a_graph)
3896
3899
            to_texts.insert_record_stream(root_stream)
3897
3900
        to_texts.insert_record_stream(from_texts.get_record_stream(
3898
3901
            text_keys, self.target._format._fetch_order,
3955
3958
        cache[basis_id] = basis_tree
3956
3959
        del basis_tree # We don't want to hang on to it here
3957
3960
        hints = []
 
3961
        if self._converting_to_rich_root and len(revision_ids) > 100:
 
3962
            a_graph = _mod_fetch._get_rich_root_heads_graph(self.source,
 
3963
                                                            revision_ids)
 
3964
        else:
 
3965
            a_graph = None
 
3966
 
3958
3967
        for offset in range(0, len(revision_ids), batch_size):
3959
3968
            self.target.start_write_group()
3960
3969
            try:
3961
3970
                pb.update('Transferring revisions', offset,
3962
3971
                          len(revision_ids))
3963
3972
                batch = revision_ids[offset:offset+batch_size]
3964
 
                basis_id = self._fetch_batch(batch, basis_id, cache)
 
3973
                basis_id = self._fetch_batch(batch, basis_id, cache,
 
3974
                                             a_graph=a_graph)
3965
3975
            except:
 
3976
                self.source._safe_to_return_from_cache = False
3966
3977
                self.target.abort_write_group()
3967
3978
                raise
3968
3979
            else:
3980
3991
        """See InterRepository.fetch()."""
3981
3992
        if fetch_spec is not None:
3982
3993
            raise AssertionError("Not implemented yet...")
3983
 
        # See <https://launchpad.net/bugs/456077> asking for a warning here
3984
 
        #
3985
 
        # nb this is only active for local-local fetches; other things using
3986
 
        # streaming.
3987
 
        ui.ui_factory.warn_cross_format_fetch(self.source._format,
3988
 
            self.target._format)
 
3994
        ui.ui_factory.warn_experimental_format_fetch(self)
3989
3995
        if (not self.source.supports_rich_root()
3990
3996
            and self.target.supports_rich_root()):
3991
3997
            self._converting_to_rich_root = True
3992
3998
            self._revision_id_to_root_id = {}
3993
3999
        else:
3994
4000
            self._converting_to_rich_root = False
 
4001
        # See <https://launchpad.net/bugs/456077> asking for a warning here
 
4002
        if self.source._format.network_name() != self.target._format.network_name():
 
4003
            ui.ui_factory.show_user_warning('cross_format_fetch',
 
4004
                from_format=self.source._format,
 
4005
                to_format=self.target._format)
3995
4006
        revision_ids = self.target.search_missing_revision_ids(self.source,
3996
4007
            revision_id, find_ghosts=find_ghosts).get_keys()
3997
4008
        if not revision_ids:
4066
4077
        :param to_convert: The disk object to convert.
4067
4078
        :param pb: a progress bar to use for progress information.
4068
4079
        """
4069
 
        self.pb = pb
 
4080
        pb = ui.ui_factory.nested_progress_bar()
4070
4081
        self.count = 0
4071
4082
        self.total = 4
4072
4083
        # this is only useful with metadir layouts - separated repo content.
4073
4084
        # trigger an assertion if not such
4074
4085
        repo._format.get_format_string()
4075
4086
        self.repo_dir = repo.bzrdir
4076
 
        self.step('Moving repository to repository.backup')
 
4087
        pb.update('Moving repository to repository.backup')
4077
4088
        self.repo_dir.transport.move('repository', 'repository.backup')
4078
4089
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
4079
4090
        repo._format.check_conversion_target(self.target_format)
4080
4091
        self.source_repo = repo._format.open(self.repo_dir,
4081
4092
            _found=True,
4082
4093
            _override_transport=backup_transport)
4083
 
        self.step('Creating new repository')
 
4094
        pb.update('Creating new repository')
4084
4095
        converted = self.target_format.initialize(self.repo_dir,
4085
4096
                                                  self.source_repo.is_shared())
4086
4097
        converted.lock_write()
4087
4098
        try:
4088
 
            self.step('Copying content into repository.')
 
4099
            pb.update('Copying content')
4089
4100
            self.source_repo.copy_content_into(converted)
4090
4101
        finally:
4091
4102
            converted.unlock()
4092
 
        self.step('Deleting old repository content.')
 
4103
        pb.update('Deleting old repository content')
4093
4104
        self.repo_dir.transport.delete_tree('repository.backup')
4094
 
        self.pb.note('repository converted')
4095
 
 
4096
 
    def step(self, message):
4097
 
        """Update the pb by a step."""
4098
 
        self.count +=1
4099
 
        self.pb.update(message, self.count, self.total)
 
4105
        ui.ui_factory.note('repository converted')
 
4106
        pb.finished()
4100
4107
 
4101
4108
 
4102
4109
_unescape_map = {
4284
4291
                    self._extract_and_insert_inventories(
4285
4292
                        substream, src_serializer)
4286
4293
            elif substream_type == 'inventory-deltas':
4287
 
                ui.ui_factory.warn_cross_format_fetch(src_format,
4288
 
                    self.target_repo._format)
4289
4294
                self._extract_and_insert_inventory_deltas(
4290
4295
                    substream, src_serializer)
4291
4296
            elif substream_type == 'chk_bytes':
4324
4329
                ):
4325
4330
                if versioned_file is None:
4326
4331
                    continue
 
4332
                # TODO: key is often going to be a StaticTuple object
 
4333
                #       I don't believe we can define a method by which
 
4334
                #       (prefix,) + StaticTuple will work, though we could
 
4335
                #       define a StaticTuple.sq_concat that would allow you to
 
4336
                #       pass in either a tuple or a StaticTuple as the second
 
4337
                #       object, so instead we could have:
 
4338
                #       StaticTuple(prefix) + key here...
4327
4339
                missing_keys.update((prefix,) + key for key in
4328
4340
                    versioned_file.get_missing_compression_parent_keys())
4329
4341
        except NotImplementedError:
4441
4453
        fetching the inventory weave.
4442
4454
        """
4443
4455
        if self._rich_root_upgrade():
4444
 
            import bzrlib.fetch
4445
 
            return bzrlib.fetch.Inter1and2Helper(
 
4456
            return _mod_fetch.Inter1and2Helper(
4446
4457
                self.from_repository).generate_root_texts(revs)
4447
4458
        else:
4448
4459
            return []