~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2005-07-22 19:32:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050722193252-d3cdd1bd566c9f6a
doc

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
30
 
43
31
def find_branch(f, **args):
44
32
    if f and (f.startswith('http://') or f.startswith('https://')):
130
118
        Exception.__init__(self, "These branches have diverged.")
131
119
 
132
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
 
133
129
######################################################################
134
130
# branch objects
135
131
 
316
312
            self.controlfile(f, 'w').write('')
317
313
        mutter('created control directory in ' + self.base)
318
314
 
319
 
        # if we want per-tree root ids then this is the place to set
320
 
        # them; they're not needed for now and so ommitted for
321
 
        # simplicity.
322
 
        pack_xml(Inventory(), self.controlfile('inventory','w'))
 
315
        pack_xml(Inventory(gen_root_id()), self.controlfile('inventory','w'))
323
316
 
324
317
 
325
318
    def _check_format(self):
368
361
            # ElementTree does its own conversion from UTF-8, so open in
369
362
            # binary.
370
363
            inv = unpack_xml(Inventory,
371
 
                             self.controlfile('inventory', 'rb'))
 
364
                                  self.controlfile('inventory', 'rb'))
372
365
            mutter("loaded inventory of %d items in %f"
373
366
                   % (len(inv), time() - before))
374
367
            return inv
429
422
              add all non-ignored children.  Perhaps do that in a
430
423
              higher-level method.
431
424
        """
 
425
        from bzrlib.textui import show_status
432
426
        # TODO: Re-adding a file that is removed in the working copy
433
427
        # should probably put it back with the previous ID.
434
428
        if isinstance(files, basestring):
507
501
        is the opposite of add.  Removing it is consistent with most
508
502
        other tools.  Maybe an option.
509
503
        """
 
504
        from bzrlib.textui import show_status
510
505
        ## TODO: Normalize names
511
506
        ## TODO: Remove nested loops; better scalability
512
507
        if isinstance(files, basestring):
587
582
            f.close()
588
583
 
589
584
 
590
 
    def get_revision_xml(self, revision_id):
591
 
        """Return XML file object for revision object."""
592
 
        if not revision_id or not isinstance(revision_id, basestring):
593
 
            raise InvalidRevisionId(revision_id)
594
 
 
595
 
        self.lock_read()
596
 
        try:
597
 
            try:
598
 
                return self.revision_store[revision_id]
599
 
            except IndexError:
600
 
                raise bzrlib.errors.NoSuchRevision(self, revision_id)
601
 
        finally:
602
 
            self.unlock()
603
 
 
604
 
 
605
585
    def get_revision(self, revision_id):
606
586
        """Return the Revision object for a named revision"""
607
 
        xml_file = self.get_revision_xml(revision_id)
 
587
        from bzrlib.revision import Revision
 
588
        from bzrlib.xml import unpack_xml
608
589
 
 
590
        self.lock_read()
609
591
        try:
610
 
            r = unpack_xml(Revision, xml_file)
611
 
        except SyntaxError, e:
612
 
            raise bzrlib.errors.BzrError('failed to unpack revision_xml',
613
 
                                         [revision_id,
614
 
                                          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()
615
597
            
616
598
        assert r.revision_id == revision_id
617
599
        return r
618
 
 
619
 
 
620
 
    def get_revision_delta(self, revno):
621
 
        """Return the delta for one revision.
622
 
 
623
 
        The delta is relative to its mainline predecessor, or the
624
 
        empty tree for revision 1.
625
 
        """
626
 
        assert isinstance(revno, int)
627
 
        rh = self.revision_history()
628
 
        if not (1 <= revno <= len(rh)):
629
 
            raise InvalidRevisionNumber(revno)
630
 
 
631
 
        # revno is 1-based; list is 0-based
632
 
 
633
 
        new_tree = self.revision_tree(rh[revno-1])
634
 
        if revno == 1:
635
 
            old_tree = EmptyTree()
636
 
        else:
637
 
            old_tree = self.revision_tree(rh[revno-2])
638
 
 
639
 
        return compare_trees(old_tree, new_tree)
640
 
 
641
600
        
642
601
 
643
602
    def get_revision_sha1(self, revision_id):
648
607
        # the revision, (add signatures/remove signatures) and still
649
608
        # have all hash pointers stay consistent.
650
609
        # But for now, just hash the contents.
651
 
        return bzrlib.osutils.sha_file(self.get_revision_xml(revision_id))
 
610
        return sha_file(self.revision_store[revision_id])
652
611
 
653
612
 
654
613
    def get_inventory(self, inventory_id):
738
697
                return r+1, my_history[r]
739
698
        return None, None
740
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
 
741
721
 
742
722
    def revno(self):
743
723
        """Return current revision number for this branch.
826
806
        True
827
807
        """
828
808
        from bzrlib.progress import ProgressBar
 
809
        try:
 
810
            set
 
811
        except NameError:
 
812
            from sets import Set as set
829
813
 
830
814
        pb = ProgressBar()
831
815
 
1038
1022
 
1039
1023
        `revision_id` may be None for the null revision, in which case
1040
1024
        an `EmptyTree` is returned."""
 
1025
        from bzrlib.tree import EmptyTree, RevisionTree
1041
1026
        # TODO: refactor this to use an existing revision object
1042
1027
        # so we don't need to read it in twice.
1043
1028
        if revision_id == None:
1044
 
            return EmptyTree()
 
1029
            return EmptyTree(self.get_root_id())
1045
1030
        else:
1046
1031
            inv = self.get_revision_inventory(revision_id)
1047
1032
            return RevisionTree(self.text_store, inv)
1058
1043
 
1059
1044
        If there are no revisions yet, return an `EmptyTree`.
1060
1045
        """
 
1046
        from bzrlib.tree import EmptyTree, RevisionTree
1061
1047
        r = self.last_patch()
1062
1048
        if r == None:
1063
 
            return EmptyTree()
 
1049
            return EmptyTree(self.get_root_id())
1064
1050
        else:
1065
1051
            return RevisionTree(self.text_store, self.get_revision_inventory(r))
1066
1052