summaryrefslogtreecommitdiff
path: root/projgraph
diff options
context:
space:
mode:
Diffstat (limited to 'projgraph')
-rwxr-xr-xprojgraph96
1 files changed, 96 insertions, 0 deletions
diff --git a/projgraph b/projgraph
new file mode 100755
index 0000000..c3f5757
--- /dev/null
+++ b/projgraph
@@ -0,0 +1,96 @@
+#!/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('}')