~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-06-03 20:18:35 UTC
  • mfrom: (1185.82.137 w-changeset)
  • Revision ID: pqm@pqm.ubuntu.com-20060603201835-1c9a1725641ccd24
Implement bundles

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
from copy import deepcopy
19
19
from cStringIO import StringIO
 
20
import errno
 
21
import os
 
22
import shutil
 
23
import sys
20
24
from unittest import TestSuite
21
25
from warnings import warn
22
26
 
23
27
import bzrlib
24
 
from bzrlib import (
25
 
        bzrdir, 
26
 
        errors, 
27
 
        lockdir, 
28
 
        osutils, 
29
 
        revision,
30
 
        transport,
31
 
        tree,
32
 
        ui,
33
 
        urlutils
34
 
        )
 
28
import bzrlib.bzrdir as bzrdir
35
29
from bzrlib.config import TreeConfig
36
30
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
31
from bzrlib.delta import compare_trees
37
32
import bzrlib.errors as errors
38
 
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches, 
39
 
                           HistoryMissing, InvalidRevisionId, 
40
 
                           InvalidRevisionNumber, LockError, NoSuchFile, 
41
 
                           NoSuchRevision, NoWorkingTree, NotVersionedError,
42
 
                           NotBranchError, UninitializableFormat, 
43
 
                           UnlistableStore, UnlistableBranch, 
44
 
                           )
 
33
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
 
34
                           NoSuchRevision, HistoryMissing, NotBranchError,
 
35
                           DivergedBranches, LockError,
 
36
                           UninitializableFormat,
 
37
                           UnlistableStore,
 
38
                           UnlistableBranch, NoSuchFile, NotVersionedError,
 
39
                           NoWorkingTree)
 
40
import bzrlib.inventory as inventory
 
41
from bzrlib.inventory import Inventory
45
42
from bzrlib.lockable_files import LockableFiles, TransportLock
46
 
from bzrlib.symbol_versioning import (deprecated_function,
47
 
                                      deprecated_method,
48
 
                                      DEPRECATED_PARAMETER,
49
 
                                      deprecated_passed,
50
 
                                      zero_eight, zero_nine,
51
 
                                      )
 
43
from bzrlib.lockdir import LockDir
 
44
from bzrlib.osutils import (isdir, quotefn,
 
45
                            rename, splitpath, sha_file,
 
46
                            file_kind, abspath, normpath, pathjoin,
 
47
                            safe_unicode,
 
48
                            rmtree,
 
49
                            )
 
50
from bzrlib.textui import show_status
52
51
from bzrlib.trace import mutter, note
 
52
from bzrlib.tree import EmptyTree, RevisionTree
 
53
from bzrlib.repository import Repository
 
54
from bzrlib.revision import (
 
55
                             is_ancestor,
 
56
                             NULL_REVISION,
 
57
                             Revision,
 
58
                             )
 
59
from bzrlib.store import copy_all
 
60
from bzrlib.symbol_versioning import *
 
61
import bzrlib.transactions as transactions
 
62
from bzrlib.transport import Transport, get_transport
 
63
from bzrlib.tree import EmptyTree, RevisionTree
 
64
import bzrlib.ui
 
65
import bzrlib.xml5
53
66
 
54
67
 
55
68
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
104
117
        
105
118
    @staticmethod
106
119
    def open(base, _unsupported=False):
107
 
        """Open the branch rooted at base.
 
120
        """Open the repository rooted at base.
108
121
 
109
 
        For instance, if the branch is at URL/.bzr/branch,
110
 
        Branch.open(URL) -> a Branch instance.
 
122
        For instance, if the repository is at URL/.bzr/repository,
 
123
        Repository.open(URL) -> a Repository instance.
111
124
        """
112
125
        control = bzrdir.BzrDir.open(base, _unsupported)
113
126
        return control.open_branch(_unsupported)
145
158
        warn('%s is deprecated' % self.setup_caching)
146
159
        self.cache_root = cache_root
147
160
 
148
 
    def get_config(self):
149
 
        return bzrlib.config.BranchConfig(self)
150
 
 
151
161
    def _get_nick(self):
152
 
        return self.get_config().get_nickname()
 
162
        cfg = self.tree_config()
 
163
        return cfg.get_option(u"nickname", default=self.base.split('/')[-2])
153
164
 
154
165
    def _set_nick(self, nick):
155
 
        self.get_config().set_user_option('nickname', nick)
 
166
        cfg = self.tree_config()
 
167
        cfg.set_option(nick, "nickname")
 
168
        assert cfg.get_option("nickname") == nick
156
169
 
157
170
    nick = property(_get_nick, _set_nick)
158
171
 
206
219
        if self.base == from_branch.base:
207
220
            return (0, [])
208
221
        if pb is None:
209
 
            nested_pb = ui.ui_factory.nested_progress_bar()
 
222
            nested_pb = bzrlib.ui.ui_factory.nested_progress_bar()
210
223
            pb = nested_pb
211
224
        else:
212
225
            nested_pb = None
220
233
                    last_revision = from_history[-1]
221
234
                else:
222
235
                    # no history in the source branch
223
 
                    last_revision = revision.NULL_REVISION
 
236
                    last_revision = NULL_REVISION
224
237
            return self.repository.fetch(from_branch.repository,
225
238
                                         revision_id=last_revision,
226
239
                                         pb=nested_pb)
236
249
        branch.
237
250
        """
238
251
        return None
239
 
    
240
 
    def get_commit_builder(self, parents, config=None, timestamp=None, 
241
 
                           timezone=None, committer=None, revprops=None, 
242
 
                           revision_id=None):
243
 
        """Obtain a CommitBuilder for this branch.
244
 
        
245
 
        :param parents: Revision ids of the parents of the new revision.
246
 
        :param config: Optional configuration to use.
247
 
        :param timestamp: Optional timestamp recorded for commit.
248
 
        :param timezone: Optional timezone for timestamp.
249
 
        :param committer: Optional committer to set for commit.
250
 
        :param revprops: Optional dictionary of revision properties.
251
 
        :param revision_id: Optional revision id.
252
 
        """
253
 
 
254
 
        if config is None:
255
 
            config = self.get_config()
256
 
        
257
 
        return self.repository.get_commit_builder(self, parents, config, 
258
 
            timestamp, timezone, committer, revprops, revision_id)
259
252
 
260
253
    def get_master_branch(self):
261
254
        """Return the branch we are bound to.
264
257
        """
265
258
        return None
266
259
 
267
 
    def get_revision_delta(self, revno):
268
 
        """Return the delta for one revision.
269
 
 
270
 
        The delta is relative to its mainline predecessor, or the
271
 
        empty tree for revision 1.
272
 
        """
273
 
        assert isinstance(revno, int)
274
 
        rh = self.revision_history()
275
 
        if not (1 <= revno <= len(rh)):
276
 
            raise InvalidRevisionNumber(revno)
277
 
        return self.repository.get_revision_delta(rh[revno-1])
278
 
 
279
260
    def get_root_id(self):
280
261
        """Return the id of this branches root"""
281
262
        raise NotImplementedError('get_root_id is abstract')
319
300
        
320
301
        If self and other have not diverged, return a list of the revisions
321
302
        present in other, but missing from self.
 
303
 
 
304
        >>> from bzrlib.workingtree import WorkingTree
 
305
        >>> bzrlib.trace.silent = True
 
306
        >>> d1 = bzrdir.ScratchDir()
 
307
        >>> br1 = d1.open_branch()
 
308
        >>> wt1 = d1.open_workingtree()
 
309
        >>> d2 = bzrdir.ScratchDir()
 
310
        >>> br2 = d2.open_branch()
 
311
        >>> wt2 = d2.open_workingtree()
 
312
        >>> br1.missing_revisions(br2)
 
313
        []
 
314
        >>> wt2.commit("lala!", rev_id="REVISION-ID-1")
 
315
        >>> br1.missing_revisions(br2)
 
316
        [u'REVISION-ID-1']
 
317
        >>> br2.missing_revisions(br1)
 
318
        []
 
319
        >>> wt1.commit("lala!", rev_id="REVISION-ID-1")
 
320
        >>> br1.missing_revisions(br2)
 
321
        []
 
322
        >>> wt2.commit("lala!", rev_id="REVISION-ID-2A")
 
323
        >>> br1.missing_revisions(br2)
 
324
        [u'REVISION-ID-2A']
 
325
        >>> wt1.commit("lala!", rev_id="REVISION-ID-2B")
 
326
        >>> br1.missing_revisions(br2)
 
327
        Traceback (most recent call last):
 
328
        DivergedBranches: These branches have diverged.  Try merge.
322
329
        """
323
330
        self_history = self.revision_history()
324
331
        self_len = len(self_history)
334
341
        else:
335
342
            assert isinstance(stop_revision, int)
336
343
            if stop_revision > other_len:
337
 
                raise errors.NoSuchRevision(self, stop_revision)
 
344
                raise bzrlib.errors.NoSuchRevision(self, stop_revision)
338
345
        return other_history[self_len:stop_revision]
339
346
 
340
347
    def update_revisions(self, other, stop_revision=None):
370
377
        raise NotImplementedError('pull is abstract')
371
378
 
372
379
    def basis_tree(self):
373
 
        """Return `Tree` object for last revision."""
 
380
        """Return `Tree` object for last revision.
 
381
 
 
382
        If there are no revisions yet, return an `EmptyTree`.
 
383
        """
374
384
        return self.repository.revision_tree(self.last_revision())
375
385
 
376
386
    def rename_one(self, from_rel, to_rel):
405
415
        """
406
416
        raise NotImplementedError('get_parent is abstract')
407
417
 
408
 
    def get_submit_branch(self):
409
 
        """Return the submit location of the branch.
410
 
 
411
 
        This is the default location for bundle.  The usual
412
 
        pattern is that the user can override it by specifying a
413
 
        location.
414
 
        """
415
 
        return self.get_config().get_user_option('submit_branch')
416
 
 
417
 
    def set_submit_branch(self, location):
418
 
        """Return the submit location of the branch.
419
 
 
420
 
        This is the default location for bundle.  The usual
421
 
        pattern is that the user can override it by specifying a
422
 
        location.
423
 
        """
424
 
        self.get_config().set_user_option('submit_branch', location)
425
 
 
426
418
    def get_push_location(self):
427
419
        """Return the None or the location to push this branch to."""
428
420
        raise NotImplementedError('get_push_location is abstract')
465
457
        revision_id: if not None, the revision history in the new branch will
466
458
                     be truncated to end with revision_id.
467
459
        """
468
 
        # for API compatibility, until 0.8 releases we provide the old api:
 
460
        # for API compatability, until 0.8 releases we provide the old api:
469
461
        # def clone(self, to_location, revision=None, basis_branch=None, to_branch_format=None):
470
462
        # after 0.8 releases, the *args and **kwargs should be changed:
471
463
        # def clone(self, to_bzrdir, revision_id=None):
473
465
            kwargs.get('revision', None) or
474
466
            kwargs.get('basis_branch', None) or
475
467
            (len(args) and isinstance(args[0], basestring))):
476
 
            # backwards compatibility api:
 
468
            # backwards compatability api:
477
469
            warn("Branch.clone() has been deprecated for BzrDir.clone() from"
478
470
                 " bzrlib 0.8.", DeprecationWarning, stacklevel=3)
479
471
            # get basis_branch
541
533
                rev = self.repository.get_revision(revision_id)
542
534
                new_history = rev.get_history(self.repository)[1:]
543
535
        destination.set_revision_history(new_history)
544
 
        try:
545
 
            parent = self.get_parent()
546
 
        except errors.InaccessibleParent, e:
547
 
            mutter('parent was not accessible to copy: %s', e)
548
 
        else:
549
 
            if parent:
550
 
                destination.set_parent(parent)
551
 
 
552
 
    @needs_read_lock
553
 
    def check(self):
554
 
        """Check consistency of the branch.
555
 
 
556
 
        In particular this checks that revisions given in the revision-history
557
 
        do actually match up in the revision graph, and that they're all 
558
 
        present in the repository.
559
 
        
560
 
        Callers will typically also want to check the repository.
561
 
 
562
 
        :return: A BranchCheckResult.
563
 
        """
564
 
        mainline_parent_id = None
565
 
        for revision_id in self.revision_history():
566
 
            try:
567
 
                revision = self.repository.get_revision(revision_id)
568
 
            except errors.NoSuchRevision, e:
569
 
                raise errors.BzrCheckError("mainline revision {%s} not in repository"
570
 
                            % revision_id)
571
 
            # In general the first entry on the revision history has no parents.
572
 
            # But it's not illegal for it to have parents listed; this can happen
573
 
            # in imports from Arch when the parents weren't reachable.
574
 
            if mainline_parent_id is not None:
575
 
                if mainline_parent_id not in revision.parent_ids:
576
 
                    raise errors.BzrCheckError("previous revision {%s} not listed among "
577
 
                                        "parents of {%s}"
578
 
                                        % (mainline_parent_id, revision_id))
579
 
            mainline_parent_id = revision_id
580
 
        return BranchCheckResult(self)
581
 
 
582
 
    def create_checkout(self, to_location, revision_id=None, 
583
 
                        lightweight=False):
584
 
        """Create a checkout of a branch.
585
 
        
586
 
        :param to_location: The url to produce the checkout at
587
 
        :param revision_id: The revision to check out
588
 
        :param lightweight: If True, produce a lightweight checkout, otherwise,
589
 
        produce a bound branch (heavyweight checkout)
590
 
        :return: The tree of the created checkout
591
 
        """
592
 
        if lightweight:
593
 
            t = transport.get_transport(to_location)
594
 
            try:
595
 
                t.mkdir('.')
596
 
            except errors.FileExists:
597
 
                pass
598
 
            checkout = bzrdir.BzrDirMetaFormat1().initialize_on_transport(t)
599
 
            BranchReferenceFormat().initialize(checkout, self)
600
 
        else:
601
 
            checkout_branch = bzrdir.BzrDir.create_branch_convenience(
602
 
                to_location, force_new_tree=False)
603
 
            checkout = checkout_branch.bzrdir
604
 
            checkout_branch.bind(self)
605
 
            if revision_id is not None:
606
 
                rh = checkout_branch.revision_history()
607
 
                new_rh = rh[:rh.index(revision_id) + 1]
608
 
                checkout_branch.set_revision_history(new_rh)
609
 
        return checkout.create_workingtree(revision_id)
 
536
        parent = self.get_parent()
 
537
        if parent:
 
538
            destination.set_parent(parent)
610
539
 
611
540
 
612
541
class BranchFormat(object):
643
572
        except NoSuchFile:
644
573
            raise NotBranchError(path=transport.base)
645
574
        except KeyError:
646
 
            raise errors.UnknownFormatError(format=format_string)
 
575
            raise errors.UnknownFormatError(format_string)
647
576
 
648
577
    @classmethod
649
578
    def get_default_format(klass):
660
589
 
661
590
    def initialize(self, a_bzrdir):
662
591
        """Create a branch of this format in a_bzrdir."""
663
 
        raise NotImplementedError(self.initialize)
 
592
        raise NotImplementedError(self.initialized)
664
593
 
665
594
    def is_supported(self):
666
595
        """Is this format supported?
776
705
        utf8_files = [('revision-history', ''),
777
706
                      ('branch-name', ''),
778
707
                      ]
779
 
        control_files = LockableFiles(branch_transport, 'lock', lockdir.LockDir)
 
708
        control_files = LockableFiles(branch_transport, 'lock', LockDir)
780
709
        control_files.create_lock()
781
710
        control_files.lock_write()
782
711
        control_files.put_utf8('format', self.get_format_string())
801
730
            format = BranchFormat.find_format(a_bzrdir)
802
731
            assert format.__class__ == self.__class__
803
732
        transport = a_bzrdir.get_branch_transport(None)
804
 
        control_files = LockableFiles(transport, 'lock', lockdir.LockDir)
 
733
        control_files = LockableFiles(transport, 'lock', LockDir)
805
734
        return BzrBranch5(_format=self,
806
735
                          _control_files=control_files,
807
736
                          a_bzrdir=a_bzrdir,
922
851
        self._base = self._transport.base
923
852
        self._format = _format
924
853
        if _control_files is None:
925
 
            raise ValueError('BzrBranch _control_files is None')
 
854
            raise BzrBadParameterMissing('_control_files')
926
855
        self.control_files = _control_files
927
856
        if deprecated_passed(init):
928
857
            warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
943
872
                 stacklevel=2)
944
873
            if (not relax_version_check
945
874
                and not self._format.is_supported()):
946
 
                raise errors.UnsupportedFormatError(format=fmt)
 
875
                raise errors.UnsupportedFormatError(
 
876
                        'sorry, branch format %r not supported' % fmt,
 
877
                        ['use a different bzr version',
 
878
                         'or remove the .bzr directory'
 
879
                         ' and "bzr init" again'])
947
880
        if deprecated_passed(transport):
948
881
            warn("BzrBranch.__init__(transport=XXX...): The transport "
949
882
                 "parameter is deprecated as of bzr 0.8. "
967
900
        # XXX: cache_root seems to be unused, 2006-01-13 mbp
968
901
        if hasattr(self, 'cache_root') and self.cache_root is not None:
969
902
            try:
970
 
                osutils.rmtree(self.cache_root)
 
903
                rmtree(self.cache_root)
971
904
            except:
972
905
                pass
973
906
            self.cache_root = None
1016
949
        FIXME: DELETE THIS METHOD when pre 0.8 support is removed.
1017
950
        """
1018
951
        if format is None:
1019
 
            format = BranchFormat.find_format(self.bzrdir)
 
952
            format = BzrBranchFormat.find_format(self.bzrdir)
1020
953
        self._format = format
1021
954
        mutter("got branch format %s", self._format)
1022
955
 
1030
963
        return self.control_files.is_locked()
1031
964
 
1032
965
    def lock_write(self):
 
966
        # TODO: test for failed two phase locks. This is known broken.
 
967
        self.control_files.lock_write()
1033
968
        self.repository.lock_write()
1034
 
        try:
1035
 
            self.control_files.lock_write()
1036
 
        except:
1037
 
            self.repository.unlock()
1038
 
            raise
1039
969
 
1040
970
    def lock_read(self):
 
971
        # TODO: test for failed two phase locks. This is known broken.
 
972
        self.control_files.lock_read()
1041
973
        self.repository.lock_read()
1042
 
        try:
1043
 
            self.control_files.lock_read()
1044
 
        except:
1045
 
            self.repository.unlock()
1046
 
            raise
1047
974
 
1048
975
    def unlock(self):
1049
976
        # TODO: test for failed two phase locks. This is known broken.
1050
977
        try:
 
978
            self.repository.unlock()
 
979
        finally:
1051
980
            self.control_files.unlock()
1052
 
        finally:
1053
 
            self.repository.unlock()
1054
981
        
1055
982
    def peek_lock_mode(self):
1056
983
        if self.control_files._lock_count == 0:
1094
1021
            # not really an object yet, and the transaction is for objects.
1095
1022
            # transaction.register_clean(history)
1096
1023
 
 
1024
    def get_revision_delta(self, revno):
 
1025
        """Return the delta for one revision.
 
1026
 
 
1027
        The delta is relative to its mainline predecessor, or the
 
1028
        empty tree for revision 1.
 
1029
        """
 
1030
        assert isinstance(revno, int)
 
1031
        rh = self.revision_history()
 
1032
        if not (1 <= revno <= len(rh)):
 
1033
            raise InvalidRevisionNumber(revno)
 
1034
 
 
1035
        # revno is 1-based; list is 0-based
 
1036
 
 
1037
        new_tree = self.repository.revision_tree(rh[revno-1])
 
1038
        if revno == 1:
 
1039
            old_tree = EmptyTree()
 
1040
        else:
 
1041
            old_tree = self.repository.revision_tree(rh[revno-2])
 
1042
        return compare_trees(old_tree, new_tree)
 
1043
 
1097
1044
    @needs_read_lock
1098
1045
    def revision_history(self):
1099
1046
        """See Branch.revision_history."""
1111
1058
        return list(history)
1112
1059
 
1113
1060
    @needs_write_lock
1114
 
    def generate_revision_history(self, revision_id, last_rev=None, 
1115
 
        other_branch=None):
1116
 
        """Create a new revision history that will finish with revision_id.
1117
 
        
1118
 
        :param revision_id: the new tip to use.
1119
 
        :param last_rev: The previous last_revision. If not None, then this
1120
 
            must be a ancestory of revision_id, or DivergedBranches is raised.
1121
 
        :param other_branch: The other branch that DivergedBranches should
1122
 
            raise with respect to.
1123
 
        """
1124
 
        # stop_revision must be a descendant of last_revision
1125
 
        stop_graph = self.repository.get_revision_graph(revision_id)
1126
 
        if last_rev is not None and last_rev not in stop_graph:
1127
 
            # our previous tip is not merged into stop_revision
1128
 
            raise errors.DivergedBranches(self, other_branch)
1129
 
        # make a new revision history from the graph
1130
 
        current_rev_id = revision_id
1131
 
        new_history = []
1132
 
        while current_rev_id not in (None, revision.NULL_REVISION):
1133
 
            new_history.append(current_rev_id)
1134
 
            current_rev_id_parents = stop_graph[current_rev_id]
1135
 
            try:
1136
 
                current_rev_id = current_rev_id_parents[0]
1137
 
            except IndexError:
1138
 
                current_rev_id = None
1139
 
        new_history.reverse()
1140
 
        self.set_revision_history(new_history)
1141
 
 
1142
 
    @needs_write_lock
1143
1061
    def update_revisions(self, other, stop_revision=None):
1144
1062
        """See Branch.update_revisions."""
1145
1063
        other.lock_read()
1159
1077
            if stop_revision in my_ancestry:
1160
1078
                # last_revision is a descendant of stop_revision
1161
1079
                return
1162
 
            self.generate_revision_history(stop_revision, last_rev=last_rev,
1163
 
                other_branch=other)
 
1080
            # stop_revision must be a descendant of last_revision
 
1081
            stop_graph = self.repository.get_revision_graph(stop_revision)
 
1082
            if last_rev is not None and last_rev not in stop_graph:
 
1083
                # our previous tip is not merged into stop_revision
 
1084
                raise errors.DivergedBranches(self, other)
 
1085
            # make a new revision history from the graph
 
1086
            current_rev_id = stop_revision
 
1087
            new_history = []
 
1088
            while current_rev_id not in (None, NULL_REVISION):
 
1089
                new_history.append(current_rev_id)
 
1090
                current_rev_id_parents = stop_graph[current_rev_id]
 
1091
                try:
 
1092
                    current_rev_id = current_rev_id_parents[0]
 
1093
                except IndexError:
 
1094
                    current_rev_id = None
 
1095
            new_history.reverse()
 
1096
            self.set_revision_history(new_history)
1164
1097
        finally:
1165
1098
            other.unlock()
1166
1099
 
1171
1104
    @deprecated_method(zero_eight)
1172
1105
    def working_tree(self):
1173
1106
        """Create a Working tree object for this branch."""
1174
 
 
 
1107
        from bzrlib.workingtree import WorkingTree
1175
1108
        from bzrlib.transport.local import LocalTransport
1176
1109
        if (self.base.find('://') != -1 or 
1177
1110
            not isinstance(self._transport, LocalTransport)):
1198
1131
 
1199
1132
    def get_parent(self):
1200
1133
        """See Branch.get_parent."""
1201
 
 
 
1134
        import errno
1202
1135
        _locs = ['parent', 'pull', 'x-pull']
1203
 
        assert self.base[-1] == '/'
1204
1136
        for l in _locs:
1205
1137
            try:
1206
 
                parent = self.control_files.get(l).read().strip('\n')
 
1138
                return self.control_files.get_utf8(l).read().strip('\n')
1207
1139
            except NoSuchFile:
1208
 
                continue
1209
 
            # This is an old-format absolute path to a local branch
1210
 
            # turn it into a url
1211
 
            if parent.startswith('/'):
1212
 
                parent = urlutils.local_path_to_url(parent.decode('utf8'))
1213
 
            try:
1214
 
                return urlutils.join(self.base[:-1], parent)
1215
 
            except errors.InvalidURLJoin, e:
1216
 
                raise errors.InaccessibleParent(parent, self.base)
 
1140
                pass
1217
1141
        return None
1218
1142
 
1219
1143
    def get_push_location(self):
1220
1144
        """See Branch.get_push_location."""
1221
 
        push_loc = self.get_config().get_user_option('push_location')
 
1145
        config = bzrlib.config.BranchConfig(self)
 
1146
        push_loc = config.get_user_option('push_location')
1222
1147
        return push_loc
1223
1148
 
1224
1149
    def set_push_location(self, location):
1225
1150
        """See Branch.set_push_location."""
1226
 
        self.get_config().set_user_option('push_location', location, 
1227
 
                                          local=True)
 
1151
        config = bzrlib.config.LocationConfig(self.base)
 
1152
        config.set_user_option('push_location', location)
1228
1153
 
1229
1154
    @needs_write_lock
1230
1155
    def set_parent(self, url):
1237
1162
        if url is None:
1238
1163
            self.control_files._transport.delete('parent')
1239
1164
        else:
1240
 
            if isinstance(url, unicode):
1241
 
                try: 
1242
 
                    url = url.encode('ascii')
1243
 
                except UnicodeEncodeError:
1244
 
                    raise bzrlib.errors.InvalidURL(url,
1245
 
                        "Urls must be 7-bit ascii, "
1246
 
                        "use bzrlib.urlutils.escape")
1247
 
                    
1248
 
            url = urlutils.relative_url(self.base, url)
1249
 
            self.control_files.put('parent', url + '\n')
 
1165
            self.control_files.put_utf8('parent', url + '\n')
1250
1166
 
1251
 
    @deprecated_function(zero_nine)
1252
1167
    def tree_config(self):
1253
 
        """DEPRECATED; call get_config instead.  
1254
 
        TreeConfig has become part of BranchConfig."""
1255
1168
        return TreeConfig(self)
1256
1169
 
1257
1170
 
1297
1210
 
1298
1211
        This could memoise the branch, but if thats done
1299
1212
        it must be revalidated on each new lock.
1300
 
        So for now we just don't memoise it.
 
1213
        So for now we just dont memoise it.
1301
1214
        # RBC 20060304 review this decision.
1302
1215
        """
1303
1216
        bound_loc = self.get_bound_location()
1349
1262
        # There may be a different check you could do here
1350
1263
        # rather than actually trying to install revisions remotely.
1351
1264
        # TODO: capture an exception which indicates the remote branch
1352
 
        #       is not writable. 
 
1265
        #       is not writeable. 
1353
1266
        #       If it is up-to-date, this probably should not be a failure
1354
1267
        
1355
1268
        # lock other for write so the revision-history syncing cannot race
1421
1334
        return result
1422
1335
 
1423
1336
 
1424
 
class BranchCheckResult(object):
1425
 
    """Results of checking branch consistency.
1426
 
 
1427
 
    :see: Branch.check
1428
 
    """
1429
 
 
1430
 
    def __init__(self, branch):
1431
 
        self.branch = branch
1432
 
 
1433
 
    def report_results(self, verbose):
1434
 
        """Report the check results via trace.note.
1435
 
        
1436
 
        :param verbose: Requests more detailed display of what was checked,
1437
 
            if any.
1438
 
        """
1439
 
        note('checked branch %s format %s',
1440
 
             self.branch.base,
1441
 
             self.branch._format)
1442
 
 
1443
 
 
1444
1337
######################################################################
1445
1338
# predicates
1446
1339
 
1447
1340
 
1448
1341
@deprecated_function(zero_eight)
 
1342
def ScratchBranch(*args, **kwargs):
 
1343
    """See bzrlib.bzrdir.ScratchDir."""
 
1344
    d = ScratchDir(*args, **kwargs)
 
1345
    return d.open_branch()
 
1346
 
 
1347
 
 
1348
@deprecated_function(zero_eight)
1449
1349
def is_control_file(*args, **kwargs):
1450
1350
    """See bzrlib.workingtree.is_control_file."""
1451
1351
    return bzrlib.workingtree.is_control_file(*args, **kwargs)