Path: blob/master/utils/diagrams.py
4918 views
import shutil1from pathlib import Path2from typing import List3from xml.dom import minidom4import os56from labml import monit78HOME = Path('.').absolute()910STYLES = """11.black-stroke {12stroke: #aaa;13}1415rect.black-stroke {16stroke: #444;17}1819.black-fill {20fill: #ddd;21}2223.white-fill {24fill: #333;25}2627.blue-stroke {28stroke: #5b8fab;29}3031.blue-fill {32fill: #356782;33}3435.yellow-stroke {36stroke: #bbab52;37}3839.yellow-fill {40fill: #a7942b;41}4243.grey-stroke {44stroke: #484d5a;45}4647.grey-fill {48fill: #2e323c;49}5051.red-stroke {52stroke: #bb3232;53}5455.red-fill {56fill: #901c1c;57}5859.orange-stroke {60stroke: #a5753f;61}6263.orange-fill {64fill: #82531e;65}6667.purple-stroke {68stroke: #a556a5;69}7071.purple-fill {72fill: #8a308a;73}7475.green-stroke {76stroke: #80cc92;77}7879.green-fill {80fill: #499e5d;81}8283switch foreignObject div div div {84color: #ddd !important;85}8687switch foreignObject div div div span {88color: #ddd !important;89}9091.has-background {92background-color: #1d2127 !important;93}94"""9596STROKES = {97'#000000': 'black',98'#6c8ebf': 'blue',99'#d6b656': 'yellow',100'#666666': 'grey',101'#b85450': 'red',102'#d79b00': 'orange',103'#9673a6': 'purple',104'#82b366': 'green',105}106107FILLS = {108'#000000': 'black',109'#ffffff': 'white',110'#dae8fc': 'blue',111'#fff2cc': 'yellow',112'#f5f5f5': 'grey',113'#f8cecc': 'red',114'#ffe6cc': 'orange',115'#e1d5e7': 'purple',116'#d5e8d4': 'green',117}118119120def clear_switches(doc: minidom.Document):121switches = doc.getElementsByTagName('switch')122for s in switches:123children = s.childNodes124assert len(children) == 2125if children[0].tagName == 'g' and 'requiredFeatures' in children[0].attributes:126s.parentNode.removeChild(s)127s.unlink()128continue129assert children[0].tagName == 'foreignObject'130assert children[1].tagName == 'text'131c = children[1]132s.removeChild(c)133s.parentNode.insertBefore(c, s)134s.parentNode.removeChild(s)135136137def add_class(node: minidom.Node, class_name: str):138if 'class' not in node.attributes:139node.attributes['class'] = class_name140return141142node.attributes['class'] = node.attributes['class'].value + f' {class_name}'143144145def add_bg_classes(nodes: List[minidom.Node]):146for node in nodes:147if 'style' in node.attributes:148s = node.attributes['style'].value149if s.count('background-color'):150add_class(node, 'has-background')151152153def add_stroke_classes(nodes: List[minidom.Node]):154for node in nodes:155if 'stroke' in node.attributes:156stroke = node.attributes['stroke'].value157if stroke not in STROKES:158continue159160node.removeAttribute('stroke')161add_class(node, f'{STROKES[stroke]}-stroke')162163164def add_fill_classes(nodes: List[minidom.Node]):165for node in nodes:166if 'fill' in node.attributes:167fill = node.attributes['fill'].value168if fill not in FILLS:169continue170171node.removeAttribute('fill')172add_class(node, f'{FILLS[fill]}-fill')173174175def add_classes(doc: minidom.Document):176paths = doc.getElementsByTagName('path')177add_stroke_classes(paths)178add_fill_classes(paths)179180rects = doc.getElementsByTagName('rect')181add_stroke_classes(rects)182add_fill_classes(rects)183184ellipse = doc.getElementsByTagName('ellipse')185add_stroke_classes(ellipse)186add_fill_classes(ellipse)187188text = doc.getElementsByTagName('text')189add_fill_classes(text)190191div = doc.getElementsByTagName('div')192add_bg_classes(div)193194span = doc.getElementsByTagName('span')195add_bg_classes(span)196197198def parse(source: Path, dest: Path):199doc: minidom.Document = minidom.parse(str(source))200201svg = doc.getElementsByTagName('svg')202203assert len(svg) == 1204svg = svg[0]205206if 'content' in svg.attributes:207svg.removeAttribute('content')208# svg.attributes['height'] = str(int(svg.attributes['height'].value[:-2]) + 30) + 'px'209# svg.attributes['width'] = str(int(svg.attributes['width'].value[:-2]) + 30) + 'px'210211view_box = svg.attributes['viewBox'].value.split(' ')212view_box = [float(v) for v in view_box]213view_box[0] -= 10214view_box[1] -= 10215view_box[2] += 20216view_box[3] += 20217svg.attributes['viewBox'] = ' '.join([str(v) for v in view_box])218219svg.attributes['style'] = 'background: #1d2127;' # padding: 10px;'220221# clear_switches(doc)222223style = doc.createElement('style')224style.appendChild(doc.createTextNode(STYLES))225svg.insertBefore(style, svg.childNodes[0])226add_classes(doc)227228with open(str(dest), 'w') as f:229doc.writexml(f)230231232def recurse(path: Path):233files = []234if path.is_file():235files.append(path)236return files237238for f in path.iterdir():239files += recurse(f)240241return files242243244def main():245diagrams_path = HOME / 'diagrams'246docs_path = HOME / 'docs'247248# For first invocation249os.makedirs(diagrams_path, exist_ok=True)250251for p in recurse(diagrams_path):252source_path = p253p = p.relative_to(diagrams_path)254dest_path = docs_path / p255if not dest_path.parent.exists():256dest_path.parent.mkdir(parents=True)257258with monit.section(str(p)):259if source_path.suffix == '.svg':260parse(source_path, dest_path)261else:262shutil.copy(str(source_path), str(dest_path))263264265if __name__ == '__main__':266main()267268269