Guest User

graphdeps-improved

a guest
Jan 12th, 2013
1,349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.13 KB | None | 0 0
  1. #!/usr/bin/env python
  2. 'graph dependencies in projects'
  3. import json
  4. from subprocess import Popen, PIPE
  5. import sys
  6. import textwrap
  7.  
  8.  
  9.  
  10. # Typical command line usage:
  11. #
  12. # python graphdeps.py TASKFILTER
  13. #
  14. # TASKFILTER is a taskwarrior filter, documentation can be found here: http://taskwarrior.org/projects/taskwarrior/wiki/Feature_filters
  15. #
  16. # Probably the most helpful commands are:
  17. #
  18. # python graphdeps.py project:fooproject status:pending  
  19. #  --> graph pending tasks in project 'fooproject'
  20. #
  21. # python graphdeps.py project:fooproject
  22. #  --> graphs all tasks in 'fooproject', pending, completed, deleted
  23. #
  24. # python graphdeps.py status:pending
  25. #  --> graphs all pending tasks in all projects
  26. #
  27. # python graphdeps.py
  28. #  --> graphs everything - could be massive
  29. #
  30.  
  31.  
  32. #Wrap label text at this number of characters
  33. charsPerLine = 20;
  34.  
  35.  
  36. #full list of colors here: http://www.graphviz.org/doc/info/colors.html
  37. blockedColor = 'gold4'
  38. maxUrgencyColor = 'red2' #color of the tasks that have absolutely the highest urgency
  39. unblockedColor = 'green'
  40. doneColor = 'grey'
  41. waitColor = 'white'
  42. deletedColor = 'pink';
  43.  
  44. #The width of the border around the tasks:
  45. penWidth = 1
  46.  
  47.  
  48.  
  49. #Have one HEADER (and only one) uncommented at a time, or the last uncommented value will be the only one considered
  50.  
  51. #Left to right layout, my favorite, ganntt-ish
  52. HEADER = "digraph  dependencies { splines=true; overlap=ortho; rankdir=LR; weight=2;"
  53.  
  54. #Spread tasks on page
  55. #HEADER = "digraph  dependencies { layout=neato;   splines=true; overlap=scalexy;  rankdir=LR; weight=2;"
  56.  
  57. #More information on setting up graphviz: http://www.graphviz.org/doc/info/attrs.html
  58.  
  59.  
  60. #-----------------------------------------#
  61. #  Editing under this might break things  #
  62. #-----------------------------------------#
  63.  
  64. FOOTER = "}"
  65.  
  66. JSON_START = '['
  67. JSON_END = ']'
  68.  
  69. validUuids = list()
  70.  
  71.  
  72.  
  73. def call_taskwarrior(cmd):
  74.     'call taskwarrior, returning output and error'
  75.     tw = Popen(['task'] + cmd.split(), stdout=PIPE, stderr=PIPE)
  76.     return tw.communicate()
  77.  
  78. def get_json(query):
  79.     'call taskwarrior, returning objects from json'
  80.     result, err = call_taskwarrior('export %s' % query)
  81.     return json.loads(JSON_START + result + JSON_END)
  82.  
  83. def call_dot(instr):
  84.     'call dot, returning stdout and stdout'
  85.     dot = Popen('dot -T png'.split(), stdout=PIPE, stderr=PIPE, stdin=PIPE)
  86.     return dot.communicate(instr)
  87.  
  88. if __name__ == '__main__':
  89.     query = sys.argv[1:]
  90.     print ('Calling TaskWarrior')
  91.     data = get_json(' '.join(query))
  92.     #print data
  93.    
  94.     maxUrgency = -9999;
  95.     for datum in data:
  96.         if float(datum['urgency']) > maxUrgency:
  97.             maxUrgency = float(datum['urgency'])
  98.  
  99.  
  100.     # first pass: labels
  101.     lines = [HEADER]
  102.     print ('Printing Labels')
  103.     for datum in data:
  104.         validUuids.append(datum['uuid'])
  105.         if datum['description']:
  106.  
  107.             style = ''
  108.             color = ''
  109.             style = 'filled'
  110.  
  111.             if datum['status']=='pending':
  112.                 prefix = datum['id']
  113.                 if not datum.get('depends','') : color = unblockedColor
  114.                 else :
  115.                     hasPendingDeps = 0
  116.                     for depend in datum['depends'].split(','):
  117.                         for datum2 in data:
  118.                             if datum2['uuid'] == depend and datum2['status'] == 'pending':
  119.                                hasPendingDeps = 1
  120.                     if hasPendingDeps == 1 : color = blockedColor
  121.                     else : color = unblockedColor
  122.  
  123.             elif datum['status'] == 'waiting':
  124.                 prefix = 'WAIT'
  125.                 color = waitColor
  126.             elif datum['status'] == 'completed':
  127.                 prefix = 'DONE'
  128.                 color = doneColor
  129.             elif datum['status'] == 'deleted':
  130.                 prefix = 'DELETED'
  131.                 color = deletedColor
  132.             else:
  133.                 prefix = ''
  134.                 color = 'white'
  135.  
  136.  
  137.             if float(datum['urgency']) == maxUrgency:
  138.                 color = maxUrgencyColor
  139.  
  140.             label = '';
  141.             descriptionLines = textwrap.wrap(datum['description'],charsPerLine);
  142.             for descLine in descriptionLines:
  143.                 label += descLine+"\\n";
  144.    
  145.             lines.append('"%s"[shape=box][penwidth=%d][label="%s\:%s"][fillcolor=%s][style=%s]' % (datum['uuid'], penWidth, prefix, label, color, style))
  146.             #documentation http://www.graphviz.org/doc/info/attrs.html
  147.  
  148.  
  149.  
  150.     # second pass: dependencies
  151.     print ('Resolving Dependencies')
  152.     for datum in data:
  153.         if datum['description']:
  154.             for dep in datum.get('depends', '').split(','):
  155.                 #print ("\naaa %s" %dep)
  156.                 if dep!='' and dep in validUuids:
  157.                     lines.append('"%s" -> "%s";' % (dep, datum['uuid']))
  158.                     continue
  159.  
  160.     lines.append(FOOTER)
  161.  
  162.     print ('Calling dot')
  163.     png, err = call_dot('\n'.join(lines))
  164.     if err != '':
  165.         print ('Error calling dot:')
  166.         print (err.strip())
  167.  
  168.     print ('Writing to deps.png')
  169.     with open('deps.png', 'w') as f:
  170.         f.write(png)
Advertisement
Add Comment
Please, Sign In to add comment