~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-08-05 02:53:57 UTC
  • mto: (1092.1.41) (1185.3.4) (974.1.47)
  • mto: This revision was merged to the branch mainline in revision 1110.
  • Revision ID: aaron.bentley@utoronto.ca-20050805025357-9d90b2e4c066eb4b
Switched from text-id to hashcache for merge optimization

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
 
import sys
19
 
import os
 
18
import sys, os
20
19
 
21
20
import bzrlib
22
21
from bzrlib.trace import mutter, note
23
 
from bzrlib.osutils import isdir, quotefn, compact_date, rand_bytes, \
24
 
     splitpath, \
 
22
from bzrlib.osutils import isdir, quotefn, compact_date, rand_bytes, splitpath, \
25
23
     sha_file, appendpath, file_kind
26
 
from bzrlib.errors import BzrError, InvalidRevisionNumber, InvalidRevisionId
27
 
import bzrlib.errors
28
 
from bzrlib.textui import show_status
29
 
from bzrlib.revision import Revision
30
 
from bzrlib.xml import unpack_xml
31
 
from bzrlib.delta import compare_trees
32
 
from bzrlib.tree import EmptyTree, RevisionTree
33
 
        
 
24
from bzrlib.errors import BzrError
 
25
 
34
26
BZR_BRANCH_FORMAT = "Bazaar-NG branch, format 0.0.4\n"
35
27
## TODO: Maybe include checks for common corruption of newlines, etc?
36
28
 
37
29
 
38
 
# TODO: Some operations like log might retrieve the same revisions
39
 
# repeatedly to calculate deltas.  We could perhaps have a weakref
40
 
# cache in memory to make this faster.
41
 
 
42
 
# TODO: please move the revision-string syntax stuff out of the branch
43
 
# object; it's clutter
44
 
 
45
30
 
46
31
def find_branch(f, **args):
47
32
    if f and (f.startswith('http://') or f.startswith('https://')):
133
118
        Exception.__init__(self, "These branches have diverged.")
134
119
 
135
120
 
 
121
class NoSuchRevision(BzrError):
 
122
    def __init__(self, branch, revision):
 
123
        self.branch = branch
 
124
        self.revision = revision
 
125
        msg = "Branch %s has no revision %d" % (branch, revision)
 
126
        BzrError.__init__(self, msg)
 
127
 
 
128
 
136
129
######################################################################
137
130
# branch objects
138
131
 
319
312
            self.controlfile(f, 'w').write('')
320
313
        mutter('created control directory in ' + self.base)
321
314
 
322
 
        # if we want per-tree root ids then this is the place to set
323
 
        # them; they're not needed for now and so ommitted for
324
 
        # simplicity.
325
 
        pack_xml(Inventory(), self.controlfile('inventory','w'))
 
315
        pack_xml(Inventory(gen_root_id()), self.controlfile('inventory','w'))
326
316
 
327
317
 
328
318
    def _check_format(self):
432
422
              add all non-ignored children.  Perhaps do that in a
433
423
              higher-level method.
434
424
        """
 
425
        from bzrlib.textui import show_status
435
426
        # TODO: Re-adding a file that is removed in the working copy
436
427
        # should probably put it back with the previous ID.
437
428
        if isinstance(files, basestring):
510
501
        is the opposite of add.  Removing it is consistent with most
511
502
        other tools.  Maybe an option.
512
503
        """
 
504
        from bzrlib.textui import show_status
513
505
        ## TODO: Normalize names
514
506
        ## TODO: Remove nested loops; better scalability
515
507
        if isinstance(files, basestring):
590
582
            f.close()
591
583
 
592
584
 
593
 
    def get_revision_xml(self, revision_id):
594
 
        """Return XML file object for revision object."""
595
 
        if not revision_id or not isinstance(revision_id, basestring):
596
 
            raise InvalidRevisionId(revision_id)
597
 
 
598
 
        self.lock_read()
599
 
        try:
600
 
            try:
601
 
                return self.revision_store[revision_id]
602
 
            except IndexError:
603
 
                raise bzrlib.errors.NoSuchRevision(self, revision_id)
604
 
        finally:
605
 
            self.unlock()
606
 
 
607
 
 
608
585
    def get_revision(self, revision_id):
609
586
        """Return the Revision object for a named revision"""
610
 
        xml_file = self.get_revision_xml(revision_id)
 
587
        from bzrlib.revision import Revision
 
588
        from bzrlib.xml import unpack_xml
611
589
 
 
590
        self.lock_read()
612
591
        try:
613
 
            r = unpack_xml(Revision, xml_file)
614
 
        except SyntaxError, e:
615
 
            raise bzrlib.errors.BzrError('failed to unpack revision_xml',
616
 
                                         [revision_id,
617
 
                                          str(e)])
 
592
            if not revision_id or not isinstance(revision_id, basestring):
 
593
                raise ValueError('invalid revision-id: %r' % revision_id)
 
594
            r = unpack_xml(Revision, self.revision_store[revision_id])
 
595
        finally:
 
596
            self.unlock()
618
597
            
619
598
        assert r.revision_id == revision_id
620
599
        return r
621
 
 
622
 
 
623
 
    def get_revision_delta(self, revno):
624
 
        """Return the delta for one revision.
625
 
 
626
 
        The delta is relative to its mainline predecessor, or the
627
 
        empty tree for revision 1.
628
 
        """
629
 
        assert isinstance(revno, int)
630
 
        rh = self.revision_history()
631
 
        if not (1 <= revno <= len(rh)):
632
 
            raise InvalidRevisionNumber(revno)
633
 
 
634
 
        # revno is 1-based; list is 0-based
635
 
 
636
 
        new_tree = self.revision_tree(rh[revno-1])
637
 
        if revno == 1:
638
 
            old_tree = EmptyTree()
639
 
        else:
640
 
            old_tree = self.revision_tree(rh[revno-2])
641
 
 
642
 
        return compare_trees(old_tree, new_tree)
643
 
 
644
600
        
645
601
 
646
602
    def get_revision_sha1(self, revision_id):
651
607
        # the revision, (add signatures/remove signatures) and still
652
608
        # have all hash pointers stay consistent.
653
609
        # But for now, just hash the contents.
654
 
        return bzrlib.osutils.sha_file(self.get_revision_xml(revision_id))
 
610
        return sha_file(self.revision_store[revision_id])
655
611
 
656
612
 
657
613
    def get_inventory(self, inventory_id):
663
619
        from bzrlib.inventory import Inventory
664
620
        from bzrlib.xml import unpack_xml
665
621
 
666
 
        return unpack_xml(Inventory, self.get_inventory_xml(inventory_id))
667
 
 
668
 
 
669
 
    def get_inventory_xml(self, inventory_id):
670
 
        """Get inventory XML as a file object."""
671
 
        return self.inventory_store[inventory_id]
 
622
        return unpack_xml(Inventory, self.inventory_store[inventory_id])
672
623
            
673
624
 
674
625
    def get_inventory_sha1(self, inventory_id):
675
626
        """Return the sha1 hash of the inventory entry
676
627
        """
677
 
        return sha_file(self.get_inventory_xml(inventory_id))
 
628
        return sha_file(self.inventory_store[inventory_id])
678
629
 
679
630
 
680
631
    def get_revision_inventory(self, revision_id):
746
697
                return r+1, my_history[r]
747
698
        return None, None
748
699
 
 
700
    def enum_history(self, direction):
 
701
        """Return (revno, revision_id) for history of branch.
 
702
 
 
703
        direction
 
704
            'forward' is from earliest to latest
 
705
            'reverse' is from latest to earliest
 
706
        """
 
707
        rh = self.revision_history()
 
708
        if direction == 'forward':
 
709
            i = 1
 
710
            for rid in rh:
 
711
                yield i, rid
 
712
                i += 1
 
713
        elif direction == 'reverse':
 
714
            i = len(rh)
 
715
            while i > 0:
 
716
                yield i, rh[i-1]
 
717
                i -= 1
 
718
        else:
 
719
            raise ValueError('invalid history direction', direction)
 
720
 
749
721
 
750
722
    def revno(self):
751
723
        """Return current revision number for this branch.
766
738
            return None
767
739
 
768
740
 
769
 
    def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
 
741
    def missing_revisions(self, other, stop_revision=None):
770
742
        """
771
743
        If self and other have not diverged, return a list of the revisions
772
744
        present in other, but missing from self.
810
782
        return other_history[self_len:stop_revision]
811
783
 
812
784
 
813
 
    def update_revisions(self, other, stop_revision=None, revision_ids=None):
 
785
    def update_revisions(self, other, stop_revision=None):
814
786
        """Pull in all new revisions from other branch.
815
787
        
816
788
        >>> from bzrlib.commit import commit
838
810
        pb = ProgressBar()
839
811
 
840
812
        pb.update('comparing histories')
841
 
        if revision_ids is None:
842
 
            revision_ids = self.missing_revisions(other, stop_revision)
 
813
        revision_ids = self.missing_revisions(other, stop_revision)
843
814
 
844
815
        if hasattr(other.revision_store, "prefetch"):
845
816
            other.revision_store.prefetch(revision_ids)
1047
1018
 
1048
1019
        `revision_id` may be None for the null revision, in which case
1049
1020
        an `EmptyTree` is returned."""
 
1021
        from bzrlib.tree import EmptyTree, RevisionTree
1050
1022
        # TODO: refactor this to use an existing revision object
1051
1023
        # so we don't need to read it in twice.
1052
1024
        if revision_id == None:
1053
 
            return EmptyTree()
 
1025
            return EmptyTree(self.get_root_id())
1054
1026
        else:
1055
1027
            inv = self.get_revision_inventory(revision_id)
1056
1028
            return RevisionTree(self.text_store, inv)
1067
1039
 
1068
1040
        If there are no revisions yet, return an `EmptyTree`.
1069
1041
        """
 
1042
        from bzrlib.tree import EmptyTree, RevisionTree
1070
1043
        r = self.last_patch()
1071
1044
        if r == None:
1072
 
            return EmptyTree()
 
1045
            return EmptyTree(self.get_root_id())
1073
1046
        else:
1074
1047
            return RevisionTree(self.text_store, self.get_revision_inventory(r))
1075
1048