#!/usr/bin/env python3 import os import sys import time from collections import defaultdict from datetime import datetime, timedelta from pprint import pp import plantuml from phabricator import Phabricator p = plantuml.PlantUML(url="http://www.plantuml.com/plantuml/svg/") preamble = """ @startgantt Project starts at 9th of July 2020 saturday are closed sunday are closed """ # 2020-07-27 to 2020-08-2 is closed postamble = """ @endgantt """ def maxi(day): #if 18 > day < 22: # return 0 wday = day % 7 if wday in (0, 4): return 6 if wday in (2, 3): return 1 return 3 pstart = datetime(2020, 7, 9) def inf(n, v): while v: yield n n += 1 def generate_svg(name, text): print(f"generating: {text}") try: res = p.processes(plantuml_text=(text)) except Exception: print(p.get_url(plantuml_text=(text))) return svg = "/tmp/" + name + ".svg" pdf = "/tmp/" + name + ".pdf" open(svg, "wb").write(res) os.system(f"inkscape {svg} -o {pdf}") phab = Phabricator() # This will use your ~/.arcrc file phab.user.whoami() tasks = phab.maniphest.search(queryKey="all") ids = {task["phid"]: task["id"] for task in tasks.data} vertices = {} tree = defaultdict(list) for task in tasks.data: if task["id"] < 5: continue itask = dict(phab.maniphest.info(task_id=task["id"])) for k, v in task.items(): itask[k] = v itask["weight"] = 3**(itask["fields"]["priority"]["value"] / 10) vertices[task["id"]] = itask parents = itask["dependsOnTaskPHIDs"] for parent in parents: if parent in ids: tree[task["id"]].append(ids[parent]) tree = defaultdict(list, { vertices[k]["id"]: [vertices[t]["id"] for t in v] for k, v in tree.items() }) newtree = defaultdict(list) for k, v in tree.items(): for i in v: newtree[i].append(k) print(newtree) diffs = {} diff = phab.differential.query() for d in diff: for line in d["summary"].split("\n"): try: t = int(line.split("T")[-1]) diffs[t] = int(d["dateCreated"]) except: pass weighted = sorted(vertices.keys(), key=lambda t: (-vertices[t]["weight"], t)) dependent = [] for v in vertices: item = None for n, a in enumerate(weighted): if all(i in dependent for i in tree[a]): item = n break if item is None: print("err: o nowes") nr = weighted.pop(item) dependent.append(nr) for i in reversed(dependent): for k in tree[i]: vertices[k]["weight"] += (vertices[i]["weight"] / len(tree[i])) available = sorted(vertices.keys(), key=lambda t: (-vertices[t]["weight"], t)) done = [] sstart = (datetime.now() - pstart).days for k, v in vertices.items(): v["title"] = (" " * 12) + v["title"] v["due"] = sstart + 1 if v["isClosed"]: v["start"] = (datetime.fromtimestamp(int(v["fields"]["dateClosed"])) - pstart).days - 2 if k in diffs: v["start"] = (datetime.fromtimestamp(diffs[k]) - pstart).days else: v["start"] = (datetime.fromtimestamp(int( v["fields"]["dateClosed"])) - pstart).days - 2 v["due"] = (datetime.fromtimestamp(int(v["fields"]["dateClosed"])) - pstart).days done.insert(0, k) available.remove(k) if k in diffs: v["start"] = (datetime.fromtimestamp(diffs[k]) - pstart).days done = sorted(done, key=lambda t: (-vertices[t]["weight"], t)) print(done) inwork = [] for day in inf(sstart, available): newwork = [] for task in inwork: if task["due"] <= day: done.append(task["id"]) else: newwork.append(task) inwork = newwork while available and len(inwork) < maxi(day): item = None for n, a in enumerate(available): if all(i in done for i in tree[a]): item = n break if item is None: print("err: o nowes") nr = available.pop(item) v = vertices[nr] if nr not in diffs: v["start"] = day v["due"] = day + 2 inwork.append(v) midamble = [] def pof(day): if type(day) == datetime: return day else: return pstart + timedelta(days=day) def dof(day): return str(pof(day)).split(" ")[0] def m(n): if n < 0: return str(-n) + " days before " else: return str(n) + " days after " projects = { p["phid"]: p["fields"]["color"]["key"] for p in phab.project.search(queryKey="all")["data"] } def g(v): try: return projects[v["projectPHIDs"][0]] except: return "grey" done = sorted(done, key=lambda t: (vertices[t]["start"], vertices[t]["weight"])) dependent = [] while True: item = None for n, a in enumerate(done): if all(i in dependent for i in tree[a]): item = n break if item is None: break nr = done.pop(item) dependent.append(nr) for k in dependent: v = vertices[k] needings = tuple(map(vertices.__getitem__, tree[k])) midamble.append( f"[{v['title']}] lasts {v['due'] - v['start']} days and is colored in {g(v)} and starts " + (f"on {dof(v['start'])}" if not needings else f"{m(v['start'] - needings[0]['due'] - 1)} [{needings[0]['title']}]'s end" )) # to {dof(v['due'])}") midamble = "\n".join(midamble) amble = f"{preamble}{midamble}{postamble}" generate_svg("out", amble)