~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2005-07-17 18:06:53 UTC
  • Revision ID: mbp@sourcefrog.net-20050717180653-f16d08bd74610f6d
- update more weave code to use intsets

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://')):
104
89
    It is not necessary that f exists.
105
90
 
106
91
    Basically we keep looking up until we find the control directory or
107
 
    run into the root.  If there isn't one, raises NotBranchError.
108
 
    """
 
92
    run into the root."""
109
93
    if f == None:
110
94
        f = os.getcwd()
111
95
    elif hasattr(os.path, 'realpath'):
124
108
        head, tail = os.path.split(f)
125
109
        if head == f:
126
110
            # reached the root, whatever that may be
127
 
            raise bzrlib.errors.NotBranchError('%r is not in a branch' % orig_f)
 
111
            raise BzrError('%r is not in a branch' % orig_f)
128
112
        f = head
129
 
 
130
 
 
131
 
 
132
 
# XXX: move into bzrlib.errors; subclass BzrError    
 
113
    
133
114
class DivergedBranches(Exception):
134
115
    def __init__(self, branch1, branch2):
135
116
        self.branch1 = branch1
137
118
        Exception.__init__(self, "These branches have diverged.")
138
119
 
139
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
 
140
129
######################################################################
141
130
# branch objects
142
131
 
323
312
            self.controlfile(f, 'w').write('')
324
313
        mutter('created control directory in ' + self.base)
325
314
 
326
 
        # if we want per-tree root ids then this is the place to set
327
 
        # them; they're not needed for now and so ommitted for
328
 
        # simplicity.
329
 
        pack_xml(Inventory(), self.controlfile('inventory','w'))
 
315
        pack_xml(Inventory(gen_root_id()), self.controlfile('inventory','w'))
330
316
 
331
317
 
332
318
    def _check_format(self):
375
361
            # ElementTree does its own conversion from UTF-8, so open in
376
362
            # binary.
377
363
            inv = unpack_xml(Inventory,
378
 
                             self.controlfile('inventory', 'rb'))
 
364
                                  self.controlfile('inventory', 'rb'))
379
365
            mutter("loaded inventory of %d items in %f"
380
366
                   % (len(inv), time() - before))
381
367
            return inv
436
422
              add all non-ignored children.  Perhaps do that in a
437
423
              higher-level method.
438
424
        """
 
425
        from bzrlib.textui import show_status
439
426
        # TODO: Re-adding a file that is removed in the working copy
440
427
        # should probably put it back with the previous ID.
441
428
        if isinstance(files, basestring):
514
501
        is the opposite of add.  Removing it is consistent with most
515
502
        other tools.  Maybe an option.
516
503
        """
 
504
        from bzrlib.textui import show_status
517
505
        ## TODO: Normalize names
518
506
        ## TODO: Remove nested loops; better scalability
519
507
        if isinstance(files, basestring):
594
582
            f.close()
595
583
 
596
584
 
597
 
    def get_revision_xml(self, revision_id):
598
 
        """Return XML file object for revision object."""
599
 
        if not revision_id or not isinstance(revision_id, basestring):
600
 
            raise InvalidRevisionId(revision_id)
601
 
 
602
 
        self.lock_read()
603
 
        try:
604
 
            try:
605
 
                return self.revision_store[revision_id]
606
 
            except IndexError:
607
 
                raise bzrlib.errors.NoSuchRevision(self, revision_id)
608
 
        finally:
609
 
            self.unlock()
610
 
 
611
 
 
612
585
    def get_revision(self, revision_id):
613
586
        """Return the Revision object for a named revision"""
614
 
        xml_file = self.get_revision_xml(revision_id)
 
587
        from bzrlib.revision import Revision
 
588
        from bzrlib.xml import unpack_xml
615
589
 
 
590
        self.lock_read()
616
591
        try:
617
 
            r = unpack_xml(Revision, xml_file)
618
 
        except SyntaxError, e:
619
 
            raise bzrlib.errors.BzrError('failed to unpack revision_xml',
620
 
                                         [revision_id,
621
 
                                          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()
622
597
            
623
598
        assert r.revision_id == revision_id
624
599
        return r
625
 
 
626
 
 
627
 
    def get_revision_delta(self, revno):
628
 
        """Return the delta for one revision.
629
 
 
630
 
        The delta is relative to its mainline predecessor, or the
631
 
        empty tree for revision 1.
632
 
        """
633
 
        assert isinstance(revno, int)
634
 
        rh = self.revision_history()
635
 
        if not (1 <= revno <= len(rh)):
636
 
            raise InvalidRevisionNumber(revno)
637
 
 
638
 
        # revno is 1-based; list is 0-based
639
 
 
640
 
        new_tree = self.revision_tree(rh[revno-1])
641
 
        if revno == 1:
642
 
            old_tree = EmptyTree()
643
 
        else:
644
 
            old_tree = self.revision_tree(rh[revno-2])
645
 
 
646
 
        return compare_trees(old_tree, new_tree)
647
 
 
648
600
        
649
601
 
650
602
    def get_revision_sha1(self, revision_id):
655
607
        # the revision, (add signatures/remove signatures) and still
656
608
        # have all hash pointers stay consistent.
657
609
        # But for now, just hash the contents.
658
 
        return bzrlib.osutils.sha_file(self.get_revision_xml(revision_id))
 
610
        return sha_file(self.revision_store[revision_id])
659
611
 
660
612
 
661
613
    def get_inventory(self, inventory_id):
667
619
        from bzrlib.inventory import Inventory
668
620
        from bzrlib.xml import unpack_xml
669
621
 
670
 
        return unpack_xml(Inventory, self.get_inventory_xml(inventory_id))
671
 
 
672
 
 
673
 
    def get_inventory_xml(self, inventory_id):
674
 
        """Get inventory XML as a file object."""
675
 
        return self.inventory_store[inventory_id]
 
622
        return unpack_xml(Inventory, self.inventory_store[inventory_id])
676
623
            
677
624
 
678
625
    def get_inventory_sha1(self, inventory_id):
679
626
        """Return the sha1 hash of the inventory entry
680
627
        """
681
 
        return sha_file(self.get_inventory_xml(inventory_id))
 
628
        return sha_file(self.inventory_store[inventory_id])
682
629
 
683
630
 
684
631
    def get_revision_inventory(self, revision_id):
750
697
                return r+1, my_history[r]
751
698
        return None, None
752
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
 
753
721
 
754
722
    def revno(self):
755
723
        """Return current revision number for this branch.
838
806
        True
839
807
        """
840
808
        from bzrlib.progress import ProgressBar
 
809
        try:
 
810
            set
 
811
        except NameError:
 
812
            from sets import Set as set
841
813
 
842
814
        pb = ProgressBar()
843
815
 
1050
1022
 
1051
1023
        `revision_id` may be None for the null revision, in which case
1052
1024
        an `EmptyTree` is returned."""
 
1025
        from bzrlib.tree import EmptyTree, RevisionTree
1053
1026
        # TODO: refactor this to use an existing revision object
1054
1027
        # so we don't need to read it in twice.
1055
1028
        if revision_id == None:
1056
 
            return EmptyTree()
 
1029
            return EmptyTree(self.get_root_id())
1057
1030
        else:
1058
1031
            inv = self.get_revision_inventory(revision_id)
1059
1032
            return RevisionTree(self.text_store, inv)
1070
1043
 
1071
1044
        If there are no revisions yet, return an `EmptyTree`.
1072
1045
        """
 
1046
        from bzrlib.tree import EmptyTree, RevisionTree
1073
1047
        r = self.last_patch()
1074
1048
        if r == None:
1075
 
            return EmptyTree()
 
1049
            return EmptyTree(self.get_root_id())
1076
1050
        else:
1077
1051
            return RevisionTree(self.text_store, self.get_revision_inventory(r))
1078
1052