Public Access
171 lines
5.1 KiB
Python
171 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
DATA = Path("data")
|
|
REPORTS = Path("reports")
|
|
|
|
|
|
def versions():
|
|
return sorted(
|
|
[d for d in DATA.iterdir() if d.is_dir()],
|
|
key=lambda p: [int(x) for x in p.name.split(".")]
|
|
)
|
|
|
|
|
|
def modules():
|
|
first = versions()[0]
|
|
return sorted(f.stem for f in first.glob("*.json"))
|
|
|
|
class Module(object):
|
|
def __init__(self, module):
|
|
self.name = module
|
|
self.versionen = {}
|
|
self.classes = {}
|
|
self.operations = []
|
|
|
|
def read_data(self):
|
|
for version in versions():
|
|
|
|
vers = version.name
|
|
self.versionen[vers] = {}
|
|
|
|
infile = version / f"{self.name}.json"
|
|
if not infile.exists():
|
|
continue
|
|
|
|
data = json.loads(infile.read_text())
|
|
|
|
for f in data["files"]:
|
|
f['version'] = vers
|
|
file = f['file']
|
|
classe = f.get('class', 'ohne')
|
|
method = f.get('method', 'ohne')
|
|
if classe not in self.versionen[vers]:
|
|
self.versionen[vers][classe] = []
|
|
self.versionen[vers][classe].append(f)
|
|
try:
|
|
if vers not in self.classes[classe]:
|
|
self.classes[classe][vers] = []
|
|
except KeyError:
|
|
self.classes[classe] = {}
|
|
self.classes[classe][vers] = []
|
|
self.classes[classe][vers].append(f)
|
|
for o in f['operations']:
|
|
o['class'] = classe
|
|
o['method'] = method
|
|
o['file'] = file
|
|
o['version'] = vers
|
|
self.operations.append(o)
|
|
|
|
def operation_key(self, operation):
|
|
# kwargs are intentionally ignored for now.
|
|
# The key is only used to collapse repeated migration blocks;
|
|
# it is not intended to establish semantic equality.
|
|
return (
|
|
operation.get("phase"),
|
|
operation.get("operation"),
|
|
operation.get("object"),
|
|
tuple(operation.get("args", [])),
|
|
operation.get("condition"),
|
|
)
|
|
def block_key(self, operations):
|
|
return tuple(self.operation_key(op) for op in operations)
|
|
|
|
def write_data(self):
|
|
|
|
outfile = REPORTS / f"{self.name}.md"
|
|
|
|
with outfile.open("w", encoding="utf8") as out:
|
|
|
|
out.write(f"# {self.name}\n\n")
|
|
|
|
# iterate all classes
|
|
for c in sorted(self.classes):
|
|
classe = self.classes[c]
|
|
|
|
out.write(f"## Klasse {c}\n\n")
|
|
|
|
last_blocks = None
|
|
|
|
# iterate all Versions
|
|
for k in sorted(classe.keys()):
|
|
v = classe.get(k, None)
|
|
if not v:
|
|
continue
|
|
|
|
if last_blocks == None:
|
|
last_blocks = len(v) * [None,]
|
|
|
|
out.write(f"### {k}\n\n")
|
|
|
|
# iterate all files / occureces
|
|
for i, m in enumerate(v):
|
|
|
|
# repeating?
|
|
key = self.block_key(m["operations"])
|
|
|
|
old_block = last_blocks[i]
|
|
if key == old_block:
|
|
continue
|
|
elif old_block and key[:len(old_block)] == old_block:
|
|
m["operations"] = m['operations'][len(old_block):]
|
|
|
|
last_blocks[i] = key
|
|
|
|
|
|
out.write(f"file: {m['file']} : {m['line']}\n")
|
|
|
|
for op in m["operations"]:
|
|
|
|
out.write(
|
|
f"- **{op['phase']}** "
|
|
f"`{op['operation']}`\n"
|
|
)
|
|
|
|
if "condition" in op:
|
|
out.write(
|
|
f" - condition: `{op['condition']}`\n"
|
|
)
|
|
|
|
if op["object"]:
|
|
out.write(
|
|
f" - object: `{op['object']}`\n"
|
|
)
|
|
|
|
if op["args"]:
|
|
out.write(
|
|
f" - args: `{', '.join(op['args'])}`\n"
|
|
)
|
|
|
|
if op["kwargs"]:
|
|
out.write(" - kwargs:\n")
|
|
|
|
for k, v in op["kwargs"].items():
|
|
out.write(
|
|
f" - {k}: `{v}`\n"
|
|
)
|
|
|
|
out.write("\n")
|
|
|
|
out.write("\n")
|
|
|
|
|
|
def main():
|
|
|
|
REPORTS.mkdir(exist_ok=True)
|
|
|
|
for module in modules():
|
|
|
|
print(module)
|
|
|
|
mod = Module(module)
|
|
|
|
mod.read_data()
|
|
mod.write_data()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |