import sys
import os
import subprocess
ANCHOR_START = '// [ANCHOR START] CONST-TO-STRUCT.PY //'
ANCHOR_ENDED = '// [ANCHOR ENDED] CONST-TO-STRUCT.PY //'
def walk_mod(walk=os.walk, path='src'):
for current, dirs, files in walk(path):
for file in files:
realpath = os.path.realpath(os.path.join(current, file))
yield (realpath, single_mod(realpath))
def single_mod(f):
m = os.path.basename(f)
is_mod = False
if 'mod.rs' in m:
is_mod = True
m = os.path.basename(os.path.dirname(f))
if m.endswith('.rs'):
m = m[:-3]
if '/cfg/' in f.replace('\\', '/'):
if not is_mod:
m = 'cfg_' + m
code = ''
with open(f, 'r') as fo:
code = fo.read()
code = code.replace('\n', ';').replace('\r', ';')
code = code.split(';')
code = [it for it in code if len(it) > 0]
fo.close()
line = ''
def get_line():
nonlocal line
try:
line = code.pop(0)
except IndexError:
return ''
else:
return line
info_struct_name = '%s_info' % m
info_struct = '\n'.join([
'#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]',
'pub struct %s {' % info_struct_name,
]) + '\n'
all_info_fn = '\n'.join([
'pub const fn all_info() -> %s {' % info_struct_name,
' %s {' % info_struct_name,
]) + '\n'
all_info_json_impl = '\n'.join([
'#[cfg(feature = "json")]',
'impl %s {' % info_struct_name,
' pub fn to_json(&self) -> serde_json::Value {',
' serde_json::json!({',
]) + '\n'
while len(get_line()) > 0:
if 'pub const' in line and ':' in line and '=' in line:
line = line.strip()
skip = False
for ex in ('pub fn all_info', 'pub const ALL_INFO', '/*', '*/', '//', '{', '}', ','):
if ex in line:
skip = True
break
if skip:
continue
for c in '\r\n\t':
line = line.replace(c, '')
line = line.replace('=', ':').replace(';', '')
if line.startswith('pub const '):
line = line[10:]
words = line.split(':')
const_name = words[0].strip()
lower_name = const_name.lower()
type = words[1].strip()
info_struct += ' pub %s: %s,\n' % (lower_name, type)
all_info_fn += ' %s: %s,\n' % (lower_name, const_name)
cal = ''
if type.endswith('_info'):
cal = '.to_json()'
all_info_json_impl += ' "%s": self.%s,\n' % (lower_name, lower_name+cal)
info_struct += '}\n'
all_info_fn += ' }\n}\n'
all_info_json_impl += ' })\n }\n}\n'
all_info = 'pub const ALL_INFO: %s = all_info();\n' % info_struct_name
out = info_struct + all_info + all_info_fn + all_info_json_impl
prefix = '''%s
/*
* the following source code is automatic generated by const-to-struct.py
* DO NOT EDIT.
*/
''' % ANCHOR_START
return prefix + out
def update_rs(f, code):
orig = open(f, 'r').read()
if ANCHOR_START not in orig:
raise SyntaxError('no "start anchor" in rust code.')
start = orig.index(ANCHOR_START)
ended = None
try:
ended = orig.index(ANCHOR_ENDED) + len(ANCHOR_ENDED)
except ValueError:
print('WARNING: no "end anchor" in rust code, assume to EOF (append to the end of ".rs" files)')
new = orig[:start]
if not ended:
new += code
new += ANCHOR_ENDED
else:
new += code
new += ANCHOR_ENDED
new += orig[ended:]
if conf['dry_run']:
print(code)
return
open(f, 'w').write(new)
def run():
for file, code in walk_mod():
print("Entering:", file)
try:
update_rs(file, code)
except SyntaxError as e:
print(repr(e))
conf = {
'dry_run': False
}
def main():
try:
if len(sys.argv[1])>0:
conf['dry_run'] = True
return run()
except IndexError:
pass
p = subprocess.Popen(
['git', 'show', '-q'],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if p.wait() != 0:
print('ERROR: Refusing to start, due to you are not in a git repo.')
raise SystemExit(1)
try:
os.stat('Cargo.toml')
except FileNotFoundError:
print("ERROR: Refusing to start, due to Cargo.toml does not exists in current directory (PWD).")
raise SystemExit(2)
if len(os.popen("git diff --raw").read().replace('\r', '').replace('\n', '')) > 0:
print('ERROR: Refusing to start, due to your git repo have some files that is not staged.')
raise SystemExit(3)
run()
if __name__ == '__main__':
main()