Skip to content

Instantly share code, notes, and snippets.

@rrbutani
Created August 5, 2024 06:14
Show Gist options
  • Save rrbutani/905c099b402e7020dc18c220633f8429 to your computer and use it in GitHub Desktop.
Save rrbutani/905c099b402e7020dc18c220633f8429 to your computer and use it in GitHub Desktop.
#!/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