26
25
sha_file, appendpath, file_kind
28
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
27
from bzrlib.errors import BzrError, InvalidRevisionNumber, InvalidRevisionId
30
29
from bzrlib.textui import show_status
31
30
from bzrlib.revision import Revision
32
31
from bzrlib.delta import compare_trees
33
32
from bzrlib.tree import EmptyTree, RevisionTree
34
from bzrlib.inventory import Inventory
35
from bzrlib.weavestore import WeaveStore
36
from bzrlib.store import ImmutableStore
41
INVENTORY_FILEID = '__inventory'
42
ANCESTRY_FILEID = '__ancestry'
45
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
46
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
38
BZR_BRANCH_FORMAT = "Bazaar-NG branch, format 0.0.4\n"
47
39
## TODO: Maybe include checks for common corruption of newlines, etc?
50
42
# TODO: Some operations like log might retrieve the same revisions
51
43
# repeatedly to calculate deltas. We could perhaps have a weakref
52
# cache in memory to make this faster. In general anything can be
53
# cached in memory between lock and unlock operations.
44
# cache in memory to make this faster.
55
46
# TODO: please move the revision-string syntax stuff out of the branch
56
47
# object; it's clutter
309
301
raise BzrError("invalid controlfile mode %r" % mode)
311
303
def _make_control(self):
304
from bzrlib.inventory import Inventory
312
306
os.mkdir(self.controlfilename([]))
313
307
self.controlfile('README', 'w').write(
314
308
"This is a Bazaar-NG control directory.\n"
315
309
"Do not change any files in this directory.\n")
316
self.controlfile('branch-format', 'w').write(BZR_BRANCH_FORMAT_5)
317
for d in ('text-store', 'revision-store',
310
self.controlfile('branch-format', 'w').write(BZR_BRANCH_FORMAT)
311
for d in ('text-store', 'inventory-store', 'revision-store'):
319
312
os.mkdir(self.controlfilename(d))
320
313
for f in ('revision-history', 'merged-patches',
321
314
'pending-merged-patches', 'branch-name',
328
321
# them; they're not needed for now and so ommitted for
330
323
f = self.controlfile('inventory','w')
331
bzrlib.xml5.serializer_v5.write_inventory(Inventory(), f)
324
bzrlib.xml.serializer_v4.write_inventory(Inventory(), f)
335
327
def _check_format(self):
336
328
"""Check this branch format is supported.
338
The format level is stored, as an integer, in
339
self._branch_format for code that needs to check it later.
330
The current tool only supports the current unstable format.
341
332
In the future, we might need different in-memory Branch
342
333
classes to support downlevel branches. But not yet.
335
# This ignores newlines so that we can open branches created
336
# on Windows from Linux and so on. I think it might be better
337
# to always make all internal files in unix format.
344
338
fmt = self.controlfile('branch-format', 'r').read()
345
if fmt == BZR_BRANCH_FORMAT_5:
346
self._branch_format = 5
348
raise BzrError('sorry, branch format "%s" not supported; '
349
'use a different bzr version, '
350
'or run "bzr upgrade", '
351
'or remove the .bzr directory and "bzr init" again'
352
% fmt.rstrip('\n\r'))
339
fmt = fmt.replace('\r\n', '\n')
340
if fmt != BZR_BRANCH_FORMAT:
341
raise BzrError('sorry, branch format %r not supported' % fmt,
342
['use a different bzr version',
343
'or remove the .bzr directory and "bzr init" again'])
354
345
def get_root_id(self):
355
346
"""Return the id of this branches root"""
371
362
def read_working_inventory(self):
372
363
"""Read the working inventory."""
364
from bzrlib.inventory import Inventory
375
367
# ElementTree does its own conversion from UTF-8, so open in
377
369
f = self.controlfile('inventory', 'rb')
378
return bzrlib.xml5.serializer_v5.read_inventory(f)
370
return bzrlib.xml.serializer_v4.read_inventory(f)
651
643
return bzrlib.osutils.sha_file(self.get_revision_xml(revision_id))
654
def get_ancestry(self, revision_id):
655
"""Return a list of revision-ids integrated by a revision.
657
w = self.weave_store.get_weave(ANCESTRY_FILEID)
659
return [l[:-1] for l in w.get_iter(w.lookup(revision_id))]
662
def get_inventory_weave(self):
663
return self.weave_store.get_weave(INVENTORY_FILEID)
666
def get_inventory(self, revision_id):
667
"""Get Inventory object by hash."""
668
# FIXME: The text gets passed around a lot coming from the weave.
669
f = StringIO(self.get_inventory_xml(revision_id))
670
return bzrlib.xml5.serializer_v5.read_inventory(f)
673
def get_inventory_xml(self, revision_id):
646
def get_inventory(self, inventory_id):
647
"""Get Inventory object by hash.
649
TODO: Perhaps for this and similar methods, take a revision
650
parameter which can be either an integer revno or a
652
from bzrlib.inventory import Inventory
654
f = self.get_inventory_xml_file(inventory_id)
655
return bzrlib.xml.serializer_v4.read_inventory(f)
658
def get_inventory_xml(self, inventory_id):
674
659
"""Get inventory XML as a file object."""
676
assert isinstance(revision_id, basestring), type(revision_id)
677
iw = self.get_inventory_weave()
678
return iw.get_text(iw.lookup(revision_id))
680
raise bzrlib.errors.HistoryMissing(self, 'inventory', revision_id)
683
def get_inventory_sha1(self, revision_id):
660
return self.inventory_store[inventory_id]
662
get_inventory_xml_file = get_inventory_xml
665
def get_inventory_sha1(self, inventory_id):
684
666
"""Return the sha1 hash of the inventory entry
686
return self.get_revision(revision_id).inventory_sha1
668
return sha_file(self.get_inventory_xml(inventory_id))
689
671
def get_revision_inventory(self, revision_id):
690
672
"""Return inventory of a past revision."""
691
# bzr 0.0.6 and later imposes the constraint that the inventory_id
673
# bzr 0.0.6 imposes the constraint that the inventory_id
692
674
# must be the same as its revision, so this is trivial.
693
675
if revision_id == None:
676
from bzrlib.inventory import Inventory
694
677
return Inventory(self.get_root_id())
696
679
return self.get_inventory(revision_id)
716
699
>>> sb = ScratchBranch(files=['foo', 'foo~'])
717
700
>>> sb.common_ancestor(sb) == (None, None)
719
>>> commit.commit(sb, "Committing first revision")
702
>>> commit.commit(sb, "Committing first revision", verbose=False)
720
703
>>> sb.common_ancestor(sb)[0]
722
705
>>> clone = sb.clone()
723
>>> commit.commit(sb, "Committing second revision")
706
>>> commit.commit(sb, "Committing second revision", verbose=False)
724
707
>>> sb.common_ancestor(sb)[0]
726
709
>>> sb.common_ancestor(clone)[0]
728
>>> commit.commit(clone, "Committing divergent second revision")
711
>>> commit.commit(clone, "Committing divergent second revision",
729
713
>>> sb.common_ancestor(clone)[0]
731
715
>>> sb.common_ancestor(clone) == clone.common_ancestor(sb)
835
819
## note("Added %d revisions." % count)
822
def install_revisions(self, other, revision_ids, pb):
823
if hasattr(other.revision_store, "prefetch"):
824
other.revision_store.prefetch(revision_ids)
825
if hasattr(other.inventory_store, "prefetch"):
826
inventory_ids = [other.get_revision(r).inventory_id
827
for r in revision_ids]
828
other.inventory_store.prefetch(inventory_ids)
831
pb = bzrlib.ui.ui_factory.progress_bar()
838
for i, rev_id in enumerate(revision_ids):
839
pb.update('fetching revision', i+1, len(revision_ids))
841
rev = other.get_revision(rev_id)
842
except bzrlib.errors.NoSuchRevision:
846
revisions.append(rev)
847
inv = other.get_inventory(str(rev.inventory_id))
848
for key, entry in inv.iter_entries():
849
if entry.text_id is None:
851
if entry.text_id not in self.text_store:
852
needed_texts.add(entry.text_id)
856
count, cp_fail = self.text_store.copy_multi(other.text_store,
858
#print "Added %d texts." % count
859
inventory_ids = [ f.inventory_id for f in revisions ]
860
count, cp_fail = self.inventory_store.copy_multi(other.inventory_store,
862
#print "Added %d inventories." % count
863
revision_ids = [ f.revision_id for f in revisions]
865
count, cp_fail = self.revision_store.copy_multi(other.revision_store,
868
assert len(cp_fail) == 0
869
return count, failures
839
872
def commit(self, *args, **kw):
840
from bzrlib.commit import Commit
841
Commit().commit(self, *args, **kw)
873
from bzrlib.commit import commit
874
commit(self, *args, **kw)
844
877
def lookup_revision(self, revision):