~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Vincent Ladeuil
  • Date: 2011-12-08 09:24:06 UTC
  • mto: This revision was merged to the branch mainline in revision 6351.
  • Revision ID: v.ladeuil+lp@free.fr-20111208092406-ueqyyoftzwk22bq4
Open 2.5b5 for bug fixes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2012 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
import bz2
20
18
import zlib
21
19
 
23
21
    bencode,
24
22
    branch,
25
23
    bzrdir as _mod_bzrdir,
26
 
    config as _mod_config,
 
24
    config,
27
25
    controldir,
28
26
    debug,
29
27
    errors,
30
28
    gpg,
31
29
    graph,
32
 
    inventory_delta,
33
30
    lock,
34
31
    lockdir,
35
32
    osutils,
59
56
from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin
60
57
from bzrlib.serializer import format_registry as serializer_format_registry
61
58
from bzrlib.trace import mutter, note, warning, log_exception_quietly
62
 
from bzrlib.versionedfile import FulltextContentFactory
63
59
 
64
60
 
65
61
_DEFAULT_SEARCH_DEPTH = 100
113
109
 
114
110
    supports_workingtrees = False
115
111
 
116
 
    colocated_branches = False
117
 
 
118
112
    def __init__(self):
119
113
        _mod_bzrdir.BzrDirMetaFormat1.__init__(self)
120
114
        # XXX: It's a bit ugly that the network name is here, because we'd
351
345
        _mod_bzrdir.BzrDirMetaFormat1._set_repository_format) #.im_func)
352
346
 
353
347
 
354
 
class RemoteControlStore(_mod_config.IniFileStore):
 
348
class RemoteControlStore(config.IniFileStore):
355
349
    """Control store which attempts to use HPSS calls to retrieve control store.
356
350
 
357
351
    Note that this is specific to bzr-based formats.
381
375
    def _ensure_real(self):
382
376
        self.bzrdir._ensure_real()
383
377
        if self._real_store is None:
384
 
            self._real_store = _mod_config.ControlStore(self.bzrdir)
 
378
            self._real_store = config.ControlStore(self.bzrdir)
385
379
 
386
380
    def external_url(self):
387
381
        return self.bzrdir.user_url
483
477
                warning('VFS BzrDir access triggered\n%s',
484
478
                    ''.join(traceback.format_stack()))
485
479
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
486
 
                self.root_transport, probers=[_mod_bzrdir.BzrProber])
 
480
                self.root_transport, _server_formats=False)
487
481
            self._format._network_name = \
488
482
                self._real_bzrdir._format.network_name()
489
483
 
496
490
        self._next_open_branch_result = None
497
491
        return _mod_bzrdir.BzrDir.break_lock(self)
498
492
 
499
 
    def _vfs_checkout_metadir(self):
500
 
        self._ensure_real()
501
 
        return self._real_bzrdir.checkout_metadir()
502
 
 
503
 
    def checkout_metadir(self):
504
 
        """Retrieve the controldir format to use for checkouts of this one.
505
 
        """
506
 
        medium = self._client._medium
507
 
        if medium._is_remote_before((2, 5)):
508
 
            return self._vfs_checkout_metadir()
509
 
        path = self._path_for_remote_call(self._client)
510
 
        try:
511
 
            response = self._client.call('BzrDir.checkout_metadir',
512
 
                path)
513
 
        except errors.UnknownSmartMethod:
514
 
            medium._remember_remote_is_before((2, 5))
515
 
            return self._vfs_checkout_metadir()
516
 
        if len(response) != 3:
517
 
            raise errors.UnexpectedSmartServerResponse(response)
518
 
        control_name, repo_name, branch_name = response
519
 
        try:
520
 
            format = controldir.network_format_registry.get(control_name)
521
 
        except KeyError:
522
 
            raise errors.UnknownFormatError(kind='control',
523
 
                format=control_name)
524
 
        if repo_name:
525
 
            try:
526
 
                repo_format = _mod_repository.network_format_registry.get(
527
 
                    repo_name)
528
 
            except KeyError:
529
 
                raise errors.UnknownFormatError(kind='repository',
530
 
                    format=repo_name)
531
 
            format.repository_format = repo_format
532
 
        if branch_name:
533
 
            try:
534
 
                format.set_branch_format(
535
 
                    branch.network_format_registry.get(branch_name))
536
 
            except KeyError:
537
 
                raise errors.UnknownFormatError(kind='branch',
538
 
                    format=branch_name)
539
 
        return format
540
 
 
541
493
    def _vfs_cloning_metadir(self, require_stacking=False):
542
494
        self._ensure_real()
543
495
        return self._real_bzrdir.cloning_metadir(
627
579
 
628
580
    def create_branch(self, name=None, repository=None,
629
581
                      append_revisions_only=None):
630
 
        if name is None:
631
 
            name = self._get_selected_branch()
632
 
        if name != "":
633
 
            raise errors.NoColocatedBranchSupport(self)
634
582
        # as per meta1 formats - just delegate to the format object which may
635
583
        # be parameterised.
636
584
        real_branch = self._format.get_branch_format().initialize(self,
655
603
 
656
604
    def destroy_branch(self, name=None):
657
605
        """See BzrDir.destroy_branch"""
658
 
        if name is None:
659
 
            name = self._get_selected_branch()
660
 
        if name != "":
661
 
            raise errors.NoColocatedBranchSupport(self)
662
606
        path = self._path_for_remote_call(self._client)
663
607
        try:
664
 
            if name != "":
 
608
            if name is not None:
665
609
                args = (name, )
666
610
            else:
667
611
                args = ()
687
631
        b = self.open_branch(name=name)
688
632
        return b._format
689
633
 
690
 
    def get_branches(self, possible_transports=None, ignore_fallbacks=False):
691
 
        path = self._path_for_remote_call(self._client)
692
 
        try:
693
 
            response, handler = self._call_expecting_body(
694
 
                'BzrDir.get_branches', path)
695
 
        except errors.UnknownSmartMethod:
696
 
            self._ensure_real()
697
 
            return self._real_bzrdir.get_branches()
698
 
        if response[0] != "success":
699
 
            raise errors.UnexpectedSmartServerResponse(response)
700
 
        body = bencode.bdecode(handler.read_body_bytes())
701
 
        ret = {}
702
 
        for (name, value) in body.iteritems():
703
 
            ret[name] = self._open_branch(name, value[0], value[1],
704
 
                possible_transports=possible_transports,
705
 
                ignore_fallbacks=ignore_fallbacks)
706
 
        return ret
707
 
 
708
 
    def set_branch_reference(self, target_branch, name=None):
709
 
        """See BzrDir.set_branch_reference()."""
710
 
        if name is None:
711
 
            name = self._get_selected_branch()
712
 
        if name != "":
713
 
            raise errors.NoColocatedBranchSupport(self)
714
 
        self._ensure_real()
715
 
        return self._real_bzrdir.set_branch_reference(target_branch, name=name)
716
 
 
717
634
    def get_branch_reference(self, name=None):
718
635
        """See BzrDir.get_branch_reference()."""
719
 
        if name is None:
720
 
            name = self._get_selected_branch()
721
 
        if name != "":
 
636
        if name is not None:
 
637
            # XXX JRV20100304: Support opening colocated branches
722
638
            raise errors.NoColocatedBranchSupport(self)
723
639
        response = self._get_branch_reference()
724
640
        if response[0] == 'ref':
760
676
        """See BzrDir._get_tree_branch()."""
761
677
        return None, self.open_branch(name=name)
762
678
 
763
 
    def _open_branch(self, name, kind, location_or_format,
764
 
                     ignore_fallbacks=False, possible_transports=None):
765
 
        if kind == 'ref':
 
679
    def open_branch(self, name=None, unsupported=False,
 
680
                    ignore_fallbacks=False, possible_transports=None):
 
681
        if unsupported:
 
682
            raise NotImplementedError('unsupported flag support not implemented yet.')
 
683
        if self._next_open_branch_result is not None:
 
684
            # See create_branch for details.
 
685
            result = self._next_open_branch_result
 
686
            self._next_open_branch_result = None
 
687
            return result
 
688
        response = self._get_branch_reference()
 
689
        if response[0] == 'ref':
766
690
            # a branch reference, use the existing BranchReference logic.
767
691
            format = BranchReferenceFormat()
768
692
            return format.open(self, name=name, _found=True,
769
 
                location=location_or_format, ignore_fallbacks=ignore_fallbacks,
 
693
                location=response[1], ignore_fallbacks=ignore_fallbacks,
770
694
                possible_transports=possible_transports)
771
 
        branch_format_name = location_or_format
 
695
        branch_format_name = response[1]
772
696
        if not branch_format_name:
773
697
            branch_format_name = None
774
698
        format = RemoteBranchFormat(network_name=branch_format_name)
776
700
            setup_stacking=not ignore_fallbacks, name=name,
777
701
            possible_transports=possible_transports)
778
702
 
779
 
    def open_branch(self, name=None, unsupported=False,
780
 
                    ignore_fallbacks=False, possible_transports=None):
781
 
        if name is None:
782
 
            name = self._get_selected_branch()
783
 
        if name != "":
784
 
            raise errors.NoColocatedBranchSupport(self)
785
 
        if unsupported:
786
 
            raise NotImplementedError('unsupported flag support not implemented yet.')
787
 
        if self._next_open_branch_result is not None:
788
 
            # See create_branch for details.
789
 
            result = self._next_open_branch_result
790
 
            self._next_open_branch_result = None
791
 
            return result
792
 
        response = self._get_branch_reference()
793
 
        return self._open_branch(name, response[0], response[1],
794
 
            possible_transports=possible_transports,
795
 
            ignore_fallbacks=ignore_fallbacks)
796
 
 
797
703
    def _open_repo_v1(self, path):
798
704
        verb = 'BzrDir.find_repository'
799
705
        response = self._call(verb, path)
1260
1166
        if response != ('ok', ):
1261
1167
            raise errors.UnexpectedSmartServerResponse(response)
1262
1168
        self._write_group_tokens = None
1263
 
        # Refresh data after writing to the repository.
1264
 
        self.refresh_data()
1265
1169
 
1266
1170
    def resume_write_group(self, tokens):
1267
1171
        if self._real_repository:
1816
1720
    def get_commit_builder(self, branch, parents, config, timestamp=None,
1817
1721
                           timezone=None, committer=None, revprops=None,
1818
1722
                           revision_id=None, lossy=False):
1819
 
        """Obtain a CommitBuilder for this repository.
1820
 
 
1821
 
        :param branch: Branch to commit to.
1822
 
        :param parents: Revision ids of the parents of the new revision.
1823
 
        :param config: Configuration to use.
1824
 
        :param timestamp: Optional timestamp recorded for commit.
1825
 
        :param timezone: Optional timezone for timestamp.
1826
 
        :param committer: Optional committer to set for commit.
1827
 
        :param revprops: Optional dictionary of revision properties.
1828
 
        :param revision_id: Optional revision id.
1829
 
        :param lossy: Whether to discard data that can not be natively
1830
 
            represented, when pushing to a foreign VCS
1831
 
        """
1832
 
        if self._fallback_repositories and not self._format.supports_chks:
1833
 
            raise errors.BzrError("Cannot commit directly to a stacked branch"
1834
 
                " in pre-2a formats. See "
1835
 
                "https://bugs.launchpad.net/bzr/+bug/375013 for details.")
1836
 
        if self._format.rich_root_data:
1837
 
            commit_builder_kls = vf_repository.VersionedFileRootCommitBuilder
1838
 
        else:
1839
 
            commit_builder_kls = vf_repository.VersionedFileCommitBuilder
1840
 
        result = commit_builder_kls(self, parents, config,
1841
 
            timestamp, timezone, committer, revprops, revision_id,
1842
 
            lossy)
1843
 
        self.start_write_group()
1844
 
        return result
 
1723
        # FIXME: It ought to be possible to call this without immediately
 
1724
        # triggering _ensure_real.  For now it's the easiest thing to do.
 
1725
        self._ensure_real()
 
1726
        real_repo = self._real_repository
 
1727
        builder = real_repo.get_commit_builder(branch, parents,
 
1728
                config, timestamp=timestamp, timezone=timezone,
 
1729
                committer=committer, revprops=revprops,
 
1730
                revision_id=revision_id, lossy=lossy)
 
1731
        return builder
1845
1732
 
1846
1733
    def add_fallback_repository(self, repository):
1847
1734
        """Add a repository to use for looking up data not held locally.
1892
1779
            delta, new_revision_id, parents, basis_inv=basis_inv,
1893
1780
            propagate_caches=propagate_caches)
1894
1781
 
1895
 
    def add_revision(self, revision_id, rev, inv=None):
1896
 
        _mod_revision.check_not_reserved_id(revision_id)
1897
 
        key = (revision_id,)
1898
 
        # check inventory present
1899
 
        if not self.inventories.get_parent_map([key]):
1900
 
            if inv is None:
1901
 
                raise errors.WeaveRevisionNotPresent(revision_id,
1902
 
                                                     self.inventories)
1903
 
            else:
1904
 
                # yes, this is not suitable for adding with ghosts.
1905
 
                rev.inventory_sha1 = self.add_inventory(revision_id, inv,
1906
 
                                                        rev.parent_ids)
1907
 
        else:
1908
 
            rev.inventory_sha1 = self.inventories.get_sha1s([key])[key]
1909
 
        self._add_revision(rev)
1910
 
 
1911
 
    def _add_revision(self, rev):
1912
 
        if self._real_repository is not None:
1913
 
            return self._real_repository._add_revision(rev)
1914
 
        text = self._serializer.write_revision_to_string(rev)
1915
 
        key = (rev.revision_id,)
1916
 
        parents = tuple((parent,) for parent in rev.parent_ids)
1917
 
        self._write_group_tokens, missing_keys = self._get_sink().insert_stream(
1918
 
            [('revisions', [FulltextContentFactory(key, parents, None, text)])],
1919
 
            self._format, self._write_group_tokens)
 
1782
    def add_revision(self, rev_id, rev, inv=None, config=None):
 
1783
        self._ensure_real()
 
1784
        return self._real_repository.add_revision(
 
1785
            rev_id, rev, inv=inv, config=config)
1920
1786
 
1921
1787
    @needs_read_lock
1922
1788
    def get_inventory(self, revision_id):
1923
1789
        return list(self.iter_inventories([revision_id]))[0]
1924
1790
 
1925
 
    def _iter_inventories_rpc(self, revision_ids, ordering):
1926
 
        if ordering is None:
1927
 
            ordering = 'unordered'
1928
 
        path = self.bzrdir._path_for_remote_call(self._client)
1929
 
        body = "\n".join(revision_ids)
1930
 
        response_tuple, response_handler = (
1931
 
            self._call_with_body_bytes_expecting_body(
1932
 
                "VersionedFileRepository.get_inventories",
1933
 
                (path, ordering), body))
1934
 
        if response_tuple[0] != "ok":
1935
 
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1936
 
        deserializer = inventory_delta.InventoryDeltaDeserializer()
1937
 
        byte_stream = response_handler.read_streamed_body()
1938
 
        decoded = smart_repo._byte_stream_to_stream(byte_stream)
1939
 
        if decoded is None:
1940
 
            # no results whatsoever
1941
 
            return
1942
 
        src_format, stream = decoded
1943
 
        if src_format.network_name() != self._format.network_name():
1944
 
            raise AssertionError(
1945
 
                "Mismatched RemoteRepository and stream src %r, %r" % (
1946
 
                src_format.network_name(), self._format.network_name()))
1947
 
        # ignore the src format, it's not really relevant
1948
 
        prev_inv = Inventory(root_id=None,
1949
 
            revision_id=_mod_revision.NULL_REVISION)
1950
 
        # there should be just one substream, with inventory deltas
1951
 
        substream_kind, substream = stream.next()
1952
 
        if substream_kind != "inventory-deltas":
1953
 
            raise AssertionError(
1954
 
                 "Unexpected stream %r received" % substream_kind)
1955
 
        for record in substream:
1956
 
            (parent_id, new_id, versioned_root, tree_references, invdelta) = (
1957
 
                deserializer.parse_text_bytes(record.get_bytes_as("fulltext")))
1958
 
            if parent_id != prev_inv.revision_id:
1959
 
                raise AssertionError("invalid base %r != %r" % (parent_id,
1960
 
                    prev_inv.revision_id))
1961
 
            inv = prev_inv.create_by_apply_delta(invdelta, new_id)
1962
 
            yield inv, inv.revision_id
1963
 
            prev_inv = inv
1964
 
 
1965
 
    def _iter_inventories_vfs(self, revision_ids, ordering=None):
1966
 
        self._ensure_real()
1967
 
        return self._real_repository._iter_inventories(revision_ids, ordering)
1968
 
 
1969
1791
    def iter_inventories(self, revision_ids, ordering=None):
1970
 
        """Get many inventories by revision_ids.
1971
 
 
1972
 
        This will buffer some or all of the texts used in constructing the
1973
 
        inventories in memory, but will only parse a single inventory at a
1974
 
        time.
1975
 
 
1976
 
        :param revision_ids: The expected revision ids of the inventories.
1977
 
        :param ordering: optional ordering, e.g. 'topological'.  If not
1978
 
            specified, the order of revision_ids will be preserved (by
1979
 
            buffering if necessary).
1980
 
        :return: An iterator of inventories.
1981
 
        """
1982
 
        if ((None in revision_ids)
1983
 
            or (_mod_revision.NULL_REVISION in revision_ids)):
1984
 
            raise ValueError('cannot get null revision inventory')
1985
 
        for inv, revid in self._iter_inventories(revision_ids, ordering):
1986
 
            if inv is None:
1987
 
                raise errors.NoSuchRevision(self, revid)
1988
 
            yield inv
1989
 
 
1990
 
    def _iter_inventories(self, revision_ids, ordering=None):
1991
 
        if len(revision_ids) == 0:
1992
 
            return
1993
 
        missing = set(revision_ids)
1994
 
        if ordering is None:
1995
 
            order_as_requested = True
1996
 
            invs = {}
1997
 
            order = list(revision_ids)
1998
 
            order.reverse()
1999
 
            next_revid = order.pop()
2000
 
        else:
2001
 
            order_as_requested = False
2002
 
            if ordering != 'unordered' and self._fallback_repositories:
2003
 
                raise ValueError('unsupported ordering %r' % ordering)
2004
 
        iter_inv_fns = [self._iter_inventories_rpc] + [
2005
 
            fallback._iter_inventories for fallback in
2006
 
            self._fallback_repositories]
2007
 
        try:
2008
 
            for iter_inv in iter_inv_fns:
2009
 
                request = [revid for revid in revision_ids if revid in missing]
2010
 
                for inv, revid in iter_inv(request, ordering):
2011
 
                    if inv is None:
2012
 
                        continue
2013
 
                    missing.remove(inv.revision_id)
2014
 
                    if ordering != 'unordered':
2015
 
                        invs[revid] = inv
2016
 
                    else:
2017
 
                        yield inv, revid
2018
 
                if order_as_requested:
2019
 
                    # Yield as many results as we can while preserving order.
2020
 
                    while next_revid in invs:
2021
 
                        inv = invs.pop(next_revid)
2022
 
                        yield inv, inv.revision_id
2023
 
                        try:
2024
 
                            next_revid = order.pop()
2025
 
                        except IndexError:
2026
 
                            # We still want to fully consume the stream, just
2027
 
                            # in case it is not actually finished at this point
2028
 
                            next_revid = None
2029
 
                            break
2030
 
        except errors.UnknownSmartMethod:
2031
 
            for inv, revid in self._iter_inventories_vfs(revision_ids, ordering):
2032
 
                yield inv, revid
2033
 
            return
2034
 
        # Report missing
2035
 
        if order_as_requested:
2036
 
            if next_revid is not None:
2037
 
                yield None, next_revid
2038
 
            while order:
2039
 
                revid = order.pop()
2040
 
                yield invs.get(revid), revid
2041
 
        else:
2042
 
            while missing:
2043
 
                yield None, missing.pop()
 
1792
        self._ensure_real()
 
1793
        return self._real_repository.iter_inventories(revision_ids, ordering)
2044
1794
 
2045
1795
    @needs_read_lock
2046
1796
    def get_revision(self, revision_id):
2082
1832
        """
2083
1833
        if self._real_repository is not None:
2084
1834
            self._real_repository.refresh_data()
2085
 
        # Refresh the parents cache for this object
2086
 
        self._unstacked_provider.disable_cache()
2087
 
        self._unstacked_provider.enable_cache()
2088
1835
 
2089
1836
    def revision_ids_to_search_result(self, result_set):
2090
1837
        """Convert a set of revision ids to a graph SearchResult."""
2402
2149
 
2403
2150
    @needs_read_lock
2404
2151
    def _get_inventory_xml(self, revision_id):
2405
 
        # This call is used by older working tree formats,
2406
 
        # which stored a serialized basis inventory.
2407
2152
        self._ensure_real()
2408
2153
        return self._real_repository._get_inventory_xml(revision_id)
2409
2154
 
2410
 
    @needs_write_lock
2411
2155
    def reconcile(self, other=None, thorough=False):
2412
 
        from bzrlib.reconcile import RepoReconciler
2413
 
        path = self.bzrdir._path_for_remote_call(self._client)
2414
 
        try:
2415
 
            response, handler = self._call_expecting_body(
2416
 
                'Repository.reconcile', path, self._lock_token)
2417
 
        except (errors.UnknownSmartMethod, errors.TokenLockingNotSupported):
2418
 
            self._ensure_real()
2419
 
            return self._real_repository.reconcile(other=other, thorough=thorough)
2420
 
        if response != ('ok', ):
2421
 
            raise errors.UnexpectedSmartServerResponse(response)
2422
 
        body = handler.read_body_bytes()
2423
 
        result = RepoReconciler(self)
2424
 
        for line in body.split('\n'):
2425
 
            if not line:
2426
 
                continue
2427
 
            key, val_text = line.split(':')
2428
 
            if key == "garbage_inventories":
2429
 
                result.garbage_inventories = int(val_text)
2430
 
            elif key == "inconsistent_parents":
2431
 
                result.inconsistent_parents = int(val_text)
2432
 
            else:
2433
 
                mutter("unknown reconcile key %r" % key)
2434
 
        return result
 
2156
        self._ensure_real()
 
2157
        return self._real_repository.reconcile(other=other, thorough=thorough)
2435
2158
 
2436
2159
    def all_revision_ids(self):
2437
2160
        path = self.bzrdir._path_for_remote_call(self._client)
2448
2171
            revids.update(set(fallback.all_revision_ids()))
2449
2172
        return list(revids)
2450
2173
 
2451
 
    def _filtered_revision_trees(self, revision_ids, file_ids):
2452
 
        """Return Tree for a revision on this branch with only some files.
2453
 
 
2454
 
        :param revision_ids: a sequence of revision-ids;
2455
 
          a revision-id may not be None or 'null:'
2456
 
        :param file_ids: if not None, the result is filtered
2457
 
          so that only those file-ids, their parents and their
2458
 
          children are included.
2459
 
        """
2460
 
        inventories = self.iter_inventories(revision_ids)
2461
 
        for inv in inventories:
2462
 
            # Should we introduce a FilteredRevisionTree class rather
2463
 
            # than pre-filter the inventory here?
2464
 
            filtered_inv = inv.filter(file_ids)
2465
 
            yield InventoryRevisionTree(self, filtered_inv, filtered_inv.revision_id)
2466
 
 
2467
2174
    @needs_read_lock
2468
2175
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
2469
 
        medium = self._client._medium
2470
 
        if medium._is_remote_before((1, 2)):
2471
 
            self._ensure_real()
2472
 
            for delta in self._real_repository.get_deltas_for_revisions(
2473
 
                    revisions, specific_fileids):
2474
 
                yield delta
2475
 
            return
2476
 
        # Get the revision-ids of interest
2477
 
        required_trees = set()
2478
 
        for revision in revisions:
2479
 
            required_trees.add(revision.revision_id)
2480
 
            required_trees.update(revision.parent_ids[:1])
2481
 
 
2482
 
        # Get the matching filtered trees. Note that it's more
2483
 
        # efficient to pass filtered trees to changes_from() rather
2484
 
        # than doing the filtering afterwards. changes_from() could
2485
 
        # arguably do the filtering itself but it's path-based, not
2486
 
        # file-id based, so filtering before or afterwards is
2487
 
        # currently easier.
2488
 
        if specific_fileids is None:
2489
 
            trees = dict((t.get_revision_id(), t) for
2490
 
                t in self.revision_trees(required_trees))
2491
 
        else:
2492
 
            trees = dict((t.get_revision_id(), t) for
2493
 
                t in self._filtered_revision_trees(required_trees,
2494
 
                specific_fileids))
2495
 
 
2496
 
        # Calculate the deltas
2497
 
        for revision in revisions:
2498
 
            if not revision.parent_ids:
2499
 
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
2500
 
            else:
2501
 
                old_tree = trees[revision.parent_ids[0]]
2502
 
            yield trees[revision.revision_id].changes_from(old_tree)
 
2176
        self._ensure_real()
 
2177
        return self._real_repository.get_deltas_for_revisions(revisions,
 
2178
            specific_fileids=specific_fileids)
2503
2179
 
2504
2180
    @needs_read_lock
2505
2181
    def get_revision_delta(self, revision_id, specific_fileids=None):
3137
2813
        if isinstance(a_bzrdir, RemoteBzrDir):
3138
2814
            a_bzrdir._ensure_real()
3139
2815
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
3140
 
                name=name, append_revisions_only=append_revisions_only)
 
2816
                name, append_revisions_only=append_revisions_only)
3141
2817
        else:
3142
2818
            # We assume the bzrdir is parameterised; it may not be.
3143
 
            result = self._custom_format.initialize(a_bzrdir, name=name,
 
2819
            result = self._custom_format.initialize(a_bzrdir, name,
3144
2820
                append_revisions_only=append_revisions_only)
3145
2821
        if (isinstance(a_bzrdir, RemoteBzrDir) and
3146
2822
            not isinstance(result, RemoteBranch)):
3150
2826
 
3151
2827
    def initialize(self, a_bzrdir, name=None, repository=None,
3152
2828
                   append_revisions_only=None):
3153
 
        if name is None:
3154
 
            name = a_bzrdir._get_selected_branch()
3155
2829
        # 1) get the network name to use.
3156
2830
        if self._custom_format:
3157
2831
            network_name = self._custom_format.network_name()
3172
2846
        # Creating on a remote bzr dir.
3173
2847
        # 2) try direct creation via RPC
3174
2848
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
3175
 
        if name != "":
 
2849
        if name is not None:
3176
2850
            # XXX JRV20100304: Support creating colocated branches
3177
2851
            raise errors.NoColocatedBranchSupport(self)
3178
2852
        verb = 'BzrDir.create_branch'
3250
2924
        return False
3251
2925
 
3252
2926
 
3253
 
class RemoteBranchStore(_mod_config.IniFileStore):
 
2927
class RemoteBranchStore(config.IniFileStore):
3254
2928
    """Branch store which attempts to use HPSS calls to retrieve branch store.
3255
2929
 
3256
2930
    Note that this is specific to bzr-based formats.
3262
2936
        self.id = "branch"
3263
2937
        self._real_store = None
3264
2938
 
 
2939
    def lock_write(self, token=None):
 
2940
        return self.branch.lock_write(token)
 
2941
 
 
2942
    def unlock(self):
 
2943
        return self.branch.unlock()
 
2944
 
 
2945
    @needs_write_lock
 
2946
    def save(self):
 
2947
        # We need to be able to override the undecorated implementation
 
2948
        self.save_without_locking()
 
2949
 
 
2950
    def save_without_locking(self):
 
2951
        super(RemoteBranchStore, self).save()
 
2952
 
3265
2953
    def external_url(self):
3266
2954
        return self.branch.user_url
3267
2955
 
3294
2982
    def _ensure_real(self):
3295
2983
        self.branch._ensure_real()
3296
2984
        if self._real_store is None:
3297
 
            self._real_store = _mod_config.BranchStore(self.branch)
 
2985
            self._real_store = config.BranchStore(self.branch)
3298
2986
 
3299
2987
 
3300
2988
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
3323
3011
        # will try to assign to self.tags, which is a property in this subclass.
3324
3012
        # And the parent's __init__ doesn't do much anyway.
3325
3013
        self.bzrdir = remote_bzrdir
3326
 
        self.name = name
3327
3014
        if _client is not None:
3328
3015
            self._client = _client
3329
3016
        else:
3352
3039
        self._repo_lock_token = None
3353
3040
        self._lock_count = 0
3354
3041
        self._leave_lock = False
3355
 
        self.conf_store = None
3356
3042
        # Setup a format: note that we cannot call _ensure_real until all the
3357
3043
        # attributes above are set: This code cannot be moved higher up in this
3358
3044
        # function.
3401
3087
        return RemoteBranchConfig(self)
3402
3088
 
3403
3089
    def _get_config_store(self):
3404
 
        if self.conf_store is None:
3405
 
            self.conf_store =  RemoteBranchStore(self)
3406
 
        return self.conf_store
 
3090
        return RemoteBranchStore(self)
3407
3091
 
3408
3092
    def _get_real_transport(self):
3409
3093
        # if we try vfs access, return the real branch's vfs transport
3429
3113
            self.bzrdir._ensure_real()
3430
3114
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
3431
3115
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
3432
 
            # The remote branch and the real branch shares the same store. If
3433
 
            # we don't, there will always be cases where one of the stores
3434
 
            # doesn't see an update made on the other.
3435
 
            self._real_branch.conf_store = self.conf_store
3436
3116
            if self.repository._real_repository is None:
3437
3117
                # Give the remote repository the matching real repo.
3438
3118
                real_repo = self._real_branch.repository
3477
3157
                self.bzrdir, self._client)
3478
3158
        return self._control_files
3479
3159
 
 
3160
    def _get_checkout_format(self, lightweight=False):
 
3161
        self._ensure_real()
 
3162
        if lightweight:
 
3163
            format = RemoteBzrDirFormat()
 
3164
            self.bzrdir._format._supply_sub_formats_to(format)
 
3165
            format.workingtree_format = self._real_branch._get_checkout_format(
 
3166
                lightweight=lightweight).workingtree_format
 
3167
            return format
 
3168
        else:
 
3169
            return self._real_branch._get_checkout_format(lightweight=False)
 
3170
 
3480
3171
    def get_physical_lock_status(self):
3481
3172
        """See Branch.get_physical_lock_status()."""
3482
3173
        try:
3516
3207
 
3517
3208
    def set_stacked_on_url(self, url):
3518
3209
        branch.Branch.set_stacked_on_url(self, url)
3519
 
        # We need the stacked_on_url to be visible both locally (to not query
3520
 
        # it repeatedly) and remotely (so smart verbs can get it server side)
3521
 
        # Without the following line,
3522
 
        # bzrlib.tests.per_branch.test_create_clone.TestCreateClone
3523
 
        # .test_create_clone_on_transport_stacked_hooks_get_stacked_branch
3524
 
        # fails for remote branches -- vila 2012-01-04
3525
 
        self.conf_store.save_changes()
3526
3210
        if not url:
3527
3211
            self._is_stacked = False
3528
3212
        else:
3656
3340
        try:
3657
3341
            self._lock_count -= 1
3658
3342
            if not self._lock_count:
3659
 
                if self.conf_store is not None:
3660
 
                    self.conf_store.save_changes()
3661
3343
                self._clear_cached_state()
3662
3344
                mode = self._lock_mode
3663
3345
                self._lock_mode = None
3953
3635
            last_rev=last_rev,other_branch=other_branch))
3954
3636
 
3955
3637
    def set_push_location(self, location):
3956
 
        self._set_config_location('push_location', location)
 
3638
        self._ensure_real()
 
3639
        return self._real_branch.set_push_location(location)
3957
3640
 
3958
3641
    def heads_to_fetch(self):
3959
3642
        if self._format._use_default_local_heads_to_fetch():
4015
3698
                value = section_obj.get(name, default)
4016
3699
        except errors.UnknownSmartMethod:
4017
3700
            value = self._vfs_get_option(name, section, default)
4018
 
        for hook in _mod_config.OldConfigHooks['get']:
 
3701
        for hook in config.OldConfigHooks['get']:
4019
3702
            hook(self, name, value)
4020
3703
        return value
4021
3704
 
4023
3706
        if len(response[0]) and response[0][0] != 'ok':
4024
3707
            raise errors.UnexpectedSmartServerResponse(response)
4025
3708
        lines = response[1].read_body_bytes().splitlines()
4026
 
        conf = _mod_config.ConfigObj(lines, encoding='utf-8')
4027
 
        for hook in _mod_config.OldConfigHooks['load']:
 
3709
        conf = config.ConfigObj(lines, encoding='utf-8')
 
3710
        for hook in config.OldConfigHooks['load']:
4028
3711
            hook(self)
4029
3712
        return conf
4030
3713
 
4245
3928
    lambda err, find, get_path: errors.ReadError(get_path()))
4246
3929
error_translators.register('NoSuchFile',
4247
3930
    lambda err, find, get_path: errors.NoSuchFile(get_path()))
4248
 
error_translators.register('TokenLockingNotSupported',
4249
 
    lambda err, find, get_path: errors.TokenLockingNotSupported(
4250
 
        find('repository')))
4251
3931
error_translators.register('UnsuspendableWriteGroup',
4252
3932
    lambda err, find, get_path: errors.UnsuspendableWriteGroup(
4253
3933
        repository=find('repository')))