~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

[merge] 0.7-bugfix: Fix fileid_involved to unescape xml characters, fix StubServer to handle paramiko > 1.5.2

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
 
487
488
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
488
489
        raise NotImplementedError('store_revision_signature is abstract')
489
490
 
 
491
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
492
        """ This function returns the file_id(s) involved in the
 
493
            changes between the from_revid revision and the to_revid
 
494
            revision
 
495
        """
 
496
        raise NotImplementedError('fileid_involved_between_revs is abstract')
 
497
 
 
498
    def fileid_involved(self, last_revid=None):
 
499
        """ This function returns the file_id(s) involved in the
 
500
            changes up to the revision last_revid
 
501
            If no parametr is passed, then all file_id[s] present in the
 
502
            repository are returned
 
503
        """
 
504
        raise NotImplementedError('fileid_involved is abstract')
 
505
 
 
506
    def fileid_involved_by_set(self, changes):
 
507
        """ This function returns the file_id(s) involved in the
 
508
            changes present in the set 'changes'
 
509
        """
 
510
        raise NotImplementedError('fileid_involved_by_set is abstract')
 
511
 
490
512
class BzrBranch(Branch):
491
513
    """A branch stored in the actual filesystem.
492
514
 
1114
1136
        self.revision_store.add(StringIO(gpg_strategy.sign(plaintext)), 
1115
1137
                                revision_id, "sig")
1116
1138
 
 
1139
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
1140
        """Find file_id(s) which are involved in the changes between revisions.
 
1141
 
 
1142
        This determines the set of revisions which are involved, and then
 
1143
        finds all file ids affected by those revisions.
 
1144
        """
 
1145
        # TODO: jam 20060119 This code assumes that w.inclusions will
 
1146
        #       always be correct. But because of the presence of ghosts
 
1147
        #       it is possible to be wrong.
 
1148
        #       One specific example from Robert Collins:
 
1149
        #       Two branches, with revisions ABC, and AD
 
1150
        #       C is a ghost merge of D.
 
1151
        #       Inclusions doesn't recognize D as an ancestor.
 
1152
        #       If D is ever merged in the future, the weave
 
1153
        #       won't be fixed, because AD never saw revision C
 
1154
        #       to cause a conflict which would force a reweave.
 
1155
        w = self._get_inventory_weave( )
 
1156
        from_set = set(w.inclusions([w.lookup(from_revid)]))
 
1157
        to_set = set(w.inclusions([w.lookup(to_revid)]))
 
1158
        included = to_set.difference(from_set)
 
1159
        changed = map(w.idx_to_name,included)
 
1160
        return self._fileid_involved_by_set(changed)
 
1161
 
 
1162
    def fileid_involved(self, last_revid=None):
 
1163
        """Find all file_ids modified in the ancestry of last_revid.
 
1164
 
 
1165
        :param last_revid: If None, last_revision() will be used.
 
1166
        """
 
1167
        w = self._get_inventory_weave( )
 
1168
        if not last_revid:
 
1169
            changed = set(w._names)
 
1170
        else:
 
1171
            included = w.inclusions([w.lookup(last_revid)])
 
1172
            changed = map(w.idx_to_name, included)
 
1173
        return self._fileid_involved_by_set(changed)
 
1174
 
 
1175
    def fileid_involved_by_set(self, changes):
 
1176
        """Find all file_ids modified by the set of revisions passed in.
 
1177
 
 
1178
        :param changes: A set() of revision ids
 
1179
        """
 
1180
        # TODO: jam 20060119 This line does *nothing*, remove it.
 
1181
        #       or better yet, change _fileid_involved_by_set so
 
1182
        #       that it takes the inventory weave, rather than
 
1183
        #       pulling it out by itself.
 
1184
        w = self._get_inventory_weave( )
 
1185
        return self._fileid_involved_by_set(changes)
 
1186
 
 
1187
    def _fileid_involved_by_set(self, changes):
 
1188
        """Find the set of file-ids affected by the set of revisions.
 
1189
 
 
1190
        :param changes: A set() of revision ids.
 
1191
        :return: A set() of file ids.
 
1192
        
 
1193
        This peaks at the Weave, interpreting each line, looking to
 
1194
        see if it mentions one of the revisions. And if so, includes
 
1195
        the file id mentioned.
 
1196
        This expects both the Weave format, and the serialization
 
1197
        to have a single line per file/directory, and to have
 
1198
        fileid="" and revision="" on that line.
 
1199
        """
 
1200
        assert self._branch_format in (5,6), \
 
1201
            "fileid_involved only supported for branches which store inventory as xml"
 
1202
 
 
1203
        w = self._get_inventory_weave( )
 
1204
        file_ids = set( )
 
1205
        for line in w._weave:
 
1206
 
 
1207
            # it is ugly, but it is due to the weave structure
 
1208
            if not isinstance(line,basestring): continue
 
1209
 
 
1210
            start = line.find('file_id="')+9
 
1211
            if start < 9: continue
 
1212
            end = line.find('"',start)
 
1213
            assert end>= 0
 
1214
            file_id = xml.sax.saxutils.unescape(line[start:end])
 
1215
 
 
1216
            # check if file_id is already present
 
1217
            if file_id in file_ids: continue
 
1218
 
 
1219
            start = line.find('revision="')+10
 
1220
            if start < 10: continue
 
1221
            end = line.find('"',start)
 
1222
            assert end>= 0
 
1223
            revision_id = xml.sax.saxutils.unescape(line[start:end])
 
1224
 
 
1225
            if revision_id in changes:
 
1226
                file_ids.add(file_id)
 
1227
 
 
1228
        return file_ids
 
1229
 
1117
1230
 
1118
1231
class ScratchBranch(BzrBranch):
1119
1232
    """Special test class: a branch that cleans up after itself.