Created
August 5, 2024 06:14
-
-
Save rrbutani/905c099b402e7020dc18c220633f8429 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env nix-shell | |
#!nix-shell -p python3 -i python3 | |
# in its graphviz output (i.e. `ninja -t graph`), ninja uses memory addresses | |
# for node identifiers as an easy way to guarantee that they are unique | |
# | |
# for tools (i.e. dot-viewer: https://github.com/rrbutani/dot-viewer) that rely | |
# on human-readable node ids this is... annoying | |
# | |
# this hacky script (tightly coupled to ninja's graphviz output style; doesn't | |
# attempt to actually parse graphviz) rewrites nodes that have a unique label | |
# to use that label as their id | |
from collections import defaultdict | |
import sys | |
from typing import Optional | |
label_map: defaultdict[str, set[str]] = defaultdict(set) # label -> [ids] | |
lines: list[str] = [] | |
for line in sys.stdin: | |
line = line.rstrip() | |
lines.append(line) | |
if ' [label="' in line: | |
id, rest = line.split(' [label="', maxsplit=1) | |
label = rest.split('"')[0] | |
label_map[label].add(id) | |
ids_to_replace: dict[str, Optional[str]] = dict() # id -> label | |
for label, ids in label_map.items(): | |
if len(ids) == 1: | |
id = ids.pop() | |
# if an id had multiple labels (shouldn't be possible...) bail and don't | |
# replace it. | |
if id in ids_to_replace: | |
first = ids_to_replace[id] or "see above" | |
print(f"warning: {id} has multiple labels: {first}, {label}", file=sys.stderr) | |
ids_to_replace[id] = None | |
ids_to_replace[id] = label | |
replacing = len([() for l in ids_to_replace.values() if l]) | |
print(f"replacing {replacing} id(s) with labels", file=sys.stderr) | |
print("", file=sys.stderr) | |
def try_replace(id: str) -> str: | |
if id in ids_to_replace and (label := ids_to_replace[id]): | |
print('\x1b[1A', '\x1b[2K', id, "->", label, file=sys.stderr) | |
return f'"{label}"' | |
else: | |
return id | |
for line in lines: | |
if line.startswith('"0x'): | |
if '" -> "' in line: # edge | |
src, rest = line.split(' -> ', maxsplit=1) | |
dest, *attrs = rest.split(" ", maxsplit=1) | |
print(f"{try_replace(src)} -> {try_replace(dest)}" + (" " + attrs[0] if attrs else "")) | |
elif '" [' in line: # node | |
id, attrs = line.split(" ", maxsplit=1) | |
print(f"{try_replace(id)} {attrs}") | |
else: | |
print(f"warn: don't know how to handle: {line}\n", file=sys.stderr) | |
print(line) | |
else: | |
print(line) | |
print('\x1b[1A', '\x1b[2K', file=sys.stderr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment