1 # HG changeset patch 2 # User Paul Boddie <paul@boddie.org.uk> 3 # Date 1337531723 -7200 4 # Node ID 9488fd4c05876377ad4e3b2ca4c60713d20bf917 5 # Parent d7c9976b930e1fdbf8608a65462cd124977c7d53 6 hgweb: make graph data suitable for template usage 7 8 Previously, graph data has been encoded for processing done by 9 JavaScript code run in the browser, employing simple structures 10 with implicit member positions. This patch modifies the graph 11 command to also produce data employing a dictionary-based 12 structure suitable for use with the templating mechanism, thus 13 permitting other ways of presenting repository graphs using that 14 mechanism. 15 16 In order to test these changes, the raw theme has been modified 17 to include templates for graph nodes and edges. In a similar 18 fashion, themes could employ technologies such as SVG that lend 19 themselves to templating to produce the graph display. This patch 20 makes use of a much simpler output representation than SVG in 21 order to maintain clarity. 22 23 diff -r d7c9976b930e -r 9488fd4c0587 mercurial/hgweb/webcommands.py 24 --- a/mercurial/hgweb/webcommands.py Wed May 02 13:20:06 2012 +0200 25 +++ b/mercurial/hgweb/webcommands.py Sun May 20 18:35:23 2012 +0200 26 @@ -783,24 +783,69 @@ 27 28 dag = graphmod.dagwalker(web.repo, range(startrev, downrev - 1, -1)) 29 tree = list(graphmod.colored(dag, web.repo)) 30 - canvasheight = (len(tree) + 1) * bg_height - 27 31 - data = [] 32 - for (id, type, ctx, vtx, edges) in tree: 33 - if type != graphmod.CHANGESET: 34 - continue 35 - node = str(ctx) 36 - age = templatefilters.age(ctx.date()) 37 - desc = templatefilters.firstline(ctx.description()) 38 - desc = cgi.escape(templatefilters.nonempty(desc)) 39 - user = cgi.escape(templatefilters.person(ctx.user())) 40 - branch = ctx.branch() 41 - branch = branch, web.repo.branchtags().get(branch) == ctx.node() 42 - data.append((node, vtx, edges, desc, user, age, branch, ctx.tags(), 43 - ctx.bookmarks())) 44 + 45 + def getcolumns(tree): 46 + cols = 0 47 + for (id, type, ctx, vtx, edges) in tree: 48 + if type != graphmod.CHANGESET: 49 + continue 50 + cols = max(cols, max([edge[0] for edge in edges] or [0]), 51 + max([edge[1] for edge in edges] or [0])) 52 + return cols 53 + 54 + def graphdata(usetuples, **map): 55 + data = [] 56 + 57 + row = 0 58 + for (id, type, ctx, vtx, edges) in tree: 59 + if type != graphmod.CHANGESET: 60 + continue 61 + node = str(ctx) 62 + age = templatefilters.age(ctx.date()) 63 + desc = templatefilters.firstline(ctx.description()) 64 + desc = cgi.escape(templatefilters.nonempty(desc)) 65 + user = cgi.escape(templatefilters.person(ctx.user())) 66 + branch = ctx.branch() 67 + branch = branch, web.repo.branchtags().get(branch) == ctx.node() 68 + 69 + if usetuples: 70 + data.append((node, vtx, edges, desc, user, age, branch, ctx.tags(), 71 + ctx.bookmarks())) 72 + else: 73 + edgedata = [dict(col=edge[0], nextcol=edge[1], 74 + color=(edge[2] - 1) % 6 + 1, 75 + width=edge[3], bcolor=edge[4]) for edge in edges] 76 + 77 + data.append(dict(node=node, 78 + col=vtx[0], 79 + color=(vtx[1] - 1) % 6 + 1, 80 + edges=edgedata, 81 + row=row, 82 + nextrow=row+1, 83 + desc=desc, 84 + user=user, 85 + age=age, 86 + bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()), 87 + branches=webutil.nodebranchdict(web.repo, ctx), 88 + inbranch=webutil.nodeinbranch(web.repo, ctx), 89 + tags=webutil.nodetagsdict(web.repo, ctx.node()))) 90 + 91 + row += 1 92 + 93 + return data 94 + 95 + cols = getcolumns(tree) 96 + rows = len(tree) 97 + canvasheight = (rows + 1) * bg_height - 27 98 99 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev, 100 lessvars=lessvars, morevars=morevars, downrev=downrev, 101 - canvasheight=canvasheight, jsdata=data, bg_height=bg_height, 102 + cols=cols, rows=rows, 103 + canvaswidth=(cols+1)*bg_height, 104 + truecanvasheight=rows*bg_height, 105 + canvasheight=canvasheight, bg_height=bg_height, 106 + jsdata=lambda **x: graphdata(True, **x), 107 + nodes=lambda **x: graphdata(False, **x), 108 node=revnode_hex, changenav=changenav) 109 110 def _getdoc(e): 111 diff -r d7c9976b930e -r 9488fd4c0587 mercurial/templates/raw/map 112 --- a/mercurial/templates/raw/map Wed May 02 13:20:06 2012 +0200 113 +++ b/mercurial/templates/raw/map Sun May 20 18:35:23 2012 +0200 114 @@ -28,3 +28,9 @@ 115 bookmarkentry = '{bookmark} {node}\n' 116 branches = '{entries%branchentry}' 117 branchentry = '{branch} {node} {status}\n' 118 +graph = graph.tmpl 119 +graphnode = graphnode.tmpl 120 +graphedge = graphedge.tmpl 121 +bookmarkname = 'bookmark: {name}\n' 122 +branchname = 'branch: {name}\n' 123 +tagname = 'tag: {name}\n' 124 diff -r d7c9976b930e -r 9488fd4c0587 tests/test-hgweb-commands.t 125 --- a/tests/test-hgweb-commands.t Wed May 02 13:20:06 2012 +0200 126 +++ b/tests/test-hgweb-commands.t Sun May 20 18:35:23 2012 +0200 127 @@ -1038,6 +1038,55 @@ 128 </body> 129 </html> 130 131 +raw graph 132 + 133 + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/?style=raw' 134 + 200 Script output follows 135 + 136 + 137 + # HG graph 138 + # Node ID ba87b23d29ca67a305625d81a20ac279c1e3f444 139 + # Rows shown 4 140 + 141 + changeset: ba87b23d29ca 142 + user: test 143 + date: 1970-01-01 144 + summary: branch 145 + branch: unstable 146 + tag: tip 147 + bookmark: something 148 + 149 + node: (0, 0) (color 1) 150 + edge: (0, 0) -> (0, 1) (color 1) 151 + 152 + changeset: 1d22e65f027e 153 + user: test 154 + date: 1970-01-01 155 + summary: branch 156 + branch: stable 157 + 158 + node: (0, 1) (color 1) 159 + edge: (0, 1) -> (0, 2) (color 1) 160 + 161 + changeset: a4f92ed23982 162 + user: test 163 + date: 1970-01-01 164 + summary: Added tag 1.0 for changeset 2ef0ac749a14 165 + branch: default 166 + 167 + node: (0, 2) (color 1) 168 + edge: (0, 2) -> (0, 3) (color 1) 169 + 170 + changeset: 2ef0ac749a14 171 + user: test 172 + date: 1970-01-01 173 + summary: base 174 + tag: 1.0 175 + bookmark: anotherthing 176 + 177 + node: (0, 3) (color 1) 178 + 179 + 180 181 capabilities 182