-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild-aux.py
More file actions
184 lines (155 loc) · 5.49 KB
/
build-aux.py
File metadata and controls
184 lines (155 loc) · 5.49 KB
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
#!/usr/bin/env python
# coding: utf8
import sys
def prterr(s):
sys.stderr.write(s + "\n")
def usage():
"""Show usage help."""
prterr(u"""Usage:
python build-aux.py <command> [<args>]
Where command can be:
setvars <file> <var>=<value> ...:
Preprocesses the given file in place, to replace values like
version and others.
oss-process <file>:
Processes the given file for OpenSim and outputs the result to
standard output. If <file> is not given, read from standard input.
rm <file> [<file>...]
Deletes the given list of files.
""")
def rm(filelist):
"""Delete the given list of files, ignoring 'file not found' errors."""
import os
for i in filelist:
try:
os.unlink(i)
except OSError as e:
if e.errno != 2:
raise
return 0
def oss_process(filename):
"""Process a file for OpenSim Scripting."""
import re
# Regex that replaces a line with its OSS version when one's specified.
os_line_re = re.compile(r'^( *).*?// ?OSS::(.*)$', re.MULTILINE)
# Regex that removes lines between //LSL:: and //::LSL (can't begin on first line)
sl_block_re = re.compile(r'\n\s*// ?LSL::(?:[^\n]|\n(?![ \t]*// ?::LSL[^\n]*?(?=\n)))*\n[ \t]*// ?::LSL[^\n]*(?=\n)')
# Regex that removes /*OSS:: and its matching */ (can't begin on first line)
os_block_re = re.compile(r'\n\s*/\* ?OSS::[^\n]*(\n(?:[^\n]|\n(?![ \t]*\*/))*)\n[ \t]*\*/[^\n]*(?=\n)')
# Regex that reads a token, can be a string or comment or #IDENT or anything else,
# capturing a group for IDENT when #IDENT is found.
token_re = re.compile(r'"(?:\\.|[^"\\]+)*"|/\*[\S\s]*?\*/|//[^\n]*|/|[^#/"]+|#([a-zA-Z_][a-zA-Z0-9_]*)|#')
if filename is not None:
f = open(filename, "r")
else:
f = sys.stdin
try:
s = f.read()
finally:
if filename is not None:
f.close()
# UUIDs in OpenSim
s = s.replace('f2e0ed5e-6592-4199-901d-a659c324ca94',
'206fcbe2-47b3-41e8-98e6-8909595b8605')
s = s.replace('3506213c-29c8-4aa1-a38f-e12f6d41b804',
'd648fb86-d59b-4d69-8d3c-d00862aec699')
# OpenSim 0.8.0 does not support this constant.
#s = s.replace('OBJECT_BODY_SHAPE_TYPE', '26 /*OBJECT_BODY_SHAPE_TYPE*/')
# Tag OpenSim releases
s = s.replace('\n *\n * This Source Code', '\n * (OpenSim version)\n *\n * This Source Code')
s = os_line_re.sub(r'\1\2', s)
s = sl_block_re.sub('', s)
s = os_block_re.sub(r'\1', s)
new = ''
for match in token_re.finditer(s):
if match.group(1):
new += match.group(1) # remove '#'
else:
new += match.group(0)
s = new
sys.stdout.write(s)
return 0
def setvars(filename, *settings):
"""Preprocess a file in place, to replace values"""
import re
values = {}
var_value_re = re.compile(r'^([^=]*)=(.*)$')
for v in settings:
match = var_value_re.search(v)
if not match:
sys.stderr.write('Incorrect setting format, it should be key=value\n')
return 1
values[match.group(1)] = match.group(2)
if filename is not None:
f = open(filename, "r")
else:
f = sys.stdin
try:
s = f.read()
finally:
if filename is not None:
f.close()
orig = s
# Regex to read a token in the set of expected tokens.
# NOTE: This regex deliberately ignores // so that //#variable = value; is still valid.
token_re = re.compile(r'"(?:\\.|[^"\\]+)*"|/\*[\S\s]*?\*/|/|;|[^#;/"]+|#([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*|#')
p = 0
while True:
match = token_re.search(s, p)
if not match:
break
if match.group(1) in values:
# found '#variable = ' in the code, and variable matches
value = values[match.group(1)]
# mark the start of the value as the end of the match
vbegin = match.end(0)
while True:
# keep skipping tokens until we hit a ';'
p = match.end(0)
match = token_re.search(s, p)
if not match:
# end of script? this is wrong but better don't crash
vend = vbegin
break
if match.group(0) == ';':
# mark end of value before the matching ';'
vend = match.start(0)
break
# Replace the value between vbegin and vend
s = s[:vbegin] + value + s[vend:]
# Advance past the value to keep searching
p = vbegin + len(value)
continue
# not a token we're interested in - keep searching after it
p = match.end(0)
if s != orig:
if filename is not None:
f = open(filename, "w")
else:
f = sys.stdout
try:
f.write(s)
finally:
if filename is not None:
f.close()
def main(argc, argv):
if argc < 2:
usage()
return 0
cmd = argv[1]
if cmd == 'rm':
return rm(argv[2:])
if cmd == 'setvars':
filename = None if argv[2] == '-' else argv[2]
return setvars(filename, *argv[3:])
if cmd == 'oss-process':
if argc > 3:
usage()
return 1
filename = argv[2] if argc == 3 else None
return oss_process(filename)
usage()
return 1
ret = main(len(sys.argv), sys.argv)
if ret is not None and ret > 0:
sys.exit(ret)