-
Notifications
You must be signed in to change notification settings - Fork 7
/
common.py
321 lines (258 loc) · 9.21 KB
/
common.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
import os, traceback, sys, json, shutil, copy
import subprocess32 as subprocess
from threading import Timer
from contextlib import contextmanager
WORKING_DIR = os.path.dirname(os.path.realpath(__file__))
OUTPUT_DIR = WORKING_DIR
LIBS_DIR = os.path.join(WORKING_DIR, "libs")
CORPUS_DIR = os.path.join(WORKING_DIR, "corpus")
CORPUS_INFO = None
TOOLS_DIR = os.path.join(WORKING_DIR, "tools")
SIMPROG_DIR = os.path.join(WORKING_DIR, "simprog")
CLUSTER_FILE = "clusters.json"
CLASS2FIELDS_FILE = "c2f.json"
WORDCLUSTERS_FILE = "word_based_field_clusters.json"
if os.environ.get('DLJCDIR'):
DLJC_BINARY = os.path.join(os.environ.get('DLJCDIR'), 'dljc')
else:
DLJC_BINARY = os.path.join(TOOLS_DIR, "do-like-javac", "dljc")
DLJC_OUTPUT_DIR = "dljc-out"
DYNTRACE_ADDONS_DIR = os.path.join(WORKING_DIR, "dyntrace")
LIMITED_PROJECT_LIST = ["dyn4j", "jreactphysics3d", "jbox2d", "react", "jmonkeyengine"]
def set_output_dir(newdir):
global OUTPUT_DIR
if os.path.isdir(newdir):
OUTPUT_DIR = newdir
def run_cmd(cmd, output=False, timeout=None):
stats = {'timed_out': False,
'output': ''}
timer = None
out = None
out_file = None
if isinstance(cmd, str):
friendly_cmd = cmd
cmd = cmd.split()
else:
friendly_cmd = ' '.join(cmd)
if hasattr(output, 'write'):
out = output
elif isinstance(output, str):
out_file = os.path.join(OUTPUT_DIR, output + '.log')
out = open(out_file, 'a')
def output(line):
if out:
out.write(line)
out.flush()
def kill_proc(proc, stats):
output('Timed out after {} seconds on {}'.format(timeout, friendly_cmd))
stats['timed_out'] = True
proc.kill()
output("Running {}\n\n".format(friendly_cmd))
try:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if timeout:
timer = Timer(timeout, kill_proc, [process, stats])
timer.start()
for line in iter(process.stdout.readline, b''):
stats['output'] = stats['output'] + line
output(line)
process.stdout.close()
process.wait()
stats['return_code'] = process.returncode
if timer:
timer.cancel()
except:
output('calling {} failed\n{}'.format(friendly_cmd,
traceback.format_exc()))
if out_file:
out.close()
return stats
@contextmanager
def cd(newdir):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)
def mkdir(newdir):
if not os.path.isdir(newdir):
os.makedirs(newdir)
def get_method_from_daikon_out(daikon_out):
arr1 = daikon_out.split('.')
arr2 = arr1[1].split(':::')
method = arr2[0]
return method
def get_jar(jar_name):
path = os.path.join(LIBS_DIR, jar_name)
if os.path.isfile(path):
return path
else:
return None
def get_corpus_set(setname):
corpus = get_corpus_info()
if setname == "all":
return list(corpus['projects'].keys())
else:
return corpus['sets'][setname]
def load_corpus_info():
with open(os.path.join(WORKING_DIR, 'corpus.json')) as f:
info = json.loads(f.read())
global_properties = info.get('global', {})
projects = info['projects']
for project_name in list(projects.keys()):
base = copy.deepcopy(global_properties)
base['name'] = project_name
base.update(projects[project_name])
projects[project_name] = base
return info
def get_corpus_info():
global CORPUS_INFO
if not CORPUS_INFO:
CORPUS_INFO = load_corpus_info()
return CORPUS_INFO
def get_project_dir(project_name):
project = project_info(project_name)
if 'build-dir' in project:
return os.path.join(CORPUS_DIR, project['name'], project['build-dir'])
else:
return os.path.join(CORPUS_DIR, project['name'])
def get_project_list():
return list(get_corpus_info()['projects'].keys())
def project_info(project_name):
return get_corpus_info()['projects'][project_name]
def get_simprog(py_file):
return os.path.join(SIMPROG_DIR, py_file)
def get_dljc_dir(project_name):
dtrace_path = os.path.join(get_project_dir(project_name), DLJC_OUTPUT_DIR)
if os.path.exists(dtrace_path):
return dtrace_path
else:
return None
def clean_corpus(proj_set="all"):
for project in get_corpus_set(proj_set):
clean_project(project)
def clean_project(project_name):
info = project_info(project_name)
project_dir = get_project_dir(project_name)
if not os.path.exists(project_dir):
return
with cd(project_dir):
clean_command = info['clean'].strip().split()
run_cmd(clean_command)
run_cmd(['rm', '-r', DLJC_OUTPUT_DIR])
if 'git-url' in info:
run_cmd(['git', 'reset', '--hard', 'HEAD'])
run_cmd(['git', 'clean', '-dxf', '.'])
def get_class_dirs(project_name):
classdirs = []
dljc_output = os.path.join(get_project_dir(project_name),
DLJC_OUTPUT_DIR,
'javac.json')
if not os.path.exists(dljc_output):
print('Tried to get classdirs from project where DLJC has not been run.')
return None
with open(dljc_output, 'r') as f:
javac_commands = json.loads(f.read())
for command in javac_commands:
classdir = command['javac_switches'].get('d')
if classdir:
classdirs.append(classdir)
return classdirs
def copy_dyntrace_files(project_name):
project_dir = get_project_dir(project_name)
out_dir = os.path.join(project_dir, DLJC_OUTPUT_DIR)
mkdir(out_dir)
addons = [f for f in os.listdir(DYNTRACE_ADDONS_DIR) \
if f.startswith(project_info(project_name)['name']+".")]
for addon in addons:
addon_type = addon.split('.', 1)[-1]
shutil.copyfile(os.path.join(DYNTRACE_ADDONS_DIR, addon),
os.path.join(out_dir, addon_type))
def run_dljc(project_name, tools=[], options=[]):
project = project_info(project_name)
timelimit = project.get('timelimit') or 900
extra_opts = project.get('dljc-opt')
exclusions = project['exclude']
skipped_tools = [tool for tool in exclusions if tool in tools]
remaining_tools = [tool for tool in tools if tool not in exclusions]
# If tools is non-empty but remaining_tools is empty, then we don't need to do anything
if tools and not remaining_tools:
print("Skipping {} on {}".format(', '.join(skipped_tools), project_name))
return
elif tools:
if skipped_tools:
print("Running {} on {} (skipping {})".format(
', '.join(remaining_tools),
project_name,
', '.join(skipped_tools)))
else:
print("Running {} on {}".format(
', '.join(remaining_tools),
project_name))
copy_dyntrace_files(project_name)
if not os.environ.get('DAIKONDIR'):
os.environ['DAIKONDIR'] = os.path.join(TOOLS_DIR, 'daikon-src')
project_dir = get_project_dir(project_name)
with cd(project_dir):
build_command = project['build'].strip().split()
dljc_command = [DLJC_BINARY,
'-l', LIBS_DIR,
'-o', DLJC_OUTPUT_DIR,
'--timeout', str(timelimit)]
if remaining_tools:
dljc_command.extend(['-t', ','.join(remaining_tools)])
dljc_command.extend(options)
if extra_opts:
dljc_command.extend(extra_opts.split())
dljc_command.append('--')
dljc_command.extend(build_command)
result = run_cmd(dljc_command, 'dljc')
if result['return_code'] != 0:
print("DLJC command failed on {}".format(project_name))
sys.exit(1)
def ensure_java_home():
if not os.environ.get('JAVA_HOME'):
# If we're on OS X, we can auto-set JAVA_HOME
if os.path.exists('/usr/libexec/java_home'):
java_home = run_cmd(['/usr/libexec/java_home'])['output'].strip()
print("Automatically setting JAVA_HOME to {}".format(java_home))
os.environ['JAVA_HOME'] = java_home
else:
caller = inspect.stack()[1][3]
print("ERROR: {} requires the JAVA_HOME environment variable to be set, and we couldn't set it automatically. Please set the JAVA_HOME environment variable and try again.".format(caller))
sys.exit(0)
def get_os_lib_path_name():
import platform
if platform.system() == 'Darwin':
return 'DYLD_LIBRARY_PATH'
else:
return 'LD_LIBRARY_PATH'
CHECKER_ENV_SETUP = False
def setup_checker_framework_env():
global CHECKER_ENV_SETUP
if CHECKER_ENV_SETUP:
return
jsr308 = TOOLS_DIR
os.environ['JSR308'] = jsr308
os.environ[get_os_lib_path_name()] = os.path.join(TOOLS_DIR, 'checker-framework-inference', 'lib')
afu = os.path.join(jsr308, 'annotation-tools', 'annotation-file-utilities')
os.environ['AFU'] = afu
os.environ['PATH'] += ':' + os.path.join(afu, 'scripts')
CHECKER_ENV_SETUP = True
def recompile_checker_framework():
""" recompile checker framework stuffs
include:
- checker-framework-inference
- ontology
"""
ensure_java_home()
checker_framework_inference_dir = os.path.join(TOOLS_DIR, "checker-framework-inference")
ontology_dir = os.path.join(TOOLS_DIR, "ontology")
with cd(checker_framework_inference_dir):
setup_checker_framework_env()
run_cmd("gradle dist -i", 'checker_build')
with cd(ontology_dir):
run_cmd("gradle build -i -x test", 'checker_build')
install_cmd = "mvn -B install:install-file -Dfile=dist/ontology.jar -DgroupId=pascaliUWat -DartifactId=ontology -Dversion=1.0 -Dpackaging=jar"
run_cmd(install_cmd, 'checker_build')