import json
import requests
import subprocess
from copy import deepcopy
from pathlib import Path
TOOLFORGE_USERINDEX = [
"archive",
"filearchive",
"logging",
"oldimage",
"recentchanges",
"revision",
]
TOOLFORGE_ACTOR = [
"user",
"archive",
"ipblocks",
"image",
"oldimage",
"filearchive",
"recentchanges",
"logging",
"revision"
]
def snake_to_camel(phrase: str) -> str:
sp = phrase.split('_')
return ''.join(word.title() for word in sp)
def strip_prefix(items: list) -> dict:
data = {}
for item in items:
data[item] = item
last = deepcopy(data)
while True:
first = list(data.values())[0].split('_', 1)[0] + '_'
print(first)
for key in data:
print(key)
print(data[key])
if data[key].startswith(first):
data[key] = data[key][len(first):]
else:
return last
last = deepcopy(data)
def build_rust(table: dict, toolforge=False) -> str:
if toolforge:
rust = '#[cfg(feature = "toolforge")]\n'
rust += '#[cfg_attr(docs, doc(cfg(feature = "toolforge")))]\n'
else:
rust = ""
name = table["name"]
rust += f"/// `{name}` table\n"
rust += "///\n"
if toolforge:
rust += "/// This is an optimized view for Toolforge users.\n"
else:
rust += f"/// Documentation may be available on [mediawiki.org](https://www.mediawiki.org/wiki/Manual:{name}_table).\n"
rust += "#[non_exhaustive]\n"
rust += "#[derive(Copy, Clone, IdenStatic)]\n"
rust += f'#[iden="{name}"]\n'
camel_name = snake_to_camel(name)
print(f"Generating {camel_name} for {name}")
rust += f"pub enum {camel_name} {{\nTable,\n"
columns = [item["name"] for item in table["columns"]]
stripped = strip_prefix(columns)
for column, name in sorted(stripped.items()):
camel_name = snake_to_camel(name)
rust += f"/// `{column}` column\n"
rust += f'#[iden="{column}"]\n'
rust += f"{camel_name},\n"
rust += "}"
rust += "\n\n"
return rust
def make(repo: str, path: str, filename: str):
req = requests.get(f"https://github.com/wikimedia/{repo.replace('/', '-')}/raw/master/{path}")
req.raise_for_status()
tables = req.json()
rust = "// This file is autogenerated.\n"
rust += f"//! Schema definitions for the `{repo}` repository\n"
rust += "use sea_query::IdenStatic;\n\n"
for table in sorted(tables, key=lambda x: x["name"]):
rust += build_rust(table)
if table["name"] in TOOLFORGE_USERINDEX:
table["name"] = f"{table['name']}_userindex"
rust += build_rust(table, toolforge=True)
if table["name"] == "actor":
for variant in TOOLFORGE_ACTOR:
table["name"] = f"actor_{variant}"
rust += build_rust(table, toolforge=True)
Path(f"src/{filename}.rs").write_text(rust)
subprocess.check_call(["cargo", "fmt"])
print("Done!")
def main():
make('mediawiki/core', 'maintenance/tables.json', 'core')
make('mediawiki/extensions/Linter', 'sql/tables.json', 'linter')
make('mediawiki/extensions/PageAssessments', 'db/tables.json', 'page_assessments')
make('mediawiki/extensions/ProofreadPage', 'sql/tables.json', 'proofread_page')
if __name__ == "__main__":
main()