Module: Amp::Diffs::MercurialPatch

Defined in:
lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb,
ext/amp/mercurial_patch/mpatch.c

Overview

This handles applying patches in mercurial. yay!!!!

Class Method Summary collapse

Class Method Details

.apply_patches(text, bins) ⇒ Object

This attempts to apply a series of patches in time proportional to the total size of the patches, rather than patches * len(text). This means rather than shuffling strings around, we shuffle around pointers to fragments with fragment lists.

When the fragment lists get too long, we collapse them. To do this efficiently, we do all our operations inside a buffer created by mmap and simply use memmove. This avoids creating a bunch of large temporary string buffers.

UPDATE 2AM BEFORE I GO BACK TO SCHOOL I FUCKING HATE PYTHON



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb', line 22

def self.apply_patches(source, patches)
  return source if patches.empty?
  patch_lens = patches.map {|patch| patch.size}
  pl = patch_lens.sum
  bl = source.size + pl
  tl = bl + bl + pl
  b1, b2 = 0, bl
  
  return a if tl == 0 #empty patches. lame.
  
  output = StringIO.new "",(ruby_19? ? "r+:ASCII-8BIT" : "r+")
  output.write source
  
  frags = [[source.size, b1]]
  
  pos = b2 + bl
  output.seek pos
  patches.each {|patch| output.write(patch)}
  patch_lens.each do |plen|
    if frags.size > 128
      b2, b1 = b1, b2
      frags = [self.collect(output,b1,frags)]
    end
    newarr = []
    endpt = pos + plen
    last = 0
    while pos < endpt
      output.seek pos
      p1, p2, l = output.read(12).unpack("NNN")
      self.pull(newarr, frags, p1 - last)
      self.pull([], frags, p2 - p1)
      newarr << [l, pos + 12]
      pos += l + 12
      last = p2
    end
    frags = newarr + frags
  end
  
  t = self.collect output, b2, frags
  output.seek t[1]
  output.read t[0]
end

.collect(io, buf, list) ⇒ Object

Takes the fragments we’ve accumulated and applies them all to the IO.



112
113
114
115
116
117
118
119
# File 'lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb', line 112

def self.collect(io, buf, list)
  start = buf
  list.each do |l, p|
    self.copy_block(io, buf, p, l)
    buf += l
  end
  [buf - start, start]
end

.copy_block(io, destination, source, count) ⇒ Object



88
89
90
91
92
93
# File 'lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb', line 88

def self.copy_block(io, destination, source, count)
  io.seek(source)
  buf = io.read(count)
  io.seek(destination)
  io.write(buf)
end

.patched_size(orig_r, bin_r) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'ext/amp/mercurial_patch/mpatch.c', line 357

def self.patched_size(orig, delta)
  outlen, last, bin = 0, 0, 0
  binend = delta.size
  data = 12 # size of the delta instruction values (3 longs)
  while data <= binend
    decode = delta[bin..(bin+11)]
    start, endpt, length = decode.unpack("NNN")
    break if start > endpt
    
    bin = data + length
    data = bin + 12
    outlen += start - last
    last = endpt
    outlen += length
  end
  
  raise "patch cannot be decoded" if bin != binend
  
  outlen += orig - last
  outlen
end

.pull(dst, src, l) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/amp/encoding/pure_ruby/ruby_mercurial_patch.rb', line 97

def self.pull(dst, src, l)
  until l == 0
    f = src.shift
    if f[0] > l
      src.unshift [f[0] - l, f[1] + l]
      dst << [l, f[1]]
      return
    end
    dst << f
    l -= f[0]
  end
end