|
|
|
|
| import os.path
|
| import subprocess
|
| import tempfile
|
|
|
| from .exceptions import HunkApplyException, SubprocessException
|
| from .snippets import remove, which
|
|
|
|
|
| def _apply_diff_with_subprocess(diff, lines, reverse=False):
|
|
|
| patchexec = which('patch')
|
| if not patchexec:
|
| raise SubprocessException('cannot find patch program', code=-1)
|
|
|
| tempdir = tempfile.gettempdir()
|
|
|
| filepath = os.path.join(tempdir, 'wtp-' + str(hash(diff.header)))
|
| oldfilepath = filepath + '.old'
|
| newfilepath = filepath + '.new'
|
| rejfilepath = filepath + '.rej'
|
| patchfilepath = filepath + '.patch'
|
| with open(oldfilepath, 'w') as f:
|
| f.write('\n'.join(lines) + '\n')
|
|
|
| with open(patchfilepath, 'w') as f:
|
| f.write(diff.text)
|
|
|
| args = [
|
| patchexec,
|
| '--reverse' if reverse else '--forward',
|
| '--quiet',
|
| '--no-backup-if-mismatch',
|
| '-o',
|
| newfilepath,
|
| '-i',
|
| patchfilepath,
|
| '-r',
|
| rejfilepath,
|
| oldfilepath,
|
| ]
|
| ret = subprocess.call(args)
|
|
|
| with open(newfilepath) as f:
|
| lines = f.read().splitlines()
|
|
|
| try:
|
| with open(rejfilepath) as f:
|
| rejlines = f.read().splitlines()
|
| except IOError:
|
| rejlines = None
|
|
|
| remove(oldfilepath)
|
| remove(newfilepath)
|
| remove(rejfilepath)
|
| remove(patchfilepath)
|
|
|
|
|
| if ret != 0:
|
| raise SubprocessException('patch program failed', code=ret)
|
|
|
| return lines, rejlines
|
|
|
|
|
| def _reverse(changes):
|
| def _reverse_change(c):
|
| return c._replace(old=c.new, new=c.old)
|
|
|
| return [_reverse_change(c) for c in changes]
|
|
|
|
|
| def apply_diff(diff, text, reverse=False, use_patch=False):
|
| try:
|
| lines = text.splitlines()
|
| except AttributeError:
|
| lines = list(text)
|
|
|
| if use_patch:
|
| return _apply_diff_with_subprocess(diff, lines, reverse)
|
|
|
| n_lines = len(lines)
|
|
|
| changes = _reverse(diff.changes) if reverse else diff.changes
|
|
|
| for old, new, line, hunk in changes:
|
|
|
| if old is not None and line is not None:
|
| if old > n_lines:
|
| raise HunkApplyException(
|
| 'context line {n}, "{line}" does not exist in source'.format(
|
| n=old, line=line
|
| ),
|
| hunk=hunk,
|
| )
|
| if lines[old - 1] != line:
|
| raise HunkApplyException(
|
| 'context line {n}, "{line}" does not match "{sl}"'.format(
|
| n=old, line=line, sl=lines[old - 1]
|
| ),
|
| hunk=hunk,
|
| )
|
|
|
|
|
| r = 0
|
| i = 0
|
|
|
| for old, new, line, hunk in changes:
|
| if old is not None and new is None:
|
| del lines[old - 1 - r + i]
|
| r += 1
|
| elif old is None and new is not None:
|
| lines.insert(new - 1, line)
|
| i += 1
|
| elif old is not None and new is not None:
|
|
|
|
|
| pass
|
|
|
| return lines
|
|
|