| 1 | = Visualizing Django source code changeset dependencies = |
| 2 | |
| 3 | When following the workflow I describe in '''![1]''' to be able to maintain a local copy of Django with selected changes backported from the SVN trunk development evolution to a 0.96 base copy I soon found myself in following situation: |
| 4 | |
| 5 | Certain changeset ''C'' that I'd want to use wasn't being considered by '''![2]'''{{{darcs}}} as a potential candidate so it didn't offer me to apply it. |
| 6 | |
| 7 | Later the cause became evident: The ''C'' changeset wasn't being considered by {{{darcs}}} because I had previously answered "no" when it offered me to apply a (chronologically previous) changeset ''B'' on which ''C'' depends (dependency in this context means both ''B'' and ''C'' modify some overlaping section of some file). |
| 8 | |
| 9 | Given the fact that in {{{darcs}}} patches (changesets, patchsets) are first class citizens, it is easier to track and visualize the dependencies among them by using it together with some related '''![3]'''tools and '''![4]'''{{{GraphViz}}}. |
| 10 | |
| 11 | If we add a couple of ad-hoc scripts and some tips from the experience gained to the mix we can get something like this: |
| 12 | |
| 13 | == Scripts == |
| 14 | |
| 15 | === filter1.sh === |
| 16 | {{{ |
| 17 | #!/bin/sh |
| 18 | |
| 19 | # This filter changes the labels of the nodes of a Graphviz dot |
| 20 | # file as generated by darcs-deps to only consist of the patchset |
| 21 | # number. |
| 22 | # |
| 23 | # It depends on the labels being of the form |
| 24 | # "[tailor-project-name @ changeset-number]" |
| 25 | # |
| 26 | # It needs one command line parameter: The tailor-project-name |
| 27 | # |
| 28 | |
| 29 | if test $# -ne 1; then |
| 30 | echo "Usage:" |
| 31 | echo "$(basename $0) tailor-project-name" |
| 32 | exit 1 |
| 33 | fi |
| 34 | |
| 35 | /bin/sed "s/\[$1 @ \\([0-9]\+\\)\]/\1/g" |
| 36 | }}} |
| 37 | |
| 38 | === filter2.sh === |
| 39 | {{{ |
| 40 | #!/bin/sh |
| 41 | |
| 42 | # This filter modifies the properties of the nodes of a Graphviz dot |
| 43 | # to add a relative "href" property with the same value as the node label. |
| 44 | # |
| 45 | # It depends on the labels being the number of the revision/changeset |
| 46 | # represented by the node (possibly generated by filtering the darcs-deps |
| 47 | # output through filter1.sh). |
| 48 | # |
| 49 | # It has been created to facilitate the navigation of the Django trunk |
| 50 | # changeset dependancy graph, enabling (for the relevant output formats: pdf, |
| 51 | # image maps) the user to click on a node and getting a web browser window |
| 52 | # opened with the Django Trac page showing the corresponding changeset. |
| 53 | # |
| 54 | # For this to work, a graph level property href=http://code.djangoproject.com/changeset/ |
| 55 | # must be also present, it can be added with a -Ghref=... commandline switch |
| 56 | # in the dot(1) invocation. |
| 57 | |
| 58 | if test $# -ne 0; then |
| 59 | echo "Usage:" |
| 60 | echo "$(basename $0)" |
| 61 | exit 1 |
| 62 | fi |
| 63 | |
| 64 | /bin/sed "s#label = \"\\([0-9]\+\\)\"#label = \"\1\", href=\"\1\"#g" |
| 65 | }}} |
| 66 | |
| 67 | == Usage == |
| 68 | |
| 69 | {{{ |
| 70 | ramiro@tabaqui:~/src/django/inmutable $ darcs-deps | filter1.sh django096 | filter2.sh | unflatten | dot -Tps2 -Gsize=50,50 -Ghref=http://code.djangoproject.com/changeset/ -o ~/django-deps.ps -Tpng -o ~/django-deps.png |
| 71 | Examining patch 249 of 249. |
| 72 | |
| 73 | ramiro@tabaqui:~/src/django/inmutable $ cd |
| 74 | |
| 75 | ramiro@tabaqui:~ $ ps2pdf django-deps.ps |
| 76 | }}} |
| 77 | |
| 78 | === Explanation === |
| 79 | |
| 80 | {{{darcs-deps}}} is ran on the {{{inmutable}}} {{{darcs}}} repository (please refer to '''![1]''' to see what that repository is and how to create it), it generates a {{{Graphviz}}} dot language description of the dependancy graph. |
| 81 | |
| 82 | We filter that otput first through our two custom filtering scripts (see above) to change some graph node attributes, and then through {{{unflatten(1)}}} (part of {{{Graphviz}}}) to enhance the layout of the graphic representation. |
| 83 | |
| 84 | And finally we feed the result to {{{dot(1)}}} (also part of {{{Graphviz}}}) to get our final output. In the case |
| 85 | of some output methods (PDF [via Postscript], server and client side image maps) we'll be able to click on the nodes and get our Web browser to go to the Django Trac page associated with the changeset at hand. |
| 86 | |
| 87 | == Example output == |
| 88 | |
| 89 | Status as of [5165] (May 8 2007 3:43 UTC): |
| 90 | |
| 91 | |
| 92 | == References == |
| 93 | |
| 94 | 1. [http://seeonee.homeip.net:81/intdoc/DjangoPost096 Django: My post 0.96 branch] |
| 95 | 2. [http://darcs.net darcs] |
| 96 | 3. [http://scratchbox.org/~ttimonen/repos/darcs-deps/darcs-deps darcs-deps] (darcs repo: http://scratchbox.org/~ttimonen/repos/darcs-deps) |
| 97 | 4. [http://www.graphviz.org/ GraphViz] |
| 98 | 5. [http://www.cs.wisc.edu/~ghost/ Ghostscript] |
| 99 | |
| 100 | == Feedback == |
| 101 | |
| 102 | Please direct all feedback to [mailto:cramm0_at_gmail.com Ramiro Morales]. |