Skip to content

Commit 6b342d5

Browse files
author
Thomas Grainger
committed
Raise exceptions with hunk context info Fixes #8, Fixes #9
1 parent b343266 commit 6b342d5

File tree

4 files changed

+90
-50
lines changed

4 files changed

+90
-50
lines changed

tests/test_apply.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
import whatthepatch as wtp
4+
from whatthepatch import exceptions
45

56

67
import unittest
@@ -60,7 +61,7 @@ def test_diff_unified_patchutil(self):
6061
self.assertEqual(new_text, (self.tzu, None))
6162

6263
self.assertRaises(
63-
AssertionError,
64+
exceptions.ApplyException,
6465
wtp.apply.apply_diff,
6566
diff,
6667
[''] + self.lao,

whatthepatch/apply.py

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import subprocess
44

5-
from . import patch
5+
from . import patch, exceptions
66
from .snippets import which, remove
77

88

@@ -25,62 +25,82 @@ def apply_patch(diffs):
2525
f.write(new_text)
2626

2727

28+
def _apply_diff_with_subprocess(diff, lines):
29+
# call out to patch program
30+
patchexec = which('patch')
31+
if not patchexec:
32+
raise exceptions.ApplyException('patch program does not exist')
33+
34+
filepath = '/tmp/wtp-' + str(hash(diff.header))
35+
oldfilepath = filepath + '.old'
36+
newfilepath = filepath + '.new'
37+
rejfilepath = filepath + '.rej'
38+
patchfilepath = filepath + '.patch'
39+
with open(oldfilepath, 'w') as f:
40+
f.write('\n'.join(lines) + '\n')
41+
42+
with open(patchfilepath, 'w') as f:
43+
f.write(diff.text)
44+
45+
args = [patchexec,
46+
'--quiet',
47+
'-o', newfilepath,
48+
'-i', patchfilepath,
49+
'-r', rejfilepath,
50+
oldfilepath
51+
]
52+
ret = subprocess.call(args)
53+
54+
with open(newfilepath) as f:
55+
lines = f.read().splitlines()
56+
57+
try:
58+
with open(rejfilepath) as f:
59+
rejlines = f.read().splitlines()
60+
except IOError:
61+
rejlines = None
62+
63+
remove(oldfilepath)
64+
remove(newfilepath)
65+
remove(rejfilepath)
66+
remove(patchfilepath)
67+
68+
# do this last to ensure files get cleaned up
69+
if ret != 0:
70+
raise exceptions.ApplyException('patch program failed')
71+
72+
return lines, rejlines
73+
74+
2875
def apply_diff(diff, text, use_patch=False):
2976
try:
3077
lines = text.splitlines()
3178
except AttributeError:
3279
lines = list(text)
3380

3481
if use_patch:
35-
# call out to patch program
36-
patchexec = which('patch')
37-
assert patchexec # patch program does not exist
38-
39-
filepath = '/tmp/wtp-' + str(hash(diff.header))
40-
oldfilepath = filepath + '.old'
41-
newfilepath = filepath + '.new'
42-
rejfilepath = filepath + '.rej'
43-
patchfilepath = filepath + '.patch'
44-
with open(oldfilepath, 'w') as f:
45-
f.write('\n'.join(lines) + '\n')
46-
47-
with open(patchfilepath, 'w') as f:
48-
f.write(diff.text)
49-
50-
args = [patchexec,
51-
'--quiet',
52-
'-o', newfilepath,
53-
'-i', patchfilepath,
54-
'-r', rejfilepath,
55-
oldfilepath
56-
]
57-
ret = subprocess.call(args)
58-
59-
with open(newfilepath) as f:
60-
lines = f.read().splitlines()
61-
62-
try:
63-
with open(rejfilepath) as f:
64-
rejlines = f.read().splitlines()
65-
except IOError:
66-
rejlines = None
67-
68-
remove(oldfilepath)
69-
remove(newfilepath)
70-
remove(rejfilepath)
71-
remove(patchfilepath)
72-
73-
# do this last to ensure files get cleaned up
74-
assert ret == 0 # patch return code is success
75-
76-
return lines, rejlines
82+
return _apply_diff_with_subprocess(diff, lines)
7783

84+
n_lines = len(lines)
7885
# check that the source text matches the context of the diff
7986
for old, new, line in diff.changes:
8087
# might have to check for line is None here for ed scripts
8188
if old is not None and line is not None:
82-
assert len(lines) >= old
83-
assert lines[old-1] == line
89+
if old > n_lines:
90+
raise exceptions.ApplyException(
91+
'context line {n}, "{l}" does not exist in source'.format(
92+
n=old,
93+
l=line,
94+
)
95+
)
96+
if lines[old-1] != line:
97+
raise exceptions.ApplyException(
98+
'context line {n}, "{l}" does not match "{sl}"'.format(
99+
n=old,
100+
l=line,
101+
sl=lines[old-1]
102+
)
103+
)
84104

85105
# for calculating the old line
86106
r = 0

whatthepatch/exceptions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class WhatThePatchException(Exception):
2+
pass
3+
4+
5+
class ApplyException(WhatThePatchException):
6+
pass
7+
8+
9+
class ParseException(WhatThePatchException, ValueError):
10+
def init(self, msg, hunk=None):
11+
self.hunk = hunk
12+
if hunk is not None:
13+
super(ParseException, self).__init__('{msg}, in hunk #{n}'.format(
14+
msg=msg,
15+
n=hunk,
16+
))
17+
else:
18+
super(ParseException, self).__init__(msg)

whatthepatch/patch.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from collections import namedtuple
55

66
from .snippets import split_by_regex, findall_regex
7+
from . import exceptions
78

89
header = namedtuple(
910
'header',
@@ -621,15 +622,15 @@ def parse_context_diff(text):
621622
changes = list()
622623

623624
hunks = split_by_regex(lines, context_hunk_start)
624-
for hunk in hunks:
625+
for hunk_n, hunk in enumerate(hunks):
625626
if not len(hunk):
626627
continue
627628

628629
j = 0
629630
k = 0
630631
parts = split_by_regex(hunk, context_hunk_new)
631632
if len(parts) != 2:
632-
raise ValueError("Context diff invalid")
633+
raise exceptions.ParseException("Context diff invalid", hunk_n)
633634

634635
old_hunk = parts[0]
635636
new_hunk = parts[1]
@@ -678,7 +679,7 @@ def parse_context_diff(text):
678679
j += 1
679680
k += 1
680681
elif kind == '+' or kind == '!':
681-
raise ValueError(msg + kind)
682+
raise exceptions.ParseException(msg + kind, hunk_n)
682683

683684
continue
684685

@@ -704,7 +705,7 @@ def parse_context_diff(text):
704705
j += 1
705706
k += 1
706707
elif kind == '-' or kind == '!':
707-
raise ValueError(msg + kind)
708+
raise exceptions.ParseException(msg + kind, hunk_n)
708709
continue
709710

710711
# both

0 commit comments

Comments
 (0)