#!/usr/bin/python3 import sys import yaml unknown = 0 blocked = 1 finished = 2 ready = 3 next = 4 statuses = { 'blocked': blocked, 'finished': finished, 'ready': ready, 'next': next, } def nodeattrs(done): attrs = { unknown: {'shape': 'diamond'}, blocked: {'color': '#777777', 'shape': 'rectangle'}, finished: {'color': '#eeeeee'}, ready: {'color': '#bbbbbb'}, next: {'color': '#00cc00'}, } a = dict(attrs[done]) if 'style' not in a: a['style'] = 'filled' return ' '.join('{}="{}"'.format(key, a[key]) for key in a) def find_unknown(tasklist): return [t for t in tasklist if t['status'] == unknown] def all_deps(tasks, task, status): for dep_name in task.get('depends', []): dep = tasks[dep_name] if dep['status'] != status: return False return True def any_dep(tasks, task, status): for dep_name in task.get('depends', []): dep = tasks[dep_name] if dep['status'] == status: return True return False def set_status(tasks): tasklist = list(tasks.values()) for task in tasklist: if 'status' not in task: task['status'] = unknown else: task['status'] = statuses[task['status']] unknown_tasks = find_unknown(tasklist) while unknown_tasks: for t in unknown_tasks: if not t.get('depends', []): t['status'] = ready else: if all_deps(tasks, t, finished): t['status'] = ready else: t['status'] = blocked unknown_tasks = find_unknown(tasklist) obj = yaml.safe_load(sys.stdin) ikiwiki = sys.argv[1:] == ['ikiwiki'] if ikiwiki: print('[[!graph src="""') else: print('digraph "project" {') tasks = obj['tasks'] set_status(tasks) for name, task in tasks.items(): print('{} [label="{}"]'.format(name, task['label'])) status = task['status'] print('{} [{}]'.format(name, nodeattrs(status))) for dep in task.get('depends', []): print('{} -> {}'.format(name, dep)) if ikiwiki: print('"""]]') else: print('}')