/
metapy.py
136 lines (103 loc) · 3.44 KB
/
metapy.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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os.path as osp
import sys
import traceback
from functools import partial
import hashlib
SEP='//#'
SEP_BEGIN='/*#'
SEP_END='#*/'
HASH_BODY = """ This file was autogenerated. Hash of autogenerated content:
%s
"""
HEADER = SEP_BEGIN + HASH_BODY + SEP_END + '\n'
class ListOut(object):
def __init__(self, l):
self._l = l
def write(self, txt):
self._l.append(txt)
def run_code(code, global_context, output):
sys.stdout = ListOut(output)
try:
exec(code, global_context)
except:
sys.stdout = sys.__stdout__
print "Exception in user code:"
print '-'*60
traceback.print_exc(file=sys.stdout)
print '-'*60
sys.stdout = sys.__stdout__
def include_h(filename, global_context):
remove_ext = lambda f : osp.splitext(f)[0]
basename = remove_ext(remove_ext(filename))
for ext in ('.h', '.hxx', '.hpp', '.txx'):
new_filename = basename + ext + '.meta'
if osp.exists(new_filename):
parse_file(new_filename, global_context)
def parse_file(filename, global_context=None):
f = open(filename)
output = []
current_code_block = None
if global_context is None:
global_context = {}
global_context['include_h'] = partial(include_h, filename, global_context)
global_context['__file__'] = filename
run = partial(run_code, global_context=global_context, output=output)
for line in f:
line = line.rstrip()
if current_code_block is not None:
if line.endswith(SEP_END):
run('\n'.join(current_code_block))
current_code_block = None
else:
current_code_block.append(line)
else:
if line.startswith(SEP_BEGIN):
current_code_block = []
elif line.startswith(SEP):
run(line.split(SEP)[1])
else:
output.append(line + '\n')
return output
def usage():
print """usage: python %s file1.x.meta [file2.x.meta ... fileN.x]
Generates files file1.x, file2.x, ..., fileN.x.
""" % sys.argv[0]
exit(1)
def compute_sha(data):
sha = hashlib.sha1()
sha.update(data)
return sha.hexdigest()
def check_generated_file_was_not_manually_edited(out_filename):
out_file = open(out_filename)
lines = out_file.readlines()
parsed_sha = lines[1].strip()
out_file_content = ''.join(lines[3:])
computed_sha = compute_sha(out_file_content)
if computed_sha != parsed_sha:
print '>'*100
print 'ERROR file %s was edited manually. Plese delete your modifications' \
' or delete the file!' % out_filename
print '>'*100
exit(1)
return parsed_sha
def main():
if len(sys.argv) < 2:
usage()
for filename in sys.argv[1:]:
out_filename = osp.splitext(filename)[0]
old_sha = None
if osp.exists(out_filename):
old_sha = check_generated_file_was_not_manually_edited(out_filename)
new_content = ''.join(parse_file(filename))
new_sha = compute_sha(new_content)
if osp.exists(out_filename) and new_sha == old_sha:
# do not overwrite the generated file if the content has not changed
continue
else:
out_file = open(out_filename, 'w')
out_file.write(HEADER % new_sha)
out_file.write(new_content)
if __name__ == '__main__':
main()