28
28
import bzrlib.bzrdir as bzrdir
29
29
from bzrlib.config import TreeConfig
30
30
from bzrlib.decorators import needs_read_lock, needs_write_lock
31
from bzrlib.delta import compare_trees
32
31
import bzrlib.errors as errors
33
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
34
NoSuchRevision, NotBranchError,
35
DivergedBranches, LockError,
36
UninitializableFormat,
38
UnlistableBranch, NoSuchFile, NotVersionedError,
32
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches,
33
HistoryMissing, InvalidRevisionId,
34
InvalidRevisionNumber, LockError, NoSuchFile,
35
NoSuchRevision, NoWorkingTree, NotVersionedError,
36
NotBranchError, UninitializableFormat,
37
UnlistableStore, UnlistableBranch,
40
39
import bzrlib.inventory as inventory
41
40
from bzrlib.inventory import Inventory
42
41
from bzrlib.lockable_files import LockableFiles, TransportLock
50
from bzrlib.textui import show_status
51
from bzrlib.trace import mutter, note
52
from bzrlib.tree import EmptyTree, RevisionTree
53
49
from bzrlib.repository import Repository
54
50
from bzrlib.revision import (
59
55
from bzrlib.store import copy_all
60
56
from bzrlib.symbol_versioning import *
57
from bzrlib.textui import show_status
58
from bzrlib.trace import mutter, note
61
59
import bzrlib.transactions as transactions
62
60
from bzrlib.transport import Transport, get_transport
63
from bzrlib.tree import EmptyTree, RevisionTree
62
import bzrlib.urlutils as urlutils
251
def get_commit_builder(self, parents, config=None, timestamp=None,
252
timezone=None, committer=None, revprops=None,
254
"""Obtain a CommitBuilder for this branch.
256
:param parents: Revision ids of the parents of the new revision.
257
:param config: Optional configuration to use.
258
:param timestamp: Optional timestamp recorded for commit.
259
:param timezone: Optional timezone for timestamp.
260
:param committer: Optional committer to set for commit.
261
:param revprops: Optional dictionary of revision properties.
262
:param revision_id: Optional revision id.
266
config = bzrlib.config.BranchConfig(self)
268
return self.repository.get_commit_builder(self, parents, config,
269
timestamp, timezone, committer, revprops, revision_id)
253
271
def get_master_branch(self):
254
272
"""Return the branch we are bound to.
278
def get_revision_delta(self, revno):
279
"""Return the delta for one revision.
281
The delta is relative to its mainline predecessor, or the
282
empty tree for revision 1.
284
assert isinstance(revno, int)
285
rh = self.revision_history()
286
if not (1 <= revno <= len(rh)):
287
raise InvalidRevisionNumber(revno)
288
return self.repository.get_revision_delta(rh[revno-1])
260
290
def get_root_id(self):
261
291
"""Return the id of this branches root"""
262
292
raise NotImplementedError('get_root_id is abstract')
431
461
revision_id: if not None, the revision history in the new branch will
432
462
be truncated to end with revision_id.
434
# for API compatability, until 0.8 releases we provide the old api:
464
# for API compatibility, until 0.8 releases we provide the old api:
435
465
# def clone(self, to_location, revision=None, basis_branch=None, to_branch_format=None):
436
466
# after 0.8 releases, the *args and **kwargs should be changed:
437
467
# def clone(self, to_bzrdir, revision_id=None):
439
469
kwargs.get('revision', None) or
440
470
kwargs.get('basis_branch', None) or
441
471
(len(args) and isinstance(args[0], basestring))):
442
# backwards compatability api:
472
# backwards compatibility api:
443
473
warn("Branch.clone() has been deprecated for BzrDir.clone() from"
444
474
" bzrlib 0.8.", DeprecationWarning, stacklevel=3)
445
475
# get basis_branch
512
542
destination.set_parent(parent)
546
"""Check consistency of the branch.
548
In particular this checks that revisions given in the revision-history
549
do actually match up in the revision graph, and that they're all
550
present in the repository.
552
:return: A BranchCheckResult.
554
mainline_parent_id = None
555
for revision_id in self.revision_history():
557
revision = self.repository.get_revision(revision_id)
558
except errors.NoSuchRevision, e:
559
raise BzrCheckError("mainline revision {%s} not in repository"
561
# In general the first entry on the revision history has no parents.
562
# But it's not illegal for it to have parents listed; this can happen
563
# in imports from Arch when the parents weren't reachable.
564
if mainline_parent_id is not None:
565
if mainline_parent_id not in revision.parent_ids:
566
raise BzrCheckError("previous revision {%s} not listed among "
568
% (mainline_parent_id, revision_id))
569
mainline_parent_id = revision_id
570
return BranchCheckResult(self)
515
573
class BranchFormat(object):
516
574
"""An encapsulation of the initialization and open routines for a format.
564
622
def initialize(self, a_bzrdir):
565
623
"""Create a branch of this format in a_bzrdir."""
566
raise NotImplementedError(self.initialized)
624
raise NotImplementedError(self.initialize)
568
626
def is_supported(self):
569
627
"""Is this format supported?
991
1049
# not really an object yet, and the transaction is for objects.
992
1050
# transaction.register_clean(history)
994
def get_revision_delta(self, revno):
995
"""Return the delta for one revision.
997
The delta is relative to its mainline predecessor, or the
998
empty tree for revision 1.
1000
assert isinstance(revno, int)
1001
rh = self.revision_history()
1002
if not (1 <= revno <= len(rh)):
1003
raise InvalidRevisionNumber(revno)
1005
# revno is 1-based; list is 0-based
1007
new_tree = self.repository.revision_tree(rh[revno-1])
1009
old_tree = EmptyTree()
1011
old_tree = self.repository.revision_tree(rh[revno-2])
1012
return compare_trees(old_tree, new_tree)
1014
1052
@needs_read_lock
1015
1053
def revision_history(self):
1016
1054
"""See Branch.revision_history."""
1103
1141
"""See Branch.get_parent."""
1105
1143
_locs = ['parent', 'pull', 'x-pull']
1144
assert self.base[-1] == '/'
1106
1145
for l in _locs:
1108
return self.control_files.get_utf8(l).read().strip('\n')
1147
parent = self.control_files.get(l).read().strip('\n')
1109
1148
except NoSuchFile:
1150
# This is an old-format absolute path to a local branch
1151
# turn it into a url
1152
if parent.startswith('/'):
1153
parent = urlutils.local_path_to_url(parent.decode('utf8'))
1154
return urlutils.join(self.base[:-1], parent)
1113
1157
def get_push_location(self):
1132
1176
if url is None:
1133
1177
self.control_files._transport.delete('parent')
1135
self.control_files.put_utf8('parent', url + '\n')
1179
if isinstance(url, unicode):
1181
url = url.encode('ascii')
1182
except UnicodeEncodeError:
1183
raise bzrlib.errors.InvalidURL(url,
1184
"Urls must be 7-bit ascii, "
1185
"use bzrlib.urlutils.escape")
1187
url = urlutils.relative_url(self.base, url)
1188
self.control_files.put('parent', url + '\n')
1137
1190
def tree_config(self):
1138
1191
return TreeConfig(self)
1181
1234
This could memoise the branch, but if thats done
1182
1235
it must be revalidated on each new lock.
1183
So for now we just dont memoise it.
1236
So for now we just don't memoise it.
1184
1237
# RBC 20060304 review this decision.
1186
1239
bound_loc = self.get_bound_location()
1232
1285
# There may be a different check you could do here
1233
1286
# rather than actually trying to install revisions remotely.
1234
1287
# TODO: capture an exception which indicates the remote branch
1236
1289
# If it is up-to-date, this probably should not be a failure
1238
1291
# lock other for write so the revision-history syncing cannot race
1360
class BranchCheckResult(object):
1361
"""Results of checking branch consistency.
1366
def __init__(self, branch):
1367
self.branch = branch
1369
def report_results(self, verbose):
1370
"""Report the check results via trace.note.
1372
:param verbose: Requests more detailed display of what was checked,
1375
note('checked branch %s format %s',
1377
self.branch._format)
1307
1380
######################################################################