traintastic/utils/checkmanual.py

192 Zeilen
7.4 KiB
Python

import sys
import os
import codecs
import re
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
def print_error(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def read_file(filename):
with codecs.open(os.path.join(PROJECT_ROOT, filename), 'r', 'utf-8') as f:
return f.read()
def write_file(filename, value):
with codecs.open(os.path.join(PROJECT_ROOT, filename), 'w', 'utf-8') as f:
f.write(value)
def check_messages():
success = True
# read info from hpp file:
logmessage_hpp = os.path.join(PROJECT_ROOT, 'shared', 'src', 'traintastic', 'enum', 'logmessage.hpp')
hpp = read_file(logmessage_hpp)
messages = re.findall(r'\b(D|I|N|W|E|C|F)(\d{4})_[A-Z0-9_]+[ ]*=[ ]*LogMessageOffset::[a-z]+[ ]+\+[ ]+(\d{4})', hpp)
for message in messages:
if message[1] != message[2]:
print_error('Error: ' + message[0] + message[1] + ' != ' + message[2] + ' in ' + logmessage_hpp)
success = False
success &= check_message_file('D', 'debug.md', messages)
success &= check_message_file('I', 'info.md', messages)
success &= check_message_file('N', 'notice.md', messages)
success &= check_message_file('W', 'warning.md', messages)
success &= check_message_file('E', 'error.md', messages)
success &= check_message_file('C', 'critical.md', messages)
success &= check_message_file('F', 'fatal.md', messages)
return success
def check_message_file(prefix, filename, messages):
success = True
md_file = os.path.join(PROJECT_ROOT, 'manual', 'traintasticmanual', 'en-us', 'messages', filename)
md = read_file(md_file)
for message in messages:
if prefix == message[0]:
id = message[0] + message[1]
if re.search('^## ' + id + ': .*{#' + id.lower() + '}$', md, re.MULTILINE) is None:
print_error('Error: ' + id + ' missing in ' + md_file)
success = False
return success
def check_lua_enum():
success = True
# read info from hpp files:
enums_hpp = read_file(os.path.join('server', 'src', 'lua', 'enums.hpp'))
m = re.findall(r'#define LUA_ENUMS([ \nA-Za-z0-9_,\\]+)\n\n', enums_hpp)
m = re.sub(r'[ \\\n]+', '', m[0])
enums = []
for cpp_name in m.split(','):
hpp = read_file(os.path.join('shared', 'src', 'traintastic', 'enum', cpp_name.lower() + '.hpp'))
enum = re.search(r'enum class ' + cpp_name + r'[ ]*(:[ ]*[A-Za-z0-9_]+|)[ \n]*{(.+?)};', hpp, re.DOTALL)
values = [{'cpp_name': m[0], 'description': m[3]} for m in re.findall(r'^[ ]*([A-Za-z0-9_]+)[ ]*=[ ]*.+?[ ]*(,|)[ ]*(//!< (.+)|)\n', enum.group(2), re.MULTILINE)] if enum is not None else None
info = re.search(r'TRAINTASTIC_ENUM\([ ]*' + cpp_name + r'[ \n]*,[ \n]*"([a-z0-9_]+)"[ \n]*,[ \n]*\d+[ \n]*,[ \n]*{(.+?)}[ \n]*\);', hpp, re.DOTALL)
if info is not None:
for value in values:
m = re.search(cpp_name + '::' + value['cpp_name'] + r'[ ]*,[ ]*"([A-Za-z0-9_]+)"', info.group(2))
if m is not None:
value['lua_name'] = m.group(1).upper()
enums.append({
'cpp_name': cpp_name,
'lua_name': info.group(1) if info is not None else None,
'values': values,
})
# check manual markdown files
for enum in enums:
md_file = os.path.join(PROJECT_ROOT, 'manual', 'traintasticmanual', 'en-us', 'lua', 'library', 'enum', enum['lua_name'].replace('_', '') + '.md')
if not os.path.exists(md_file):
print_error('Error: ' + md_file + ' doesn\'t exist')
md = \
'# `enum.' + enum['lua_name'] + '` {#lua-enum-' + enum['lua_name'].replace('_', '') + '}' + os.linesep + \
os.linesep + \
'TODO' + os.linesep + \
os.linesep + \
'## Constants' + os.linesep
for value in enum['values']:
md += \
os.linesep + \
'### `enum.' + enum['lua_name'] + '.' + value['lua_name'] + '`'+ os.linesep + \
(value['description'] if value['description'] != '' else 'TODO') + os.linesep
write_file(md_file, md)
print('Bootstrapped: ' + md_file)
success = False
continue
md = read_file(md_file)
# check if all values exist
for value in enum['values']:
label = '`enum.' + enum['lua_name'] + '.' + value['lua_name'] + '`'
if re.search('^### ' + label, md, re.MULTILINE) is None:
print_error('Error: ' + label + ' missing in ' + md_file)
success = False
return success
def check_lua_set():
success = True
# read info from hpp files:
sets_hpp = read_file(os.path.join('server', 'src', 'lua', 'sets.hpp'))
m = re.findall(r'#define LUA_SETS([ \nA-Za-z0-9_,\\]+)\n\n', sets_hpp)
m = re.sub(r'[ \\\n]+', '', m[0])
sets = []
for cpp_name in m.split(','):
hpp = read_file(os.path.join('shared', 'src', 'traintastic', 'set', cpp_name.lower() + '.hpp'))
set = re.search(r'enum class ' + cpp_name + r'[ ]*(:[ ]*[A-Za-z0-9_]+|)[ \n]*{(.+?)};', hpp, re.DOTALL)
values = [{'cpp_name': m[0], 'description': m[3]} for m in re.findall(r'^[ ]*([A-Za-z0-9_]+)[ ]*=[ ]*.+?[ ]*(,|)[ ]*(//!< (.+)|)\n', set.group(2), re.MULTILINE)] if set is not None else None
info = re.search(r'TRAINTASTIC_SET\([ ]*' + cpp_name + r'[ \n]*,[ \n]*"([a-z0-9_]+)"[ \n]*,[ \n]*\d+[ \n]*,[ \n]*\(.+?\),[ \n]*{(.+?)}[ \n]*\);', hpp, re.DOTALL)
if info is not None:
for value in values:
m = re.search(cpp_name + '::' + value['cpp_name'] + r'[ ]*,[ ]*"([A-Za-z0-9_]+)"', info.group(2))
if m is not None:
value['lua_name'] = m.group(1).upper()
sets.append({
'cpp_name': cpp_name,
'lua_name': info.group(1) if info is not None else None,
'values': values,
})
# check manual markdown files
for set in sets:
md_file = os.path.join(PROJECT_ROOT, 'manual', 'traintasticmanual', 'en-us', 'lua', 'library', 'set', set['lua_name'].replace('_', '') + '.md')
if not os.path.exists(md_file):
print_error('Error: ' + md_file + ' doesn\'t exist')
md = \
'# `set.' + set['lua_name'] + '` {#lua-set-' + set['lua_name'].replace('_', '') + '}' + os.linesep + \
os.linesep + \
'TODO' + os.linesep + \
os.linesep + \
'## Constants' + os.linesep
for value in set['values']:
md += \
os.linesep + \
'### `set.' + set['lua_name'] + '.' + value['lua_name'] + '`' + os.linesep + \
(value['description'] if value['description'] != '' else 'TODO') + os.linesep
write_file(md_file, md)
print('Bootstrapped: ' + md_file)
success = False
continue
md = read_file(md_file)
# check if all values exist
for value in set['values']:
label = '`set.' + set['lua_name'] + '.' + value['lua_name'] + '`'
if re.search('^### ' + label, md, re.MULTILINE) is None:
print_error('Error: ' + label + ' missing in ' + md_file)
success = False
return success
success = True
success &= check_messages()
success &= check_lua_enum()
success &= check_lua_set()
if not success:
sys.exit(1)