~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Robey Pointer
  • Date: 2006-07-01 19:03:33 UTC
  • mfrom: (1829 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1830.
  • Revision ID: robey@lag.net-20060701190333-f58465aec4bd3412
merge from bzr.dev

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
24
20
from unittest import TestSuite
25
21
from warnings import warn
26
22
 
27
23
import bzrlib
28
 
import bzrlib.bzrdir as bzrdir
 
24
from bzrlib import bzrdir, errors, lockdir, osutils, revision, \
 
25
        tree, \
 
26
        ui, \
 
27
        urlutils
29
28
from bzrlib.config import TreeConfig
30
29
from bzrlib.decorators import needs_read_lock, needs_write_lock
31
30
import bzrlib.errors as errors
36
35
                           NotBranchError, UninitializableFormat, 
37
36
                           UnlistableStore, UnlistableBranch, 
38
37
                           )
39
 
import bzrlib.inventory as inventory
40
 
from bzrlib.inventory import Inventory
41
38
from bzrlib.lockable_files import LockableFiles, TransportLock
42
 
from bzrlib.lockdir import LockDir
43
 
from bzrlib.osutils import (isdir, quotefn,
44
 
                            rename, splitpath, sha_file,
45
 
                            file_kind, abspath, normpath, pathjoin,
46
 
                            safe_unicode,
47
 
                            rmtree,
48
 
                            )
49
 
from bzrlib.repository import Repository
50
 
from bzrlib.revision import (
51
 
                             is_ancestor,
52
 
                             NULL_REVISION,
53
 
                             Revision,
54
 
                             )
55
 
from bzrlib.store import copy_all
56
 
from bzrlib.symbol_versioning import *
57
 
from bzrlib.textui import show_status
 
39
from bzrlib.symbol_versioning import (deprecated_function,
 
40
                                      deprecated_method,
 
41
                                      DEPRECATED_PARAMETER,
 
42
                                      deprecated_passed,
 
43
                                      zero_eight, zero_nine,
 
44
                                      )
58
45
from bzrlib.trace import mutter, note
59
 
import bzrlib.transactions as transactions
60
 
from bzrlib.transport import Transport, get_transport
61
 
import bzrlib.ui
62
 
import bzrlib.urlutils as urlutils
63
 
import bzrlib.xml5
64
46
 
65
47
 
66
48
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
115
97
        
116
98
    @staticmethod
117
99
    def open(base, _unsupported=False):
118
 
        """Open the repository rooted at base.
 
100
        """Open the branch rooted at base.
119
101
 
120
 
        For instance, if the repository is at URL/.bzr/repository,
121
 
        Repository.open(URL) -> a Repository instance.
 
102
        For instance, if the branch is at URL/.bzr/branch,
 
103
        Branch.open(URL) -> a Branch instance.
122
104
        """
123
105
        control = bzrdir.BzrDir.open(base, _unsupported)
124
106
        return control.open_branch(_unsupported)
156
138
        warn('%s is deprecated' % self.setup_caching)
157
139
        self.cache_root = cache_root
158
140
 
 
141
    def get_config(self):
 
142
        return bzrlib.config.BranchConfig(self)
 
143
 
159
144
    def _get_nick(self):
160
 
        cfg = self.tree_config()
161
 
        return cfg.get_option(u"nickname", default=self.base.split('/')[-2])
 
145
        return self.get_config().get_nickname()
162
146
 
163
147
    def _set_nick(self, nick):
164
 
        cfg = self.tree_config()
165
 
        cfg.set_option(nick, "nickname")
166
 
        assert cfg.get_option("nickname") == nick
 
148
        self.get_config().set_user_option('nickname', nick)
167
149
 
168
150
    nick = property(_get_nick, _set_nick)
169
151
 
217
199
        if self.base == from_branch.base:
218
200
            return (0, [])
219
201
        if pb is None:
220
 
            nested_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
202
            nested_pb = ui.ui_factory.nested_progress_bar()
221
203
            pb = nested_pb
222
204
        else:
223
205
            nested_pb = None
231
213
                    last_revision = from_history[-1]
232
214
                else:
233
215
                    # no history in the source branch
234
 
                    last_revision = NULL_REVISION
 
216
                    last_revision = revision.NULL_REVISION
235
217
            return self.repository.fetch(from_branch.repository,
236
218
                                         revision_id=last_revision,
237
219
                                         pb=nested_pb)
263
245
        """
264
246
 
265
247
        if config is None:
266
 
            config = bzrlib.config.BranchConfig(self)
 
248
            config = self.get_config()
267
249
        
268
250
        return self.repository.get_commit_builder(self, parents, config, 
269
251
            timestamp, timezone, committer, revprops, revision_id)
330
312
        
331
313
        If self and other have not diverged, return a list of the revisions
332
314
        present in other, but missing from self.
333
 
 
334
 
        >>> from bzrlib.workingtree import WorkingTree
335
 
        >>> bzrlib.trace.silent = True
336
 
        >>> d1 = bzrdir.ScratchDir()
337
 
        >>> br1 = d1.open_branch()
338
 
        >>> wt1 = d1.open_workingtree()
339
 
        >>> d2 = bzrdir.ScratchDir()
340
 
        >>> br2 = d2.open_branch()
341
 
        >>> wt2 = d2.open_workingtree()
342
 
        >>> br1.missing_revisions(br2)
343
 
        []
344
 
        >>> wt2.commit("lala!", rev_id="REVISION-ID-1")
345
 
        'REVISION-ID-1'
346
 
        >>> br1.missing_revisions(br2)
347
 
        [u'REVISION-ID-1']
348
 
        >>> br2.missing_revisions(br1)
349
 
        []
350
 
        >>> wt1.commit("lala!", rev_id="REVISION-ID-1")
351
 
        'REVISION-ID-1'
352
 
        >>> br1.missing_revisions(br2)
353
 
        []
354
 
        >>> wt2.commit("lala!", rev_id="REVISION-ID-2A")
355
 
        'REVISION-ID-2A'
356
 
        >>> br1.missing_revisions(br2)
357
 
        [u'REVISION-ID-2A']
358
 
        >>> wt1.commit("lala!", rev_id="REVISION-ID-2B")
359
 
        'REVISION-ID-2B'
360
 
        >>> br1.missing_revisions(br2)
361
 
        Traceback (most recent call last):
362
 
        DivergedBranches: These branches have diverged.  Try merge.
363
315
        """
364
316
        self_history = self.revision_history()
365
317
        self_len = len(self_history)
375
327
        else:
376
328
            assert isinstance(stop_revision, int)
377
329
            if stop_revision > other_len:
378
 
                raise bzrlib.errors.NoSuchRevision(self, stop_revision)
 
330
                raise errors.NoSuchRevision(self, stop_revision)
379
331
        return other_history[self_len:stop_revision]
380
332
 
381
333
    def update_revisions(self, other, stop_revision=None):
449
401
        """
450
402
        raise NotImplementedError('get_parent is abstract')
451
403
 
 
404
    def get_submit_branch(self):
 
405
        """Return the submit location of the branch.
 
406
 
 
407
        This is the default location for bundle.  The usual
 
408
        pattern is that the user can override it by specifying a
 
409
        location.
 
410
        """
 
411
        return self.get_config().get_user_option('submit_branch')
 
412
 
 
413
    def set_submit_branch(self, location):
 
414
        """Return the submit location of the branch.
 
415
 
 
416
        This is the default location for bundle.  The usual
 
417
        pattern is that the user can override it by specifying a
 
418
        location.
 
419
        """
 
420
        self.get_config().set_user_option('submit_branch', location)
 
421
 
452
422
    def get_push_location(self):
453
423
        """Return the None or the location to push this branch to."""
454
424
        raise NotImplementedError('get_push_location is abstract')
578
548
        In particular this checks that revisions given in the revision-history
579
549
        do actually match up in the revision graph, and that they're all 
580
550
        present in the repository.
 
551
        
 
552
        Callers will typically also want to check the repository.
581
553
 
582
554
        :return: A BranchCheckResult.
583
555
        """
586
558
            try:
587
559
                revision = self.repository.get_revision(revision_id)
588
560
            except errors.NoSuchRevision, e:
589
 
                raise BzrCheckError("mainline revision {%s} not in repository"
590
 
                        % revision_id)
 
561
                raise errors.BzrCheckError("mainline revision {%s} not in repository"
 
562
                            % revision_id)
591
563
            # In general the first entry on the revision history has no parents.
592
564
            # But it's not illegal for it to have parents listed; this can happen
593
565
            # in imports from Arch when the parents weren't reachable.
594
566
            if mainline_parent_id is not None:
595
567
                if mainline_parent_id not in revision.parent_ids:
596
 
                    raise BzrCheckError("previous revision {%s} not listed among "
 
568
                    raise errors.BzrCheckError("previous revision {%s} not listed among "
597
569
                                        "parents of {%s}"
598
570
                                        % (mainline_parent_id, revision_id))
599
571
            mainline_parent_id = revision_id
634
606
        except NoSuchFile:
635
607
            raise NotBranchError(path=transport.base)
636
608
        except KeyError:
637
 
            raise errors.UnknownFormatError(format_string)
 
609
            raise errors.UnknownFormatError(format=format_string)
638
610
 
639
611
    @classmethod
640
612
    def get_default_format(klass):
767
739
        utf8_files = [('revision-history', ''),
768
740
                      ('branch-name', ''),
769
741
                      ]
770
 
        control_files = LockableFiles(branch_transport, 'lock', LockDir)
 
742
        control_files = LockableFiles(branch_transport, 'lock', lockdir.LockDir)
771
743
        control_files.create_lock()
772
744
        control_files.lock_write()
773
745
        control_files.put_utf8('format', self.get_format_string())
792
764
            format = BranchFormat.find_format(a_bzrdir)
793
765
            assert format.__class__ == self.__class__
794
766
        transport = a_bzrdir.get_branch_transport(None)
795
 
        control_files = LockableFiles(transport, 'lock', LockDir)
 
767
        control_files = LockableFiles(transport, 'lock', lockdir.LockDir)
796
768
        return BzrBranch5(_format=self,
797
769
                          _control_files=control_files,
798
770
                          a_bzrdir=a_bzrdir,
913
885
        self._base = self._transport.base
914
886
        self._format = _format
915
887
        if _control_files is None:
916
 
            raise BzrBadParameterMissing('_control_files')
 
888
            raise ValueError('BzrBranch _control_files is None')
917
889
        self.control_files = _control_files
918
890
        if deprecated_passed(init):
919
891
            warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
934
906
                 stacklevel=2)
935
907
            if (not relax_version_check
936
908
                and not self._format.is_supported()):
937
 
                raise errors.UnsupportedFormatError(
938
 
                        'sorry, branch format %r not supported' % fmt,
939
 
                        ['use a different bzr version',
940
 
                         'or remove the .bzr directory'
941
 
                         ' and "bzr init" again'])
 
909
                raise errors.UnsupportedFormatError(format=fmt)
942
910
        if deprecated_passed(transport):
943
911
            warn("BzrBranch.__init__(transport=XXX...): The transport "
944
912
                 "parameter is deprecated as of bzr 0.8. "
962
930
        # XXX: cache_root seems to be unused, 2006-01-13 mbp
963
931
        if hasattr(self, 'cache_root') and self.cache_root is not None:
964
932
            try:
965
 
                rmtree(self.cache_root)
 
933
                osutils.rmtree(self.cache_root)
966
934
            except:
967
935
                pass
968
936
            self.cache_root = None
1011
979
        FIXME: DELETE THIS METHOD when pre 0.8 support is removed.
1012
980
        """
1013
981
        if format is None:
1014
 
            format = BzrBranchFormat.find_format(self.bzrdir)
 
982
            format = BranchFormat.find_format(self.bzrdir)
1015
983
        self._format = format
1016
984
        mutter("got branch format %s", self._format)
1017
985
 
1100
1068
        return list(history)
1101
1069
 
1102
1070
    @needs_write_lock
 
1071
    def generate_revision_history(self, revision_id, last_rev=None, 
 
1072
        other_branch=None):
 
1073
        """Create a new revision history that will finish with revision_id.
 
1074
        
 
1075
        :param revision_id: the new tip to use.
 
1076
        :param last_rev: The previous last_revision. If not None, then this
 
1077
            must be a ancestory of revision_id, or DivergedBranches is raised.
 
1078
        :param other_branch: The other branch that DivergedBranches should
 
1079
            raise with respect to.
 
1080
        """
 
1081
        # stop_revision must be a descendant of last_revision
 
1082
        stop_graph = self.repository.get_revision_graph(revision_id)
 
1083
        if last_rev is not None and last_rev not in stop_graph:
 
1084
            # our previous tip is not merged into stop_revision
 
1085
            raise errors.DivergedBranches(self, other_branch)
 
1086
        # make a new revision history from the graph
 
1087
        current_rev_id = revision_id
 
1088
        new_history = []
 
1089
        while current_rev_id not in (None, revision.NULL_REVISION):
 
1090
            new_history.append(current_rev_id)
 
1091
            current_rev_id_parents = stop_graph[current_rev_id]
 
1092
            try:
 
1093
                current_rev_id = current_rev_id_parents[0]
 
1094
            except IndexError:
 
1095
                current_rev_id = None
 
1096
        new_history.reverse()
 
1097
        self.set_revision_history(new_history)
 
1098
 
 
1099
    @needs_write_lock
1103
1100
    def update_revisions(self, other, stop_revision=None):
1104
1101
        """See Branch.update_revisions."""
1105
1102
        other.lock_read()
1119
1116
            if stop_revision in my_ancestry:
1120
1117
                # last_revision is a descendant of stop_revision
1121
1118
                return
1122
 
            # stop_revision must be a descendant of last_revision
1123
 
            stop_graph = self.repository.get_revision_graph(stop_revision)
1124
 
            if last_rev is not None and last_rev not in stop_graph:
1125
 
                # our previous tip is not merged into stop_revision
1126
 
                raise errors.DivergedBranches(self, other)
1127
 
            # make a new revision history from the graph
1128
 
            current_rev_id = stop_revision
1129
 
            new_history = []
1130
 
            while current_rev_id not in (None, NULL_REVISION):
1131
 
                new_history.append(current_rev_id)
1132
 
                current_rev_id_parents = stop_graph[current_rev_id]
1133
 
                try:
1134
 
                    current_rev_id = current_rev_id_parents[0]
1135
 
                except IndexError:
1136
 
                    current_rev_id = None
1137
 
            new_history.reverse()
1138
 
            self.set_revision_history(new_history)
 
1119
            self.generate_revision_history(stop_revision, last_rev=last_rev,
 
1120
                other_branch=other)
1139
1121
        finally:
1140
1122
            other.unlock()
1141
1123
 
1146
1128
    @deprecated_method(zero_eight)
1147
1129
    def working_tree(self):
1148
1130
        """Create a Working tree object for this branch."""
1149
 
        from bzrlib.workingtree import WorkingTree
 
1131
 
1150
1132
        from bzrlib.transport.local import LocalTransport
1151
1133
        if (self.base.find('://') != -1 or 
1152
1134
            not isinstance(self._transport, LocalTransport)):
1173
1155
 
1174
1156
    def get_parent(self):
1175
1157
        """See Branch.get_parent."""
1176
 
        import errno
 
1158
 
1177
1159
        _locs = ['parent', 'pull', 'x-pull']
1178
1160
        assert self.base[-1] == '/'
1179
1161
        for l in _locs:
1190
1172
 
1191
1173
    def get_push_location(self):
1192
1174
        """See Branch.get_push_location."""
1193
 
        config = bzrlib.config.BranchConfig(self)
1194
 
        push_loc = config.get_user_option('push_location')
 
1175
        push_loc = self.get_config().get_user_option('push_location')
1195
1176
        return push_loc
1196
1177
 
1197
1178
    def set_push_location(self, location):
1198
1179
        """See Branch.set_push_location."""
1199
 
        config = bzrlib.config.LocationConfig(self.base)
1200
 
        config.set_user_option('push_location', location)
 
1180
        self.get_config().set_user_option('push_location', location, 
 
1181
                                          local=True)
1201
1182
 
1202
1183
    @needs_write_lock
1203
1184
    def set_parent(self, url):
1221
1202
            url = urlutils.relative_url(self.base, url)
1222
1203
            self.control_files.put('parent', url + '\n')
1223
1204
 
 
1205
    @deprecated_function(zero_nine)
1224
1206
    def tree_config(self):
 
1207
        """DEPRECATED; call get_config instead.  
 
1208
        TreeConfig has become part of BranchConfig."""
1225
1209
        return TreeConfig(self)
1226
1210
 
1227
1211
 
1416
1400
 
1417
1401
 
1418
1402
@deprecated_function(zero_eight)
1419
 
def ScratchBranch(*args, **kwargs):
1420
 
    """See bzrlib.bzrdir.ScratchDir."""
1421
 
    d = ScratchDir(*args, **kwargs)
1422
 
    return d.open_branch()
1423
 
 
1424
 
 
1425
 
@deprecated_function(zero_eight)
1426
1403
def is_control_file(*args, **kwargs):
1427
1404
    """See bzrlib.workingtree.is_control_file."""
1428
1405
    return bzrlib.workingtree.is_control_file(*args, **kwargs)