|
1
|
|
|
from subprocess import Popen, PIPE |
|
2
|
|
|
|
|
3
|
|
|
from coalib.bears.LocalBear import LocalBear |
|
4
|
|
|
from coalib.results.Diff import Diff |
|
5
|
|
|
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY |
|
6
|
|
|
from coalib.results.Result import Result |
|
7
|
|
|
|
|
8
|
|
|
|
|
9
|
|
|
class CorrectionBasedBear(LocalBear): |
|
10
|
|
|
SEVERITY = RESULT_SEVERITY.NORMAL |
|
11
|
|
|
GET_REPLACEMENT = (lambda self, file, cli_options: |
|
12
|
|
|
self.__run_process(file, cli_options)) |
|
13
|
|
|
|
|
14
|
|
|
def __run_process(self, file, cli_options): |
|
15
|
|
|
process = Popen(self.BINARY + ' ' + cli_options, |
|
16
|
|
|
shell=True, |
|
17
|
|
|
stdin=PIPE, |
|
18
|
|
|
stdout=PIPE, |
|
19
|
|
|
stderr=PIPE, |
|
20
|
|
|
universal_newlines=True) |
|
21
|
|
|
process.stdin.writelines(file) |
|
22
|
|
|
process.stdin.close() |
|
23
|
|
|
process.wait() |
|
24
|
|
|
|
|
25
|
|
|
corrected = process.stdout.readlines() |
|
26
|
|
|
errors = process.stderr.readlines() |
|
27
|
|
|
|
|
28
|
|
|
process.stdout.close() |
|
29
|
|
|
process.stderr.close() |
|
30
|
|
|
|
|
31
|
|
|
return corrected, errors |
|
32
|
|
|
|
|
33
|
|
|
@staticmethod |
|
34
|
|
|
def __yield_diffs(file, new_file): |
|
35
|
|
|
if new_file != file: |
|
36
|
|
|
wholediff = Diff.from_string_arrays(file, new_file) |
|
37
|
|
|
|
|
38
|
|
|
for diff in wholediff.split_diff(): |
|
39
|
|
|
yield diff |
|
40
|
|
|
|
|
41
|
|
|
def __print_errors(self, errors): |
|
42
|
|
|
for line in filter(lambda error: bool(error.strip()), errors): |
|
43
|
|
|
self.warn(line) |
|
44
|
|
|
|
|
45
|
|
|
def retrieve_results(self, filename, file, **kwargs): |
|
46
|
|
|
""" |
|
47
|
|
|
Yields results using the self.GET_REPLACEMENT function. |
|
48
|
|
|
|
|
49
|
|
|
:param filename: The filename, just pass it over as you got it! |
|
50
|
|
|
:param file: The file, just pass it over as you got it! |
|
51
|
|
|
:param kwargs: Any keyword arguments that will be passed to the |
|
52
|
|
|
GET_REPLACEMENT function. Please provide cli_options |
|
53
|
|
|
if you don't override the default. |
|
54
|
|
|
""" |
|
55
|
|
|
new_file, errors = self.GET_REPLACEMENT(file=file, **kwargs) |
|
56
|
|
|
self.__print_errors(errors) |
|
57
|
|
|
|
|
58
|
|
|
for diff in self.__yield_diffs(file, new_file): |
|
59
|
|
|
yield Result( |
|
60
|
|
|
self, |
|
61
|
|
|
self.RESULT_MESSAGE, |
|
62
|
|
|
affected_code=(diff.range(filename),), |
|
63
|
|
|
diffs={filename: diff}, |
|
64
|
|
|
severity=self.SEVERITY) |
|
65
|
|
|
|
|
66
|
|
|
@classmethod |
|
67
|
|
|
def check_prerequisites(cls): |
|
68
|
|
|
try: |
|
69
|
|
|
bin_args = getattr(cls, "BINARY_CHECK_ARGUMENTS", "--version") |
|
70
|
|
|
Popen([cls.BINARY, bin_args], stdout=PIPE, stderr=PIPE) |
|
71
|
|
|
return True |
|
72
|
|
|
except OSError: |
|
73
|
|
|
return repr(cls.BINARY) + " is not installed." |
|
74
|
|
|
except AttributeError: |
|
75
|
|
|
# Happens when `BINARY` does not exist in `cls`. |
|
76
|
|
|
return True |
|
77
|
|
|
|