~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

Merge integration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import os
21
21
import errno
22
22
from warnings import warn
 
23
import xml.sax.saxutils
23
24
from cStringIO import StringIO
24
25
 
25
26
 
392
393
        mutter("copied")
393
394
        return br_to
394
395
 
 
396
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
397
        """ This function returns the file_id(s) involved in the
 
398
            changes between the from_revid revision and the to_revid
 
399
            revision
 
400
        """
 
401
        raise NotImplementedError('fileid_involved_between_revs is abstract')
 
402
 
 
403
    def fileid_involved(self, last_revid=None):
 
404
        """ This function returns the file_id(s) involved in the
 
405
            changes up to the revision last_revid
 
406
            If no parametr is passed, then all file_id[s] present in the
 
407
            repository are returned
 
408
        """
 
409
        raise NotImplementedError('fileid_involved is abstract')
 
410
 
 
411
    def fileid_involved_by_set(self, changes):
 
412
        """ This function returns the file_id(s) involved in the
 
413
            changes present in the set 'changes'
 
414
        """
 
415
        raise NotImplementedError('fileid_involved_by_set is abstract')
 
416
 
 
417
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
418
        """ This function returns the file_id(s) involved in the
 
419
            changes between the from_revid revision and the to_revid
 
420
            revision
 
421
        """
 
422
        raise NotImplementedError('fileid_involved_between_revs is abstract')
 
423
 
 
424
    def fileid_involved(self, last_revid=None):
 
425
        """ This function returns the file_id(s) involved in the
 
426
            changes up to the revision last_revid
 
427
            If no parametr is passed, then all file_id[s] present in the
 
428
            repository are returned
 
429
        """
 
430
        raise NotImplementedError('fileid_involved is abstract')
 
431
 
 
432
    def fileid_involved_by_set(self, changes):
 
433
        """ This function returns the file_id(s) involved in the
 
434
            changes present in the set 'changes'
 
435
        """
 
436
        raise NotImplementedError('fileid_involved_by_set is abstract')
 
437
 
 
438
 
395
439
class BzrBranch(Branch):
396
440
    """A branch stored in the actual filesystem.
397
441
 
540
584
            ('pending-merges', ''),
541
585
            ('inventory', empty_inv),
542
586
            ('inventory.weave', empty_weave),
543
 
            ('ancestry.weave', empty_weave)
544
587
        ]
545
588
        cfe = self.control_files._escape
546
589
        # FIXME: RBC 20060125 dont peek under the covers
830
873
 
831
874
        return Branch.clone(self, to_location, revision, basis_branch, to_branch_type)
832
875
 
 
876
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
877
        """Find file_id(s) which are involved in the changes between revisions.
 
878
 
 
879
        This determines the set of revisions which are involved, and then
 
880
        finds all file ids affected by those revisions.
 
881
        """
 
882
        # TODO: jam 20060119 This code assumes that w.inclusions will
 
883
        #       always be correct. But because of the presence of ghosts
 
884
        #       it is possible to be wrong.
 
885
        #       One specific example from Robert Collins:
 
886
        #       Two branches, with revisions ABC, and AD
 
887
        #       C is a ghost merge of D.
 
888
        #       Inclusions doesn't recognize D as an ancestor.
 
889
        #       If D is ever merged in the future, the weave
 
890
        #       won't be fixed, because AD never saw revision C
 
891
        #       to cause a conflict which would force a reweave.
 
892
        w = self.repository.get_inventory_weave()
 
893
        from_set = set(w.inclusions([w.lookup(from_revid)]))
 
894
        to_set = set(w.inclusions([w.lookup(to_revid)]))
 
895
        included = to_set.difference(from_set)
 
896
        changed = map(w.idx_to_name, included)
 
897
        return self._fileid_involved_by_set(changed)
 
898
 
 
899
    def fileid_involved(self, last_revid=None):
 
900
        """Find all file_ids modified in the ancestry of last_revid.
 
901
 
 
902
        :param last_revid: If None, last_revision() will be used.
 
903
        """
 
904
        w = self.repository.get_inventory_weave()
 
905
        if not last_revid:
 
906
            changed = set(w._names)
 
907
        else:
 
908
            included = w.inclusions([w.lookup(last_revid)])
 
909
            changed = map(w.idx_to_name, included)
 
910
        return self._fileid_involved_by_set(changed)
 
911
 
 
912
    def fileid_involved_by_set(self, changes):
 
913
        """Find all file_ids modified by the set of revisions passed in.
 
914
 
 
915
        :param changes: A set() of revision ids
 
916
        """
 
917
        # TODO: jam 20060119 This line does *nothing*, remove it.
 
918
        #       or better yet, change _fileid_involved_by_set so
 
919
        #       that it takes the inventory weave, rather than
 
920
        #       pulling it out by itself.
 
921
        w = self.repository.get_inventory_weave()
 
922
        return self._fileid_involved_by_set(changes)
 
923
 
 
924
    def _fileid_involved_by_set(self, changes):
 
925
        """Find the set of file-ids affected by the set of revisions.
 
926
 
 
927
        :param changes: A set() of revision ids.
 
928
        :return: A set() of file ids.
 
929
        
 
930
        This peaks at the Weave, interpreting each line, looking to
 
931
        see if it mentions one of the revisions. And if so, includes
 
932
        the file id mentioned.
 
933
        This expects both the Weave format, and the serialization
 
934
        to have a single line per file/directory, and to have
 
935
        fileid="" and revision="" on that line.
 
936
        """
 
937
        assert self._branch_format in (5, 6), \
 
938
            "fileid_involved only supported for branches which store inventory as xml"
 
939
 
 
940
        w = self.repository.get_inventory_weave()
 
941
        file_ids = set()
 
942
        for line in w._weave:
 
943
 
 
944
            # it is ugly, but it is due to the weave structure
 
945
            if not isinstance(line, basestring): continue
 
946
 
 
947
            start = line.find('file_id="')+9
 
948
            if start < 9: continue
 
949
            end = line.find('"', start)
 
950
            assert end>= 0
 
951
            file_id = xml.sax.saxutils.unescape(line[start:end])
 
952
 
 
953
            # check if file_id is already present
 
954
            if file_id in file_ids: continue
 
955
 
 
956
            start = line.find('revision="')+10
 
957
            if start < 10: continue
 
958
            end = line.find('"', start)
 
959
            assert end>= 0
 
960
            revision_id = xml.sax.saxutils.unescape(line[start:end])
 
961
 
 
962
            if revision_id in changes:
 
963
                file_ids.add(file_id)
 
964
 
 
965
        return file_ids
 
966
 
833
967
 
834
968
class ScratchBranch(BzrBranch):
835
969
    """Special test class: a branch that cleans up after itself.
901
1035
    filename = normpath(filename)
902
1036
    while filename != '':
903
1037
        head, tail = os.path.split(filename)
904
 
        ## mutter('check %r for control file' % ((head, tail), ))
 
1038
        ## mutter('check %r for control file' % ((head, tail),))
905
1039
        if tail == bzrlib.BZRDIR:
906
1040
            return True
907
1041
        if filename == head: