##// END OF EJS Templates
repair: determine what upgrade will do...
repair: determine what upgrade will do This commit introduces code for determining what actions/improvements an upgrade should perform. The "upgradefindimprovements" function introduces a mechanism to return a list of improvements that can be made to a repository. Each improvement is effectively an action that an upgrade will perform. Associated with each of these improvements is metadata that will be used to inform users what's wrong and what an upgrade will do. Each "improvement" is categorized as a "deficiency" or an "optimization." TBH, I'm not thrilled about the terminology and am receptive to constructive bikeshedding. The main difference between a "deficiency" and an "optimization" is a deficiency is always corrected (if it deviates from the current config) and an "optimization" is an optional action that goes above and beyond to improve the state of the repository (usually by requiring more CPU during upgrade). Our initial set of improvements identifies missing repository requirements, a single, easily correctable problem with changelog storage, and a set of "optimizations" related to delta recalculation. The main "upgraderepo" function has been expanded to handle improvements. It queries for the list of improvements and determines which of them will run based on the current repository state and user I went through numerous iterations of the output format before settling on a ReST-inspired definition list format. (I used bulleted lists in the first submission of this commit and could not get it to format just right.) Even with the various iterations, I'm still not super thrilled with the format. But, this is a debug* command, so that should mean we can refine the output without BC concerns.

File last commit:

r29695:f2846d54 default
r30776:3997edc4 default
Show More
mpatch.py
170 lines | 4.8 KiB | text/x-python | PythonLexer
Martin Geisler
pure Python implementation of mpatch.c
r7699 # mpatch.py - Python implementation of mpatch.c
#
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
pure Python implementation of mpatch.c
r7699
Gregory Szorc
mpatch: use absolute_import...
r27337 from __future__ import absolute_import
Martin Geisler
pure/mpatch: use StringIO instead of mmap (issue1493)...
r7775 import struct
Gregory Szorc
mpatch: use absolute_import...
r27337
Maciej Fijalkowski
mpatch: write a cffi version of mpatch.patches
r29695 from . import policy, pycompat
timeless
pycompat: switch to util.stringio for py3 compat
r28861 stringio = pycompat.stringio
Maciej Fijalkowski
mpatch: write a cffi version of mpatch.patches
r29695 modulepolicy = policy.policy
policynocffi = policy.policynocffi
Martin Geisler
pure Python implementation of mpatch.c
r7699
timeless
mpatch: unify mpatchError (issue5182)...
r28782 class mpatchError(Exception):
"""error raised when a delta cannot be decoded
"""
Martin Geisler
pure Python implementation of mpatch.c
r7699 # 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.
Augie Fackler
mpatch: move pull() method to top level...
r28587 def _pull(dst, src, l): # pull l bytes from src
while l:
f = src.pop()
if f[0] > l: # do we need to split?
src.append((f[0] - l, f[1] + l))
dst.append((l, f[1]))
return
dst.append(f)
l -= f[0]
Augie Fackler
mpatch: un-nest the move() method...
r28588 def _move(m, dest, src, count):
"""move count bytes from src to dest
The file pointer is left at the end of dest.
"""
m.seek(src)
buf = m.read(count)
m.seek(dest)
m.write(buf)
Augie Fackler
mpatch: move collect() to module level...
r28589 def _collect(m, buf, list):
start = buf
for l, p in reversed(list):
_move(m, buf, p, l)
buf += l
return (buf - start, start)
Martin Geisler
pure Python implementation of mpatch.c
r7699 def patches(a, bins):
Matt Mackall
many, many trivial check-code fixups
r10282 if not bins:
return a
Martin Geisler
pure Python implementation of mpatch.c
r7699
plens = [len(x) for x in bins]
pl = sum(plens)
bl = len(a) + pl
tl = bl + bl + pl # enough for the patches and two working texts
b1, b2 = 0, bl
Matt Mackall
many, many trivial check-code fixups
r10282 if not tl:
return a
Martin Geisler
pure Python implementation of mpatch.c
r7699
timeless
pycompat: switch to util.stringio for py3 compat
r28861 m = stringio()
Martin Geisler
pure Python implementation of mpatch.c
r7699
# load our original text
m.write(a)
frags = [(len(a), b1)]
# copy all the patches into our segment so we can memmove from them
pos = b2 + bl
m.seek(pos)
for p in bins: m.write(p)
for plen in plens:
# if our list gets too long, execute it
if len(frags) > 128:
b2, b1 = b1, b2
Augie Fackler
mpatch: move collect() to module level...
r28589 frags = [_collect(m, b1, frags)]
Martin Geisler
pure Python implementation of mpatch.c
r7699
new = []
end = pos + plen
last = 0
while pos < end:
Martin Geisler
pure/mpatch: use StringIO instead of mmap (issue1493)...
r7775 m.seek(pos)
timeless
mpatch: unify mpatchError (issue5182)...
r28782 try:
p1, p2, l = struct.unpack(">lll", m.read(12))
except struct.error:
raise mpatchError("patch cannot be decoded")
Augie Fackler
mpatch: move pull() method to top level...
r28587 _pull(new, frags, p1 - last) # what didn't change
_pull([], frags, p2 - p1) # what got deleted
Brodie Rao
cleanup: eradicate long lines
r16683 new.append((l, pos + 12)) # what got added
Martin Geisler
pure Python implementation of mpatch.c
r7699 pos += l + 12
last = p2
Brodie Rao
cleanup: eradicate long lines
r16683 frags.extend(reversed(new)) # what was left at the end
Martin Geisler
pure Python implementation of mpatch.c
r7699
Augie Fackler
mpatch: move collect() to module level...
r28589 t = _collect(m, b2, frags)
Martin Geisler
pure Python implementation of mpatch.c
r7699
Martin Geisler
pure/mpatch: use StringIO instead of mmap (issue1493)...
r7775 m.seek(t[1])
return m.read(t[0])
Martin Geisler
pure Python implementation of mpatch.c
r7699
def patchedsize(orig, delta):
outlen, last, bin = 0, 0, 0
binend = len(delta)
data = 12
while data <= binend:
decode = delta[bin:bin + 12]
start, end, length = struct.unpack(">lll", decode)
if start > end:
break
bin = data + length
data = bin + 12
outlen += start - last
last = end
outlen += length
if bin != binend:
timeless
mpatch: unify mpatchError (issue5182)...
r28782 raise mpatchError("patch cannot be decoded")
Martin Geisler
pure Python implementation of mpatch.c
r7699
outlen += orig - last
return outlen
Maciej Fijalkowski
mpatch: write a cffi version of mpatch.patches
r29695
if modulepolicy not in policynocffi:
try:
from _mpatch_cffi import ffi, lib
except ImportError:
if modulepolicy == 'cffi': # strict cffi import
raise
else:
@ffi.def_extern()
def cffi_get_next_item(arg, pos):
all, bins = ffi.from_handle(arg)
container = ffi.new("struct mpatch_flist*[1]")
to_pass = ffi.new("char[]", str(bins[pos]))
all.append(to_pass)
r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container)
if r < 0:
return ffi.NULL
return container[0]
def patches(text, bins):
lgt = len(bins)
all = []
if not lgt:
return text
arg = (all, bins)
patch = lib.mpatch_fold(ffi.new_handle(arg),
lib.cffi_get_next_item, 0, lgt)
if not patch:
raise mpatchError("cannot decode chunk")
outlen = lib.mpatch_calcsize(len(text), patch)
if outlen < 0:
lib.mpatch_lfree(patch)
raise mpatchError("inconsistency detected")
buf = ffi.new("char[]", outlen)
if lib.mpatch_apply(buf, text, len(text), patch) < 0:
lib.mpatch_lfree(patch)
raise mpatchError("error applying patches")
res = ffi.buffer(buf, outlen)[:]
lib.mpatch_lfree(patch)
return res