~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

Abbreviate pack_stat struct format to '>6L'

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
    NoSuchRevision,
41
41
    SmartProtocolError,
42
42
    )
 
43
from bzrlib.i18n import gettext
43
44
from bzrlib.lockable_files import LockableFiles
44
45
from bzrlib.smart import client, vfs, repository as smart_repo
45
46
from bzrlib.smart.client import _SmartClient
48
49
from bzrlib.trace import mutter, note, warning
49
50
 
50
51
 
 
52
_DEFAULT_SEARCH_DEPTH = 100
 
53
 
 
54
 
51
55
class _RpcHelper(object):
52
56
    """Mixin class that helps with issuing RPCs."""
53
57
 
483
487
        self._ensure_real()
484
488
        self._real_bzrdir.destroy_repository()
485
489
 
486
 
    def create_branch(self, name=None, repository=None):
 
490
    def create_branch(self, name=None, repository=None,
 
491
                      append_revisions_only=None):
487
492
        # as per meta1 formats - just delegate to the format object which may
488
493
        # be parameterised.
489
494
        real_branch = self._format.get_branch_format().initialize(self,
490
 
            name=name, repository=repository)
 
495
            name=name, repository=repository,
 
496
            append_revisions_only=append_revisions_only)
491
497
        if not isinstance(real_branch, RemoteBranch):
492
498
            if not isinstance(repository, RemoteRepository):
493
499
                raise AssertionError(
669
675
 
670
676
    def _path_for_remote_call(self, client):
671
677
        """Return the path to be used for this bzrdir in a remote call."""
672
 
        return client.remote_path_from_transport(self.root_transport)
 
678
        return urlutils.split_segment_parameters_raw(
 
679
            client.remote_path_from_transport(self.root_transport))[0]
673
680
 
674
681
    def get_branch_transport(self, branch_format, name=None):
675
682
        self._ensure_real()
735
742
        self._supports_external_lookups = None
736
743
        self._supports_tree_reference = None
737
744
        self._supports_funky_characters = None
 
745
        self._supports_nesting_repositories = None
738
746
        self._rich_root_data = None
739
747
 
740
748
    def __repr__(self):
777
785
        return self._supports_funky_characters
778
786
 
779
787
    @property
 
788
    def supports_nesting_repositories(self):
 
789
        if self._supports_nesting_repositories is None:
 
790
            self._ensure_real()
 
791
            self._supports_nesting_repositories = \
 
792
                self._custom_format.supports_nesting_repositories
 
793
        return self._supports_nesting_repositories
 
794
 
 
795
    @property
780
796
    def supports_tree_reference(self):
781
797
        if self._supports_tree_reference is None:
782
798
            self._ensure_real()
1080
1096
    def find_text_key_references(self):
1081
1097
        """Find the text key references within the repository.
1082
1098
 
1083
 
        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
1084
 
        revision_ids. Each altered file-ids has the exact revision_ids that
1085
 
        altered it listed explicitly.
1086
1099
        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
1087
1100
            to whether they were referred to by the inventory of the
1088
1101
            revision_id that they contain. The inventory texts from all present
1136
1149
        return RemoteStreamSource(self, to_format)
1137
1150
 
1138
1151
    @needs_read_lock
 
1152
    def get_file_graph(self):
 
1153
        return graph.Graph(self.texts)
 
1154
 
 
1155
    @needs_read_lock
1139
1156
    def has_revision(self, revision_id):
1140
1157
        """True if this repository has a copy of the revision."""
1141
1158
        # Copy of bzrlib.repository.Repository.has_revision
1504
1521
        # We need to accumulate additional repositories here, to pass them in
1505
1522
        # on various RPC's.
1506
1523
        #
 
1524
        # Make the check before we lock: this raises an exception.
 
1525
        self._check_fallback_repository(repository)
1507
1526
        if self.is_locked():
1508
1527
            # We will call fallback.unlock() when we transition to the unlocked
1509
1528
            # state, so always add a lock here. If a caller passes us a locked
1510
1529
            # repository, they are responsible for unlocking it later.
1511
1530
            repository.lock_read()
1512
 
        self._check_fallback_repository(repository)
1513
1531
        self._fallback_repositories.append(repository)
1514
1532
        # If self._real_repository was parameterised already (e.g. because a
1515
1533
        # _real_branch had its get_stacked_on_url method called), then the
1604
1622
    @needs_read_lock
1605
1623
    def search_missing_revision_ids(self, other,
1606
1624
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1607
 
            find_ghosts=True, revision_ids=None, if_present_ids=None):
 
1625
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
1626
            limit=None):
1608
1627
        """Return the revision ids that other has that this does not.
1609
1628
 
1610
1629
        These are returned in topological order.
1624
1643
        inter_repo = _mod_repository.InterRepository.get(other, self)
1625
1644
        return inter_repo.search_missing_revision_ids(
1626
1645
            find_ghosts=find_ghosts, revision_ids=revision_ids,
1627
 
            if_present_ids=if_present_ids)
 
1646
            if_present_ids=if_present_ids, limit=limit)
1628
1647
 
1629
1648
    def fetch(self, source, revision_id=None, find_ghosts=False,
1630
1649
            fetch_spec=None):
1658
1677
        self._real_repository.create_bundle(target, base, fileobj, format)
1659
1678
 
1660
1679
    @needs_read_lock
 
1680
    @symbol_versioning.deprecated_method(
 
1681
        symbol_versioning.deprecated_in((2, 4, 0)))
1661
1682
    def get_ancestry(self, revision_id, topo_sorted=True):
1662
1683
        self._ensure_real()
1663
1684
        return self._real_repository.get_ancestry(revision_id, topo_sorted)
1677
1698
        self._ensure_real()
1678
1699
        return self._real_repository.iter_files_bytes(desired_files)
1679
1700
 
 
1701
    def get_cached_parent_map(self, revision_ids):
 
1702
        """See bzrlib.CachingParentsProvider.get_cached_parent_map"""
 
1703
        return self._unstacked_provider.get_cached_parent_map(revision_ids)
 
1704
 
1680
1705
    def get_parent_map(self, revision_ids):
1681
1706
        """See bzrlib.Graph.get_parent_map()."""
1682
1707
        return self._make_parents_provider().get_parent_map(revision_ids)
1740
1765
        if parents_map is None:
1741
1766
            # Repository is not locked, so there's no cache.
1742
1767
            parents_map = {}
1743
 
        # start_set is all the keys in the cache
1744
 
        start_set = set(parents_map)
1745
 
        # result set is all the references to keys in the cache
1746
 
        result_parents = set()
1747
 
        for parents in parents_map.itervalues():
1748
 
            result_parents.update(parents)
1749
 
        stop_keys = result_parents.difference(start_set)
1750
 
        # We don't need to send ghosts back to the server as a position to
1751
 
        # stop either.
1752
 
        stop_keys.difference_update(self._unstacked_provider.missing_keys)
1753
 
        key_count = len(parents_map)
1754
 
        if (NULL_REVISION in result_parents
1755
 
            and NULL_REVISION in self._unstacked_provider.missing_keys):
1756
 
            # If we pruned NULL_REVISION from the stop_keys because it's also
1757
 
            # in our cache of "missing" keys we need to increment our key count
1758
 
            # by 1, because the reconsitituted SearchResult on the server will
1759
 
            # still consider NULL_REVISION to be an included key.
1760
 
            key_count += 1
1761
 
        included_keys = start_set.intersection(result_parents)
1762
 
        start_set.difference_update(included_keys)
 
1768
        if _DEFAULT_SEARCH_DEPTH <= 0:
 
1769
            (start_set, stop_keys,
 
1770
             key_count) = graph.search_result_from_parent_map(
 
1771
                parents_map, self._unstacked_provider.missing_keys)
 
1772
        else:
 
1773
            (start_set, stop_keys,
 
1774
             key_count) = graph.limited_search_result_from_parent_map(
 
1775
                parents_map, self._unstacked_provider.missing_keys,
 
1776
                keys, depth=_DEFAULT_SEARCH_DEPTH)
1763
1777
        recipe = ('manual', start_set, stop_keys, key_count)
1764
1778
        body = self._serialise_search_recipe(recipe)
1765
1779
        path = self.bzrdir._path_for_remote_call(self._client)
1869
1883
        from bzrlib import osutils
1870
1884
        import tarfile
1871
1885
        # TODO: Maybe a progress bar while streaming the tarball?
1872
 
        note("Copying repository content as tarball...")
 
1886
        note(gettext("Copying repository content as tarball..."))
1873
1887
        tar_file = self._get_tarball('bz2')
1874
1888
        if tar_file is None:
1875
1889
            return None
1971
1985
    def supports_rich_root(self):
1972
1986
        return self._format.rich_root_data
1973
1987
 
 
1988
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1974
1989
    def iter_reverse_revision_history(self, revision_id):
1975
1990
        self._ensure_real()
1976
1991
        return self._real_repository.iter_reverse_revision_history(revision_id)
2348
2363
        return a_bzrdir.open_branch(name=name, 
2349
2364
            ignore_fallbacks=ignore_fallbacks)
2350
2365
 
2351
 
    def _vfs_initialize(self, a_bzrdir, name):
 
2366
    def _vfs_initialize(self, a_bzrdir, name, append_revisions_only):
2352
2367
        # Initialisation when using a local bzrdir object, or a non-vfs init
2353
2368
        # method is not available on the server.
2354
2369
        # self._custom_format is always set - the start of initialize ensures
2356
2371
        if isinstance(a_bzrdir, RemoteBzrDir):
2357
2372
            a_bzrdir._ensure_real()
2358
2373
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2359
 
                name)
 
2374
                name, append_revisions_only=append_revisions_only)
2360
2375
        else:
2361
2376
            # We assume the bzrdir is parameterised; it may not be.
2362
 
            result = self._custom_format.initialize(a_bzrdir, name)
 
2377
            result = self._custom_format.initialize(a_bzrdir, name,
 
2378
                append_revisions_only=append_revisions_only)
2363
2379
        if (isinstance(a_bzrdir, RemoteBzrDir) and
2364
2380
            not isinstance(result, RemoteBranch)):
2365
2381
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2366
2382
                                  name=name)
2367
2383
        return result
2368
2384
 
2369
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2385
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2386
                   append_revisions_only=None):
2370
2387
        # 1) get the network name to use.
2371
2388
        if self._custom_format:
2372
2389
            network_name = self._custom_format.network_name()
2378
2395
            network_name = reference_format.network_name()
2379
2396
        # Being asked to create on a non RemoteBzrDir:
2380
2397
        if not isinstance(a_bzrdir, RemoteBzrDir):
2381
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2398
            return self._vfs_initialize(a_bzrdir, name=name,
 
2399
                append_revisions_only=append_revisions_only)
2382
2400
        medium = a_bzrdir._client._medium
2383
2401
        if medium._is_remote_before((1, 13)):
2384
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2402
            return self._vfs_initialize(a_bzrdir, name=name,
 
2403
                append_revisions_only=append_revisions_only)
2385
2404
        # Creating on a remote bzr dir.
2386
2405
        # 2) try direct creation via RPC
2387
2406
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2394
2413
        except errors.UnknownSmartMethod:
2395
2414
            # Fallback - use vfs methods
2396
2415
            medium._remember_remote_is_before((1, 13))
2397
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2416
            return self._vfs_initialize(a_bzrdir, name=name,
 
2417
                    append_revisions_only=append_revisions_only)
2398
2418
        if response[0] != 'ok':
2399
2419
            raise errors.UnexpectedSmartServerResponse(response)
2400
2420
        # Turn the response into a RemoteRepository object.
2421
2441
            remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2422
2442
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2423
2443
            format=format, setup_stacking=False, name=name)
 
2444
        if append_revisions_only:
 
2445
            remote_branch.set_append_revisions_only(append_revisions_only)
2424
2446
        # XXX: We know this is a new branch, so it must have revno 0, revid
2425
2447
        # NULL_REVISION. Creating the branch locked would make this be unable
2426
2448
        # to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2621
2643
                self.bzrdir, self._client)
2622
2644
        return self._control_files
2623
2645
 
2624
 
    def _get_checkout_format(self):
 
2646
    def _get_checkout_format(self, lightweight=False):
2625
2647
        self._ensure_real()
2626
 
        return self._real_branch._get_checkout_format()
 
2648
        if lightweight:
 
2649
            format = RemoteBzrDirFormat()
 
2650
            self.bzrdir._format._supply_sub_formats_to(format)
 
2651
            format.workingtree_format = self._real_branch._get_checkout_format(
 
2652
                lightweight=lightweight).workingtree_format
 
2653
            return format
 
2654
        else:
 
2655
            return self._real_branch._get_checkout_format(lightweight=False)
2627
2656
 
2628
2657
    def get_physical_lock_status(self):
2629
2658
        """See Branch.get_physical_lock_status()."""
2990
3019
            _override_hook_target=self, **kwargs)
2991
3020
 
2992
3021
    @needs_read_lock
2993
 
    def push(self, target, overwrite=False, stop_revision=None):
 
3022
    def push(self, target, overwrite=False, stop_revision=None, lossy=False):
2994
3023
        self._ensure_real()
2995
3024
        return self._real_branch.push(
2996
 
            target, overwrite=overwrite, stop_revision=stop_revision,
 
3025
            target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
2997
3026
            _override_hook_source_branch=self)
2998
3027
 
2999
3028
    def is_locked(self):
3098
3127
        """
3099
3128
        try:
3100
3129
            configobj = self._get_configobj()
 
3130
            section_obj = None
3101
3131
            if section is None:
3102
3132
                section_obj = configobj
3103
3133
            else:
3104
3134
                try:
3105
3135
                    section_obj = configobj[section]
3106
3136
                except KeyError:
3107
 
                    return default
3108
 
            return section_obj.get(name, default)
 
3137
                    pass
 
3138
            if section_obj is None:
 
3139
                value = default
 
3140
            else:
 
3141
                value = section_obj.get(name, default)
3109
3142
        except errors.UnknownSmartMethod:
3110
 
            return self._vfs_get_option(name, section, default)
 
3143
            value = self._vfs_get_option(name, section, default)
 
3144
        for hook in config.OldConfigHooks['get']:
 
3145
            hook(self, name, value)
 
3146
        return value
3111
3147
 
3112
3148
    def _response_to_configobj(self, response):
3113
3149
        if len(response[0]) and response[0][0] != 'ok':
3114
3150
            raise errors.UnexpectedSmartServerResponse(response)
3115
3151
        lines = response[1].read_body_bytes().splitlines()
3116
 
        return config.ConfigObj(lines, encoding='utf-8')
 
3152
        conf = config.ConfigObj(lines, encoding='utf-8')
 
3153
        for hook in config.OldConfigHooks['load']:
 
3154
            hook(self)
 
3155
        return conf
3117
3156
 
3118
3157
 
3119
3158
class RemoteBranchConfig(RemoteConfig):