~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-18 02:24:28 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-20050818022428-4c0bf84005f4dba8
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472

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, os
 
18
import sys
 
19
import os
19
20
 
20
21
import bzrlib
21
22
from bzrlib.trace import mutter, note
22
 
from bzrlib.osutils import isdir, quotefn, compact_date, rand_bytes, splitpath, \
 
23
from bzrlib.osutils import isdir, quotefn, compact_date, rand_bytes, \
 
24
     splitpath, \
23
25
     sha_file, appendpath, file_kind
24
 
from bzrlib.errors import BzrError
25
 
 
 
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
        
26
34
BZR_BRANCH_FORMAT = "Bazaar-NG branch, format 0.0.4\n"
27
35
## TODO: Maybe include checks for common corruption of newlines, etc?
28
36
 
29
37
 
 
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
 
30
45
 
31
46
def find_branch(f, **args):
32
47
    if f and (f.startswith('http://') or f.startswith('https://')):
118
133
        Exception.__init__(self, "These branches have diverged.")
119
134
 
120
135
 
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
 
 
129
136
######################################################################
130
137
# branch objects
131
138
 
312
319
            self.controlfile(f, 'w').write('')
313
320
        mutter('created control directory in ' + self.base)
314
321
 
315
 
        pack_xml(Inventory(gen_root_id()), self.controlfile('inventory','w'))
 
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'))
316
326
 
317
327
 
318
328
    def _check_format(self):
422
432
              add all non-ignored children.  Perhaps do that in a
423
433
              higher-level method.
424
434
        """
425
 
        from bzrlib.textui import show_status
426
435
        # TODO: Re-adding a file that is removed in the working copy
427
436
        # should probably put it back with the previous ID.
428
437
        if isinstance(files, basestring):
501
510
        is the opposite of add.  Removing it is consistent with most
502
511
        other tools.  Maybe an option.
503
512
        """
504
 
        from bzrlib.textui import show_status
505
513
        ## TODO: Normalize names
506
514
        ## TODO: Remove nested loops; better scalability
507
515
        if isinstance(files, basestring):
582
590
            f.close()
583
591
 
584
592
 
 
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
 
585
608
    def get_revision(self, revision_id):
586
609
        """Return the Revision object for a named revision"""
587
 
        from bzrlib.revision import Revision
588
 
        from bzrlib.xml import unpack_xml
 
610
        xml_file = self.get_revision_xml(revision_id)
589
611
 
590
 
        self.lock_read()
591
612
        try:
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()
 
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)])
597
618
            
598
619
        assert r.revision_id == revision_id
599
620
        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
 
600
644
        
601
645
 
602
646
    def get_revision_sha1(self, revision_id):
607
651
        # the revision, (add signatures/remove signatures) and still
608
652
        # have all hash pointers stay consistent.
609
653
        # But for now, just hash the contents.
610
 
        return sha_file(self.revision_store[revision_id])
 
654
        return bzrlib.osutils.sha_file(self.get_revision_xml(revision_id))
611
655
 
612
656
 
613
657
    def get_inventory(self, inventory_id):
619
663
        from bzrlib.inventory import Inventory
620
664
        from bzrlib.xml import unpack_xml
621
665
 
622
 
        return unpack_xml(Inventory, self.inventory_store[inventory_id])
 
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]
623
672
            
624
673
 
625
674
    def get_inventory_sha1(self, inventory_id):
626
675
        """Return the sha1 hash of the inventory entry
627
676
        """
628
 
        return sha_file(self.inventory_store[inventory_id])
 
677
        return sha_file(self.get_inventory_xml(inventory_id))
629
678
 
630
679
 
631
680
    def get_revision_inventory(self, revision_id):
697
746
                return r+1, my_history[r]
698
747
        return None, None
699
748
 
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
 
 
721
749
 
722
750
    def revno(self):
723
751
        """Return current revision number for this branch.
1018
1046
 
1019
1047
        `revision_id` may be None for the null revision, in which case
1020
1048
        an `EmptyTree` is returned."""
1021
 
        from bzrlib.tree import EmptyTree, RevisionTree
1022
1049
        # TODO: refactor this to use an existing revision object
1023
1050
        # so we don't need to read it in twice.
1024
1051
        if revision_id == None:
1025
 
            return EmptyTree(self.get_root_id())
 
1052
            return EmptyTree()
1026
1053
        else:
1027
1054
            inv = self.get_revision_inventory(revision_id)
1028
1055
            return RevisionTree(self.text_store, inv)
1039
1066
 
1040
1067
        If there are no revisions yet, return an `EmptyTree`.
1041
1068
        """
1042
 
        from bzrlib.tree import EmptyTree, RevisionTree
1043
1069
        r = self.last_patch()
1044
1070
        if r == None:
1045
 
            return EmptyTree(self.get_root_id())
 
1071
            return EmptyTree()
1046
1072
        else:
1047
1073
            return RevisionTree(self.text_store, self.get_revision_inventory(r))
1048
1074