-
Notifications
You must be signed in to change notification settings - Fork 0
/
fix_twirl_scripts.py
147 lines (118 loc) · 4.03 KB
/
fix_twirl_scripts.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import re
import glob
import os
import sys
import difflib
import argparse
import textwrap
def isBlank(str):
return not (str and str.strip())
def fix(lines, filepath):
imports = []
injection = ''
param = ''
rest = []
out = []
for line in lines:
# imports
pattern = re.compile(r'(@+import\s+([^\n@]*))')
matches = pattern.findall(line)
for match in matches:
imports.append('@import ' + match[1] + '\n')
line = line.replace(match[0], '')
if isBlank(line):
continue
# injector
pattern = re.compile(r'(@+this\(([^\n@]*)\))')
match = pattern.match(line)
if match:
injection = '@this(' + match.group(2) + ')\n'
line = line.replace(match.group(1), '')
if isBlank(line):
continue
# view parameters
pattern = re.compile(r'^(@+(\([^\n@]*\)))')
match = pattern.match(line)
if match:
param = '@' + match.group(2) + '\n'
line = line.replace(match.group(1), '')
if isBlank(line):
continue
rest.append(line)
if imports:
for imp in imports:
out.append(imp)
# add a blank line after imports
out.append('\n')
if injection:
out.append(injection)
if not param:
raise Exception('this twirl view "' + filepath + '" has no view parameters?')
out.append(param)
# add a blank line after view parameters
out.append('\n')
# all blank lines at the beginning are skipped,
# until a non-blank line is encountered
skipping_mode = True
for line in rest:
skipping_mode &= isBlank(line)
if not skipping_mode:
out.append(line)
return out
def diff(orig, new, filepath):
# prevent bug from difflib when the last line doesn't end with a newline
# character: https://github.com/pixee/codemodder-python/pull/116
diff_lines = list(difflib.unified_diff(orig, new, tofile=filepath))
if diff_lines:
diff_lines = [
line if line.endswith("\n") else line + "\n" for line in diff_lines[:-1]
] + [diff_lines[-1]]
return "".join(diff_lines)
def run(filepath, dry):
original = ''
fixed = ''
with open(filepath, 'r') as file:
original = file.readlines()
fixed = fix(original, filepath)
if not dry:
with open(filepath, 'w') as file:
for line in fixed:
file.write(line)
if original != fixed:
delta = diff(original, fixed, filepath)
sys.stdout.writelines(delta)
# add three linebreaks after, so that multiple printed diffs can
# be better differentiated. note, this can be split by,
# since empty lines in the diff itself are printed with a whitespace
# character, not just a line break
sys.stdout.write('\n\n\n')
def main(filepath, dry):
if os.path.isfile(filepath):
run(filepath, dry)
elif os.path.exists(filepath):
for path in glob.glob(filepath + '/**/*.scala.html', recursive=True):
run(path, dry)
else:
for path in glob.glob('./**/*.scala.html', recursive=True):
run(path, dry)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=textwrap.dedent('''\
Find and fix twirl templates that were messed up by
IntelliJ refactoring and code format. Run with '--dry'
flag first to see changes.
Prints diffs of all changes made to stdout.
'''))
parser.add_argument(
'file',
nargs='?',
default=os.getcwd(),
help='file or directory, defaults to current working dir')
parser.add_argument(
'--dry',
action="store_true",
default=False,
help="do not write changes, only output diff")
args = parser.parse_args()
main(args.file, args.dry)