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
from bzrlib.delta import compare_trees
32
30
import bzrlib.errors as errors
33
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
34
NoSuchRevision, HistoryMissing, NotBranchError,
35
DivergedBranches, LockError,
36
UninitializableFormat,
38
UnlistableBranch, NoSuchFile, NotVersionedError,
40
import bzrlib.inventory as inventory
41
from bzrlib.inventory import Inventory
31
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches,
32
HistoryMissing, InvalidRevisionId,
33
InvalidRevisionNumber, LockError, NoSuchFile,
34
NoSuchRevision, NoWorkingTree, NotVersionedError,
35
NotBranchError, UninitializableFormat,
36
UnlistableStore, UnlistableBranch,
42
38
from bzrlib.lockable_files import LockableFiles, TransportLock
43
from bzrlib.lockdir import LockDir
44
from bzrlib.osutils import (isdir, quotefn,
45
rename, splitpath, sha_file,
46
file_kind, abspath, normpath, pathjoin,
50
from bzrlib.textui import show_status
39
from bzrlib.symbol_versioning import (deprecated_function,
51
45
from bzrlib.trace import mutter, note
52
from bzrlib.tree import EmptyTree, RevisionTree
53
from bzrlib.repository import Repository
54
from bzrlib.revision import (
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
68
48
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
233
def get_commit_builder(self, parents, config=None, timestamp=None,
234
timezone=None, committer=None, revprops=None,
236
"""Obtain a CommitBuilder for this branch.
238
:param parents: Revision ids of the parents of the new revision.
239
:param config: Optional configuration to use.
240
:param timestamp: Optional timestamp recorded for commit.
241
:param timezone: Optional timezone for timestamp.
242
:param committer: Optional committer to set for commit.
243
:param revprops: Optional dictionary of revision properties.
244
:param revision_id: Optional revision id.
248
config = bzrlib.config.BranchConfig(self)
250
return self.repository.get_commit_builder(self, parents, config,
251
timestamp, timezone, committer, revprops, revision_id)
253
253
def get_master_branch(self):
254
254
"""Return the branch we are bound to.
260
def get_revision_delta(self, revno):
261
"""Return the delta for one revision.
263
The delta is relative to its mainline predecessor, or the
264
empty tree for revision 1.
266
assert isinstance(revno, int)
267
rh = self.revision_history()
268
if not (1 <= revno <= len(rh)):
269
raise InvalidRevisionNumber(revno)
270
return self.repository.get_revision_delta(rh[revno-1])
260
272
def get_root_id(self):
261
273
"""Return the id of this branches root"""
262
274
raise NotImplementedError('get_root_id is abstract')
431
443
revision_id: if not None, the revision history in the new branch will
432
444
be truncated to end with revision_id.
434
# for API compatability, until 0.8 releases we provide the old api:
446
# for API compatibility, until 0.8 releases we provide the old api:
435
447
# def clone(self, to_location, revision=None, basis_branch=None, to_branch_format=None):
436
448
# after 0.8 releases, the *args and **kwargs should be changed:
437
449
# def clone(self, to_bzrdir, revision_id=None):
439
451
kwargs.get('revision', None) or
440
452
kwargs.get('basis_branch', None) or
441
453
(len(args) and isinstance(args[0], basestring))):
442
# backwards compatability api:
454
# backwards compatibility api:
443
455
warn("Branch.clone() has been deprecated for BzrDir.clone() from"
444
456
" bzrlib 0.8.", DeprecationWarning, stacklevel=3)
445
457
# get basis_branch
512
524
destination.set_parent(parent)
528
"""Check consistency of the branch.
530
In particular this checks that revisions given in the revision-history
531
do actually match up in the revision graph, and that they're all
532
present in the repository.
534
Callers will typically also want to check the repository.
536
:return: A BranchCheckResult.
538
mainline_parent_id = None
539
for revision_id in self.revision_history():
541
revision = self.repository.get_revision(revision_id)
542
except errors.NoSuchRevision, e:
543
raise errors.BzrCheckError("mainline revision {%s} not in repository"
545
# In general the first entry on the revision history has no parents.
546
# But it's not illegal for it to have parents listed; this can happen
547
# in imports from Arch when the parents weren't reachable.
548
if mainline_parent_id is not None:
549
if mainline_parent_id not in revision.parent_ids:
550
raise errors.BzrCheckError("previous revision {%s} not listed among "
552
% (mainline_parent_id, revision_id))
553
mainline_parent_id = revision_id
554
return BranchCheckResult(self)
515
557
class BranchFormat(object):
516
558
"""An encapsulation of the initialization and open routines for a format.
679
721
utf8_files = [('revision-history', ''),
680
722
('branch-name', ''),
682
control_files = LockableFiles(branch_transport, 'lock', LockDir)
724
control_files = LockableFiles(branch_transport, 'lock', lockdir.LockDir)
683
725
control_files.create_lock()
684
726
control_files.lock_write()
685
727
control_files.put_utf8('format', self.get_format_string())
704
746
format = BranchFormat.find_format(a_bzrdir)
705
747
assert format.__class__ == self.__class__
706
748
transport = a_bzrdir.get_branch_transport(None)
707
control_files = LockableFiles(transport, 'lock', LockDir)
749
control_files = LockableFiles(transport, 'lock', lockdir.LockDir)
708
750
return BzrBranch5(_format=self,
709
751
_control_files=control_files,
710
752
a_bzrdir=a_bzrdir,
847
889
if (not relax_version_check
848
890
and not self._format.is_supported()):
849
raise errors.UnsupportedFormatError(
850
'sorry, branch format %r not supported' % fmt,
851
['use a different bzr version',
852
'or remove the .bzr directory'
853
' and "bzr init" again'])
891
raise errors.UnsupportedFormatError(format=fmt)
854
892
if deprecated_passed(transport):
855
893
warn("BzrBranch.__init__(transport=XXX...): The transport "
856
894
"parameter is deprecated as of bzr 0.8. "
995
1033
# not really an object yet, and the transaction is for objects.
996
1034
# transaction.register_clean(history)
998
def get_revision_delta(self, revno):
999
"""Return the delta for one revision.
1001
The delta is relative to its mainline predecessor, or the
1002
empty tree for revision 1.
1004
assert isinstance(revno, int)
1005
rh = self.revision_history()
1006
if not (1 <= revno <= len(rh)):
1007
raise InvalidRevisionNumber(revno)
1009
# revno is 1-based; list is 0-based
1011
new_tree = self.repository.revision_tree(rh[revno-1])
1013
old_tree = EmptyTree()
1015
old_tree = self.repository.revision_tree(rh[revno-2])
1016
return compare_trees(old_tree, new_tree)
1018
1036
@needs_read_lock
1019
1037
def revision_history(self):
1020
1038
"""See Branch.revision_history."""
1106
1124
def get_parent(self):
1107
1125
"""See Branch.get_parent."""
1109
1127
_locs = ['parent', 'pull', 'x-pull']
1128
assert self.base[-1] == '/'
1110
1129
for l in _locs:
1112
return self.control_files.get_utf8(l).read().strip('\n')
1131
parent = self.control_files.get(l).read().strip('\n')
1113
1132
except NoSuchFile:
1134
# This is an old-format absolute path to a local branch
1135
# turn it into a url
1136
if parent.startswith('/'):
1137
parent = urlutils.local_path_to_url(parent.decode('utf8'))
1138
return urlutils.join(self.base[:-1], parent)
1117
1141
def get_push_location(self):
1136
1160
if url is None:
1137
1161
self.control_files._transport.delete('parent')
1139
self.control_files.put_utf8('parent', url + '\n')
1163
if isinstance(url, unicode):
1165
url = url.encode('ascii')
1166
except UnicodeEncodeError:
1167
raise bzrlib.errors.InvalidURL(url,
1168
"Urls must be 7-bit ascii, "
1169
"use bzrlib.urlutils.escape")
1171
url = urlutils.relative_url(self.base, url)
1172
self.control_files.put('parent', url + '\n')
1141
1174
def tree_config(self):
1142
1175
return TreeConfig(self)
1306
1339
new_test.id = make_new_test_id()
1307
1340
result.addTest(new_test)
1344
class BranchCheckResult(object):
1345
"""Results of checking branch consistency.
1350
def __init__(self, branch):
1351
self.branch = branch
1353
def report_results(self, verbose):
1354
"""Report the check results via trace.note.
1356
:param verbose: Requests more detailed display of what was checked,
1359
note('checked branch %s format %s',
1361
self.branch._format)
1364
######################################################################
1368
@deprecated_function(zero_eight)
1369
def is_control_file(*args, **kwargs):
1370
"""See bzrlib.workingtree.is_control_file."""
1371
return bzrlib.workingtree.is_control_file(*args, **kwargs)