~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revfile.py

  • Committer: mbp at sourcefrog
  • Date: 2005-04-09 04:38:18 UTC
  • Revision ID: mbp@sourcefrog.net-20050409043818-6000f4ab6d40a31a21b99dd7
Revfile:- store and retrieve deltas!mdiff:- work on bytes not lines

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
I_OFFSET = 3
89
89
I_LEN = 4
90
90
 
 
91
 
91
92
class RevfileError(Exception):
92
93
    pass
93
94
 
150
151
        return text    
151
152
 
152
153
 
153
 
    def _add_full_text(self, t):
154
 
        """Add a full text to the file.
155
 
 
156
 
        This is not compressed against any reference version.
157
 
 
158
 
        Returns the index for that text."""
 
154
    def _check_index(self, idx):
 
155
        if idx < 0 or idx > len(self):
 
156
            raise RevfileError("invalid index %r" % idx)
 
157
 
 
158
 
 
159
    def find_sha(self, s):
 
160
        assert isinstance(s, str)
 
161
        assert len(s) == 20
 
162
        
 
163
        for idx, idxrec in enumerate(self):
 
164
            if idxrec[I_SHA] == s:
 
165
                return idx
 
166
        else:
 
167
            return _NO_RECORD        
 
168
 
 
169
 
 
170
    def _add_common(self, text_sha, data, flags, base):
 
171
        """Add pre-processed data, can be either full text or delta."""
159
172
        idx = len(self)
160
173
        self.datafile.seek(0, 2)        # to end
161
174
        self.idxfile.seek(0, 2)
162
175
        assert self.idxfile.tell() == _RECORDSIZE * (idx + 1)
163
176
        data_offset = self.datafile.tell()
164
177
 
165
 
        assert isinstance(t, str) # not unicode or anything wierd
 
178
        assert isinstance(data, str) # not unicode or anything wierd
166
179
 
167
 
        self.datafile.write(t)
 
180
        self.datafile.write(data)
168
181
        self.datafile.flush()
169
182
 
170
 
        entry = sha.new(t).digest()
171
 
        entry += struct.pack(">IIII12x", 0xFFFFFFFFL, 0, data_offset, len(t))
 
183
        assert isinstance(text_sha, str)
 
184
        entry = text_sha
 
185
        entry += struct.pack(">IIII12x", base, flags, data_offset, len(data))
172
186
        assert len(entry) == _RECORDSIZE
173
187
 
174
188
        self.idxfile.write(entry)
175
189
        self.idxfile.flush()
176
190
 
177
191
        return idx
178
 
 
179
 
 
180
 
    def _check_index(self, idx):
181
 
        if idx < 0 or idx > len(self):
182
 
            raise RevfileError("invalid index %r" % idx)
183
 
 
184
 
 
185
 
    def find_sha(self, s):
186
 
        assert isinstance(s, str)
187
 
        assert len(s) == 20
188
192
        
189
 
        for idx, idxrec in enumerate(self):
190
 
            if idxrec[I_SHA] == s:
191
 
                return idx
192
 
        else:
193
 
            return _NO_RECORD        
194
 
 
195
 
 
196
 
    def _add_diff(self, text, base):
 
193
 
 
194
 
 
195
    def _add_full_text(self, text):
 
196
        """Add a full text to the file.
 
197
 
 
198
        This is not compressed against any reference version.
 
199
 
 
200
        Returns the index for that text."""
 
201
        return self._add_common(sha.new(text).digest(), text, 0, _NO_RECORD)
 
202
 
 
203
 
 
204
    def _add_delta(self, text, base):
197
205
        """Add a text stored relative to a previous text."""
198
206
        self._check_index(base)
199
207
        text_sha = sha.new(text).digest()
 
208
        base_text = self.get(base)
 
209
        data = mdiff.bdiff(base_text, text)
 
210
        return self._add_common(text_sha, data, 0, base)
 
211
 
 
212
 
 
213
    def add(self, text, base=None):
 
214
        # TODO: check it's not already present?
 
215
        assert 0
200
216
 
201
217
        
202
218
    def addrevision(self, text, changeset):
221
237
        open(self.indexfile(), "a").write(entry)
222
238
        open(self.datafile(), "a").write(data)
223
239
 
224
 
    def _get_full_text(self, idx):
 
240
 
 
241
    def get(self, idx):
225
242
        idxrec = self[idx]
226
 
        assert idxrec[I_FLAGS] == 0
227
 
        assert idxrec[I_BASE] == _NO_RECORD
228
 
 
 
243
        base = idxrec[I_BASE]
 
244
        if base == _NO_RECORD:
 
245
            text = self._get_full_text(idx, idxrec)
 
246
        else:
 
247
            text = self._get_patched(idx, idxrec)
 
248
 
 
249
        if sha.new(text).digest() != idxrec[I_SHA]:
 
250
            raise RevfileError("corrupt SHA-1 digest on record %d"
 
251
                               % idx)
 
252
 
 
253
        return text
 
254
 
 
255
 
 
256
 
 
257
    def _get_raw(self, idx, idxrec):
229
258
        l = idxrec[I_LEN]
230
259
        if l == 0:
231
260
            return ''
232
261
 
233
262
        self.datafile.seek(idxrec[I_OFFSET])
234
263
 
235
 
        text = self.datafile.read(l)
236
 
        if len(text) != l:
 
264
        data = self.datafile.read(l)
 
265
        if len(data) != l:
237
266
            raise RevfileError("short read %d of %d "
238
267
                               "getting text for record %d in %r"
239
 
                               % (len(text), l, idx, self.basename))
 
268
                               % (len(data), l, idx, self.basename))
240
269
 
241
 
        if sha.new(text).digest() != idxrec[I_SHA]:
242
 
            raise RevfileError("corrupt SHA-1 digest on record %d"
243
 
                               % idx)
 
270
        return data
244
271
        
245
 
        return text
 
272
 
 
273
    def _get_full_text(self, idx, idxrec):
 
274
        assert idxrec[I_FLAGS] == 0
 
275
        assert idxrec[I_BASE] == _NO_RECORD
 
276
 
 
277
        text = self._get_raw(idx, idxrec)
 
278
 
 
279
        return text
 
280
 
 
281
 
 
282
    def _get_patched(self, idx, idxrec):
 
283
        assert idxrec[I_FLAGS] == 0
 
284
        base = idxrec[I_BASE]
 
285
        assert base >= 0
 
286
        assert base < idx    # no loops!
 
287
 
 
288
        base_text = self.get(base)
 
289
        patch = self._get_raw(idx, idxrec)
 
290
 
 
291
        text = mdiff.bpatch(base_text, patch)
 
292
 
 
293
        return text
 
294
 
246
295
 
247
296
 
248
297
    def __len__(self):
263
312
 
264
313
 
265
314
    def _seek_index(self, idx):
 
315
        if idx < 0:
 
316
            raise RevfileError("invalid index %r" % idx)
266
317
        self.idxfile.seek((idx + 1) * _RECORDSIZE)
267
318
        
268
319
 
302
353
    except IndexError:
303
354
        sys.stderr.write("usage: revfile dump\n"
304
355
                         "       revfile add\n"
 
356
                         "       revfile add-delta BASE\n"
305
357
                         "       revfile get IDX\n"
306
358
                         "       revfile find-sha HEX\n")
307
359
        return 1
310
362
    if cmd == 'add':
311
363
        new_idx = r._add_full_text(sys.stdin.read())
312
364
        print 'added idx %d' % new_idx
 
365
    elif cmd == 'add-delta':
 
366
        new_idx = r._add_delta(sys.stdin.read(), int(argv[2]))
 
367
        print 'added idx %d' % new_idx
313
368
    elif cmd == 'dump':
314
369
        r.dump()
315
370
    elif cmd == 'get':
323
378
            sys.stderr.write("invalid index %r\n" % idx)
324
379
            return 1
325
380
 
326
 
        sys.stdout.write(r._get_full_text(idx))
 
381
        sys.stdout.write(r.get(idx))
327
382
    elif cmd == 'find-sha':
328
383
        try:
329
384
            s = unhexlify(argv[2])