#! /usr/bin/env python
# -*- coding: utf-8 -*-
import argparse
import dbd
import operator
import os
import sys
def merge_build_ranges(builds):
out = []
import itertools
for version, elements in itertools.groupby(sorted(builds), key=dbd.build_version_raw.version):
builds = [element.build for element in elements]
cur = last = builds[0]
for build in builds[1:]:
if build - last != 1:
out += [((version, cur), (version, last) if cur != last else None)]
cur = build
last = build
out += [((version, cur), (version, last) if cur != last else None)]
return out
import argparse
parser = argparse.ArgumentParser()
parser.add_argument( '--definitions', dest="definitions", type=str, required=True
, help="location of .dbd files")
parser.add_argument( '--output', dest="output", type=str, required=True
, help="directory to dump wiki pages to")
parser.add_argument( '--only', dest="only", action='append'
, help='if given, a list of tables to dump')
args = parser.parse_args()
if not os.path.isdir (args.output):
os.makedirs (args.output)
dbds = {}
if args.only:
for table in args.only:
dbds[table] = dbd.parse_dbd_file(os.path.join(args.definitions, "{}{}".format(table, dbd.file_suffix)))
else:
dbds = dbd.parse_dbd_directory(args.definitions)
file_data = {}
for name, parsed in dbds.items():
file_data[name] = ""
columns = {}
for column in parsed.columns:
columns[column.name] = column
assert(len(columns)==len(parsed.columns))
for definition in sorted(parsed.definitions, key=operator.attrgetter('builds')):
def wiki_format_template(templ, *args):
templates = { "Type": ("{{{{Type|{}}}}}", "{}ⁱ")
, "Unverified": ("{{{{Unverified|{}}}}}", "{}ᵘ")
, "ForeignKey": ("{{{{Type/foreign_key|type={}|table={}|column={}}}}}", "foreign_keyⁱ<{}, &{}Rec::{}>")
, "SectionBox": ("{{{{SectionBox|{}}}}}", "WRONG {} WRONG")
, "PrettyVersion": ("{{{{Sandbox/PrettyVersion|{}}}}}", "WRONG {} WRONG")
, "VersionRange": ("{{{{Sandbox/VersionRange|{}|{}}}}}", "WRONG {}|{} WRONG")
}
sf, lf = templates[templ]
s = sf.format(*args)
l = len(lf.format(*args))
return (s, l)
def wiki_format_raw(fmt, *args):
s = fmt.format(*args)
return (s, len(s))
lines = []
for entry in definition.entries:
meta = columns[entry.column]
#! \todo annotations
def wiki_format_type():
print (meta.type, entry.column, name)
if meta.type in ["uint", "int"]:
type = wiki_format_raw("{}{}_t", meta.type if not entry.is_unsigned else "uint", entry.int_width if entry.int_width else 32)
if meta.foreign:
return wiki_format_template("ForeignKey", type[0], meta.foreign.table, "m_{}".format(meta.foreign.column))
return type
assert (not entry.int_width)
assert (not meta.foreign)
if meta.type in ["string", "locstring"]:
wikiname = "stringref" if meta.type == "string" else "langstringref"
return wiki_format_template("Type", wikiname)
else:
return wiki_format_raw("{}", meta.type)
type_str = wiki_format_type()
array_str_str = "[{}]".format(entry.array_size) if entry.array_size else ""
array_str = (array_str_str, len(array_str_str))
if meta.is_confirmed_name:
name_str = wiki_format_raw("m_{}".format(entry.column))
else:
name_str = wiki_format_template("Unverified", "m_{}".format(entry.column))
comments = []
merged_str_pattern = " {} {}{};"
for annotation in entry.annotation:
if annotation == "noninline":
merged_str_pattern = " // {} {}{};"
comments += ["non-inline field"]
elif annotation == "id":
pass
else:
comments += ["{}".format(annotation)]
merged_str = merged_str_pattern.format(type_str[0], name_str[0], array_str[0])
merged_str_visual_len = len(merged_str_pattern.format('t'*type_str[1], 'n'*name_str[1], 'a'*array_str[1]))
comments += [entry.comment] if entry.comment else []
comments += [meta.comment] if meta.comment else []
lines += [(merged_str, merged_str_visual_len, comments)]
comment_indent = max(lines, key=operator.itemgetter(1))[1] + 2
build_ranges = merge_build_ranges(definition.builds)
multiple_builds = 0
section_title_builds = []
for begin, end in build_ranges:
if not end:
section_title_builds += ["{}.{}".format(begin[0], begin[1])]
multiple_builds += 1
else:
section_title_builds += ["{}.{}-{}.{}".format(begin[0], begin[1], end[0], end[1])]
multiple_builds += 2
build_ranges_str = ', '.join(section_title_builds)
layout_hashes = [str(layout) for layout in definition.layouts]
#! \todo This is a really shit section title.
file_data[name] += "=={}==\n".format(", ".join(section_title_builds + layout_hashes))
box_content = "This definition applies to "
def wiki_format_version(version, build, prefix = ''):
#! \todo will break with version 10.
return "{}expansionlevel={}|{}build={}.{}".format(prefix, version[0], prefix, version, build)
if multiple_builds == 1:
build = build_ranges[0][0]
box_content += "version {}".format(wiki_format_template("PrettyVersion", wiki_format_version(build[0], build[1]))[0])
elif multiple_builds > 1:
box_content += "versions \n* "
strs = []
for begin, end in build_ranges:
if not end:
strs += [wiki_format_template("PrettyVersion", wiki_format_version(begin[0], begin[1]))[0]]
else:
strs += [wiki_format_template("VersionRange", wiki_format_version(begin[0], begin[1], "min_"), wiki_format_version(end[0], end[1], "max_"))[0]]
box_content += "\n* ".join (strs)
if layout_hashes:
if multiple_builds:
box_content += "{}and ".format(" " if multiple_builds == 1 else "\n")
if len(layout_hashes) == 1:
box_content += "layout hash {}".format(layout_hashes[0])
elif len(layout_hashes) > 1:
box_content += "layout hashes \n* {}".format("\n* ".join(layout_hashes))
file_data[name] += wiki_format_template("SectionBox", box_content)[0] + "\n"
for comment in definition.comments:
file_data[name] += str(comment) + "\n\n"
file_data[name] += " struct {}Rec {{\n".format(name)
for line, linelen, comments in lines:
if comments:
file_data[name] += "{}{} // {}\n".format(line, ' '*(comment_indent - linelen), comments[0])
for comment in comments[1:]:
file_data[name] += "{} // {}\n".format(" "*comment_indent, comment)
else:
file_data[name] += line + "\n"
file_data[name] += " };\n"
for name, data in file_data.items():
print(name)
with open(os.path.join(args.output, "{}.mwiki".format(name)), "w") as f:
f.write(data)