18
18
from copy import deepcopy
19
19
from cStringIO import StringIO
24
20
from unittest import TestSuite
25
21
from warnings import warn
28
import bzrlib.bzrdir as bzrdir
24
from bzrlib import bzrdir, errors, lockdir, osutils, revision, \
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,
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,
49
from bzrlib.repository import Repository
50
from bzrlib.revision import (
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,
43
zero_eight, zero_nine,
58
45
from bzrlib.trace import mutter, note
59
import bzrlib.transactions as transactions
60
from bzrlib.transport import Transport, get_transport
62
import bzrlib.urlutils as urlutils
66
48
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
117
99
def open(base, _unsupported=False):
118
"""Open the repository rooted at base.
100
"""Open the branch rooted at base.
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.
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
141
def get_config(self):
142
return bzrlib.config.BranchConfig(self)
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()
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)
168
150
nick = property(_get_nick, _set_nick)
231
213
last_revision = from_history[-1]
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,
265
247
if config is None:
266
config = bzrlib.config.BranchConfig(self)
248
config = self.get_config()
268
250
return self.repository.get_commit_builder(self, parents, config,
269
251
timestamp, timezone, committer, revprops, revision_id)
331
313
If self and other have not diverged, return a list of the revisions
332
314
present in other, but missing from self.
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)
344
>>> wt2.commit("lala!", rev_id="REVISION-ID-1")
346
>>> br1.missing_revisions(br2)
348
>>> br2.missing_revisions(br1)
350
>>> wt1.commit("lala!", rev_id="REVISION-ID-1")
352
>>> br1.missing_revisions(br2)
354
>>> wt2.commit("lala!", rev_id="REVISION-ID-2A")
356
>>> br1.missing_revisions(br2)
358
>>> wt1.commit("lala!", rev_id="REVISION-ID-2B")
360
>>> br1.missing_revisions(br2)
361
Traceback (most recent call last):
362
DivergedBranches: These branches have diverged. Try merge.
364
316
self_history = self.revision_history()
365
317
self_len = len(self_history)
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]
381
333
def update_revisions(self, other, stop_revision=None):
450
402
raise NotImplementedError('get_parent is abstract')
404
def get_submit_branch(self):
405
"""Return the submit location of the branch.
407
This is the default location for bundle. The usual
408
pattern is that the user can override it by specifying a
411
return self.get_config().get_user_option('submit_branch')
413
def set_submit_branch(self, location):
414
"""Return the submit location of the branch.
416
This is the default location for bundle. The usual
417
pattern is that the user can override it by specifying a
420
self.get_config().set_user_option('submit_branch', location)
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.
552
Callers will typically also want to check the repository.
582
554
:return: A BranchCheckResult.
587
559
revision = self.repository.get_revision(revision_id)
588
560
except errors.NoSuchRevision, e:
589
raise BzrCheckError("mainline revision {%s} not in repository"
561
raise errors.BzrCheckError("mainline revision {%s} not in repository"
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
767
739
utf8_files = [('revision-history', ''),
768
740
('branch-name', ''),
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 "
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. "
1011
979
FIXME: DELETE THIS METHOD when pre 0.8 support is removed.
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)
1100
1068
return list(history)
1102
1070
@needs_write_lock
1071
def generate_revision_history(self, revision_id, last_rev=None,
1073
"""Create a new revision history that will finish with revision_id.
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.
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
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]
1093
current_rev_id = current_rev_id_parents[0]
1095
current_rev_id = None
1096
new_history.reverse()
1097
self.set_revision_history(new_history)
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
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
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]
1134
current_rev_id = current_rev_id_parents[0]
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,
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
1150
1132
from bzrlib.transport.local import LocalTransport
1151
1133
if (self.base.find('://') != -1 or
1152
1134
not isinstance(self._transport, LocalTransport)):
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
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,
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')
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)
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()
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)