Mercurial > public > mercurial-scm > hg
comparison mercurial/graphmod.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 264a2cbb25d0 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
35 # point. A number prefix means only the last N characters of the current block | 35 # point. A number prefix means only the last N characters of the current block |
36 # will use that style, the rest will use the PARENT style. Add a - sign | 36 # will use that style, the rest will use the PARENT style. Add a - sign |
37 # (so making N negative) and all but the first N characters use that style. | 37 # (so making N negative) and all but the first N characters use that style. |
38 EDGES = {PARENT: '|', GRANDPARENT: ':', MISSINGPARENT: None} | 38 EDGES = {PARENT: '|', GRANDPARENT: ':', MISSINGPARENT: None} |
39 | 39 |
40 | |
40 def dagwalker(repo, revs): | 41 def dagwalker(repo, revs): |
41 """cset DAG generator yielding (id, CHANGESET, ctx, [parentinfo]) tuples | 42 """cset DAG generator yielding (id, CHANGESET, ctx, [parentinfo]) tuples |
42 | 43 |
43 This generator function walks through revisions (which should be ordered | 44 This generator function walks through revisions (which should be ordered |
44 from bigger to lower). It returns a tuple for each node. | 45 from bigger to lower). It returns a tuple for each node. |
55 ctx = repo[rev] | 56 ctx = repo[rev] |
56 # partition into parents in the rev set and missing parents, then | 57 # partition into parents in the rev set and missing parents, then |
57 # augment the lists with markers, to inform graph drawing code about | 58 # augment the lists with markers, to inform graph drawing code about |
58 # what kind of edge to draw between nodes. | 59 # what kind of edge to draw between nodes. |
59 pset = set(p.rev() for p in ctx.parents() if p.rev() in revs) | 60 pset = set(p.rev() for p in ctx.parents() if p.rev() in revs) |
60 mpars = [p.rev() for p in ctx.parents() | 61 mpars = [ |
61 if p.rev() != nullrev and p.rev() not in pset] | 62 p.rev() |
63 for p in ctx.parents() | |
64 if p.rev() != nullrev and p.rev() not in pset | |
65 ] | |
62 parents = [(PARENT, p) for p in sorted(pset)] | 66 parents = [(PARENT, p) for p in sorted(pset)] |
63 | 67 |
64 for mpar in mpars: | 68 for mpar in mpars: |
65 gp = gpcache.get(mpar) | 69 gp = gpcache.get(mpar) |
66 if gp is None: | 70 if gp is None: |
67 # precompute slow query as we know reachableroots() goes | 71 # precompute slow query as we know reachableroots() goes |
68 # through all revs (issue4782) | 72 # through all revs (issue4782) |
69 if not isinstance(revs, smartset.baseset): | 73 if not isinstance(revs, smartset.baseset): |
70 revs = smartset.baseset(revs) | 74 revs = smartset.baseset(revs) |
71 gp = gpcache[mpar] = sorted(set(dagop.reachableroots( | 75 gp = gpcache[mpar] = sorted( |
72 repo, revs, [mpar]))) | 76 set(dagop.reachableroots(repo, revs, [mpar])) |
77 ) | |
73 if not gp: | 78 if not gp: |
74 parents.append((MISSINGPARENT, mpar)) | 79 parents.append((MISSINGPARENT, mpar)) |
75 pset.add(mpar) | 80 pset.add(mpar) |
76 else: | 81 else: |
77 parents.extend((GRANDPARENT, g) for g in gp if g not in pset) | 82 parents.extend((GRANDPARENT, g) for g in gp if g not in pset) |
78 pset.update(gp) | 83 pset.update(gp) |
79 | 84 |
80 yield (ctx.rev(), CHANGESET, ctx, parents) | 85 yield (ctx.rev(), CHANGESET, ctx, parents) |
81 | 86 |
87 | |
82 def nodes(repo, nodes): | 88 def nodes(repo, nodes): |
83 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples | 89 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples |
84 | 90 |
85 This generator function walks the given nodes. It only returns parents | 91 This generator function walks the given nodes. It only returns parents |
86 that are in nodes, too. | 92 that are in nodes, too. |
87 """ | 93 """ |
88 include = set(nodes) | 94 include = set(nodes) |
89 for node in nodes: | 95 for node in nodes: |
90 ctx = repo[node] | 96 ctx = repo[node] |
91 parents = set((PARENT, p.rev()) for p in ctx.parents() | 97 parents = set( |
92 if p.node() in include) | 98 (PARENT, p.rev()) for p in ctx.parents() if p.node() in include |
99 ) | |
93 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) | 100 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) |
101 | |
94 | 102 |
95 def colored(dag, repo): | 103 def colored(dag, repo): |
96 """annotates a DAG with colored edge information | 104 """annotates a DAG with colored edge information |
97 | 105 |
98 For each DAG node this function emits tuples:: | 106 For each DAG node this function emits tuples:: |
119 elif setting == "color" and val.isalnum(): | 127 elif setting == "color" and val.isalnum(): |
120 config.setdefault(branch, {})[setting] = val | 128 config.setdefault(branch, {})[setting] = val |
121 | 129 |
122 if config: | 130 if config: |
123 getconf = util.lrucachefunc( | 131 getconf = util.lrucachefunc( |
124 lambda rev: config.get(repo[rev].branch(), {})) | 132 lambda rev: config.get(repo[rev].branch(), {}) |
133 ) | |
125 else: | 134 else: |
126 getconf = lambda rev: {} | 135 getconf = lambda rev: {} |
127 | 136 |
128 for (cur, type, data, parents) in dag: | 137 for (cur, type, data, parents) in dag: |
129 | 138 |
130 # Compute seen and next | 139 # Compute seen and next |
131 if cur not in seen: | 140 if cur not in seen: |
132 seen.append(cur) # new head | 141 seen.append(cur) # new head |
133 colors[cur] = newcolor | 142 colors[cur] = newcolor |
134 newcolor += 1 | 143 newcolor += 1 |
135 | 144 |
136 col = seen.index(cur) | 145 col = seen.index(cur) |
137 color = colors.pop(cur) | 146 color = colors.pop(cur) |
138 next = seen[:] | 147 next = seen[:] |
139 | 148 |
140 # Add parents to next | 149 # Add parents to next |
141 addparents = [p for pt, p in parents if p not in next] | 150 addparents = [p for pt, p in parents if p not in next] |
142 next[col:col + 1] = addparents | 151 next[col : col + 1] = addparents |
143 | 152 |
144 # Set colors for the parents | 153 # Set colors for the parents |
145 for i, p in enumerate(addparents): | 154 for i, p in enumerate(addparents): |
146 if not i: | 155 if not i: |
147 colors[p] = color | 156 colors[p] = color |
152 # Add edges to the graph | 161 # Add edges to the graph |
153 edges = [] | 162 edges = [] |
154 for ecol, eid in enumerate(seen): | 163 for ecol, eid in enumerate(seen): |
155 if eid in next: | 164 if eid in next: |
156 bconf = getconf(eid) | 165 bconf = getconf(eid) |
157 edges.append(( | 166 edges.append( |
158 ecol, next.index(eid), colors[eid], | 167 ( |
159 bconf.get('width', -1), | 168 ecol, |
160 bconf.get('color', ''))) | 169 next.index(eid), |
170 colors[eid], | |
171 bconf.get('width', -1), | |
172 bconf.get('color', ''), | |
173 ) | |
174 ) | |
161 elif eid == cur: | 175 elif eid == cur: |
162 for ptype, p in parents: | 176 for ptype, p in parents: |
163 bconf = getconf(p) | 177 bconf = getconf(p) |
164 edges.append(( | 178 edges.append( |
165 ecol, next.index(p), color, | 179 ( |
166 bconf.get('width', -1), | 180 ecol, |
167 bconf.get('color', ''))) | 181 next.index(p), |
182 color, | |
183 bconf.get('width', -1), | |
184 bconf.get('color', ''), | |
185 ) | |
186 ) | |
168 | 187 |
169 # Yield and move on | 188 # Yield and move on |
170 yield (cur, type, data, (col, color), edges) | 189 yield (cur, type, data, (col, color), edges) |
171 seen = next | 190 seen = next |
191 | |
172 | 192 |
173 def asciiedges(type, char, state, rev, parents): | 193 def asciiedges(type, char, state, rev, parents): |
174 """adds edge info to changelog DAG walk suitable for ascii()""" | 194 """adds edge info to changelog DAG walk suitable for ascii()""" |
175 seen = state['seen'] | 195 seen = state['seen'] |
176 if rev not in seen: | 196 if rev not in seen: |
190 state['edges'][parent] = state['styles'].get(ptype, '|') | 210 state['edges'][parent] = state['styles'].get(ptype, '|') |
191 | 211 |
192 ncols = len(seen) | 212 ncols = len(seen) |
193 width = 1 + ncols * 2 | 213 width = 1 + ncols * 2 |
194 nextseen = seen[:] | 214 nextseen = seen[:] |
195 nextseen[nodeidx:nodeidx + 1] = newparents | 215 nextseen[nodeidx : nodeidx + 1] = newparents |
196 edges = [(nodeidx, nextseen.index(p)) for p in knownparents] | 216 edges = [(nodeidx, nextseen.index(p)) for p in knownparents] |
197 | 217 |
198 seen[:] = nextseen | 218 seen[:] = nextseen |
199 while len(newparents) > 2: | 219 while len(newparents) > 2: |
200 # ascii() only knows how to add or remove a single column between two | 220 # ascii() only knows how to add or remove a single column between two |
221 width += 2 | 241 width += 2 |
222 # remove current node from edge characters, no longer needed | 242 # remove current node from edge characters, no longer needed |
223 state['edges'].pop(rev, None) | 243 state['edges'].pop(rev, None) |
224 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) | 244 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) |
225 | 245 |
246 | |
226 def _fixlongrightedges(edges): | 247 def _fixlongrightedges(edges): |
227 for (i, (start, end)) in enumerate(edges): | 248 for (i, (start, end)) in enumerate(edges): |
228 if end > start: | 249 if end > start: |
229 edges[i] = (start, end + 1) | 250 edges[i] = (start, end + 1) |
230 | 251 |
231 def _getnodelineedgestail( | 252 |
232 echars, idx, pidx, ncols, coldiff, pdiff, fix_tail): | 253 def _getnodelineedgestail(echars, idx, pidx, ncols, coldiff, pdiff, fix_tail): |
233 if fix_tail and coldiff == pdiff and coldiff != 0: | 254 if fix_tail and coldiff == pdiff and coldiff != 0: |
234 # Still going in the same non-vertical direction. | 255 # Still going in the same non-vertical direction. |
235 if coldiff == -1: | 256 if coldiff == -1: |
236 start = max(idx + 1, pidx) | 257 start = max(idx + 1, pidx) |
237 tail = echars[idx * 2:(start - 1) * 2] | 258 tail = echars[idx * 2 : (start - 1) * 2] |
238 tail.extend(["/", " "] * (ncols - start)) | 259 tail.extend(["/", " "] * (ncols - start)) |
239 return tail | 260 return tail |
240 else: | 261 else: |
241 return ["\\", " "] * (ncols - idx - 1) | 262 return ["\\", " "] * (ncols - idx - 1) |
242 else: | 263 else: |
243 remainder = (ncols - idx - 1) | 264 remainder = ncols - idx - 1 |
244 return echars[-(remainder * 2):] if remainder > 0 else [] | 265 return echars[-(remainder * 2) :] if remainder > 0 else [] |
266 | |
245 | 267 |
246 def _drawedges(echars, edges, nodeline, interline): | 268 def _drawedges(echars, edges, nodeline, interline): |
247 for (start, end) in edges: | 269 for (start, end) in edges: |
248 if start == end + 1: | 270 if start == end + 1: |
249 interline[2 * end + 1] = "/" | 271 interline[2 * end + 1] = "/" |
259 (start, end) = (end, start) | 281 (start, end) = (end, start) |
260 for i in range(2 * start + 1, 2 * end): | 282 for i in range(2 * start + 1, 2 * end): |
261 if nodeline[i] != "+": | 283 if nodeline[i] != "+": |
262 nodeline[i] = "-" | 284 nodeline[i] = "-" |
263 | 285 |
286 | |
264 def _getpaddingline(echars, idx, ncols, edges): | 287 def _getpaddingline(echars, idx, ncols, edges): |
265 # all edges up to the current node | 288 # all edges up to the current node |
266 line = echars[:idx * 2] | 289 line = echars[: idx * 2] |
267 # an edge for the current node, if there is one | 290 # an edge for the current node, if there is one |
268 if (idx, idx - 1) in edges or (idx, idx) in edges: | 291 if (idx, idx - 1) in edges or (idx, idx) in edges: |
269 # (idx, idx - 1) (idx, idx) | 292 # (idx, idx - 1) (idx, idx) |
270 # | | | | | | | | | 293 # | | | | | | | | |
271 # +---o | | o---+ | 294 # +---o | | o---+ |
272 # | | X | | X | | | 295 # | | X | | X | | |
273 # | |/ / | |/ / | 296 # | |/ / | |/ / |
274 # | | | | | | | 297 # | | | | | | |
275 line.extend(echars[idx * 2:(idx + 1) * 2]) | 298 line.extend(echars[idx * 2 : (idx + 1) * 2]) |
276 else: | 299 else: |
277 line.extend([' ', ' ']) | 300 line.extend([' ', ' ']) |
278 # all edges to the right of the current node | 301 # all edges to the right of the current node |
279 remainder = ncols - idx - 1 | 302 remainder = ncols - idx - 1 |
280 if remainder > 0: | 303 if remainder > 0: |
281 line.extend(echars[-(remainder * 2):]) | 304 line.extend(echars[-(remainder * 2) :]) |
282 return line | 305 return line |
306 | |
283 | 307 |
284 def _drawendinglines(lines, extra, edgemap, seen, state): | 308 def _drawendinglines(lines, extra, edgemap, seen, state): |
285 """Draw ending lines for missing parent edges | 309 """Draw ending lines for missing parent edges |
286 | 310 |
287 None indicates an edge that ends at between this node and the next | 311 None indicates an edge that ends at between this node and the next |
330 remove = [p for p, c in edgemap.items() if c is None] | 354 remove = [p for p, c in edgemap.items() if c is None] |
331 for parent in remove: | 355 for parent in remove: |
332 del edgemap[parent] | 356 del edgemap[parent] |
333 seen.remove(parent) | 357 seen.remove(parent) |
334 | 358 |
359 | |
335 def asciistate(): | 360 def asciistate(): |
336 """returns the initial value for the "state" argument to ascii()""" | 361 """returns the initial value for the "state" argument to ascii()""" |
337 return { | 362 return { |
338 'seen': [], | 363 'seen': [], |
339 'edges': {}, | 364 'edges': {}, |
341 'lastindex': 0, | 366 'lastindex': 0, |
342 'styles': EDGES.copy(), | 367 'styles': EDGES.copy(), |
343 'graphshorten': False, | 368 'graphshorten': False, |
344 } | 369 } |
345 | 370 |
371 | |
346 def outputgraph(ui, graph): | 372 def outputgraph(ui, graph): |
347 """outputs an ASCII graph of a DAG | 373 """outputs an ASCII graph of a DAG |
348 | 374 |
349 this is a helper function for 'ascii' below. | 375 this is a helper function for 'ascii' below. |
350 | 376 |
356 this function can be monkey-patched by extensions to alter graph display | 382 this function can be monkey-patched by extensions to alter graph display |
357 without needing to mimic all of the edge-fixup logic in ascii() | 383 without needing to mimic all of the edge-fixup logic in ascii() |
358 """ | 384 """ |
359 for (ln, logstr) in graph: | 385 for (ln, logstr) in graph: |
360 ui.write((ln + logstr).rstrip() + "\n") | 386 ui.write((ln + logstr).rstrip() + "\n") |
387 | |
361 | 388 |
362 def ascii(ui, state, type, char, text, coldata): | 389 def ascii(ui, state, type, char, text, coldata): |
363 """prints an ASCII graph of the DAG | 390 """prints an ASCII graph of the DAG |
364 | 391 |
365 takes the following arguments (one call per node in the graph): | 392 takes the following arguments (one call per node in the graph): |
402 # | | | | | | | | | 429 # | | | | | | | | |
403 # | o---+ into | o---+ | 430 # | o---+ into | o---+ |
404 # | / / | | | # <--- padding line | 431 # | / / | | | # <--- padding line |
405 # o | | | / / | 432 # o | | | / / |
406 # o | | | 433 # o | | |
407 add_padding_line = (len(text) > 2 and coldiff == -1 and | 434 add_padding_line = ( |
408 [x for (x, y) in edges if x + 1 < y]) | 435 len(text) > 2 and coldiff == -1 and [x for (x, y) in edges if x + 1 < y] |
436 ) | |
409 | 437 |
410 # fix_nodeline_tail says whether to rewrite | 438 # fix_nodeline_tail says whether to rewrite |
411 # | 439 # |
412 # | | o | | | | o | | | 440 # | | o | | | | o | | |
413 # | | |/ / | | |/ / | 441 # | | |/ / | | |/ / |
415 # | |/ / | |/ / | 443 # | |/ / | |/ / |
416 # o | | o | | | 444 # o | | o | | |
417 fix_nodeline_tail = len(text) <= 2 and not add_padding_line | 445 fix_nodeline_tail = len(text) <= 2 and not add_padding_line |
418 | 446 |
419 # nodeline is the line containing the node character (typically o) | 447 # nodeline is the line containing the node character (typically o) |
420 nodeline = echars[:idx * 2] | 448 nodeline = echars[: idx * 2] |
421 nodeline.extend([char, " "]) | 449 nodeline.extend([char, " "]) |
422 | 450 |
423 nodeline.extend( | 451 nodeline.extend( |
424 _getnodelineedgestail( | 452 _getnodelineedgestail( |
425 echars, idx, state['lastindex'], ncols, coldiff, | 453 echars, |
426 state['lastcoldiff'], fix_nodeline_tail)) | 454 idx, |
455 state['lastindex'], | |
456 ncols, | |
457 coldiff, | |
458 state['lastcoldiff'], | |
459 fix_nodeline_tail, | |
460 ) | |
461 ) | |
427 | 462 |
428 # shift_interline is the line containing the non-vertical | 463 # shift_interline is the line containing the non-vertical |
429 # edges between this entry and the next | 464 # edges between this entry and the next |
430 shift_interline = echars[:idx * 2] | 465 shift_interline = echars[: idx * 2] |
431 for i in pycompat.xrange(2 + coldiff): | 466 for i in pycompat.xrange(2 + coldiff): |
432 shift_interline.append(' ') | 467 shift_interline.append(' ') |
433 count = ncols - idx - 1 | 468 count = ncols - idx - 1 |
434 if coldiff == -1: | 469 if coldiff == -1: |
435 for i in pycompat.xrange(count): | 470 for i in pycompat.xrange(count): |
436 shift_interline.extend(['/', ' ']) | 471 shift_interline.extend(['/', ' ']) |
437 elif coldiff == 0: | 472 elif coldiff == 0: |
438 shift_interline.extend(echars[(idx + 1) * 2:ncols * 2]) | 473 shift_interline.extend(echars[(idx + 1) * 2 : ncols * 2]) |
439 else: | 474 else: |
440 for i in pycompat.xrange(count): | 475 for i in pycompat.xrange(count): |
441 shift_interline.extend(['\\', ' ']) | 476 shift_interline.extend(['\\', ' ']) |
442 | 477 |
443 # draw edges from the current node to its parents | 478 # draw edges from the current node to its parents |
457 else: | 492 else: |
458 lines.append(shift_interline) | 493 lines.append(shift_interline) |
459 | 494 |
460 # make sure that there are as many graph lines as there are | 495 # make sure that there are as many graph lines as there are |
461 # log strings | 496 # log strings |
462 extra_interline = echars[:(ncols + coldiff) * 2] | 497 extra_interline = echars[: (ncols + coldiff) * 2] |
463 if len(lines) < len(text): | 498 if len(lines) < len(text): |
464 while len(lines) < len(text): | 499 while len(lines) < len(text): |
465 lines.append(extra_interline[:]) | 500 lines.append(extra_interline[:]) |
466 | 501 |
467 _drawendinglines(lines, extra_interline, edgemap, seen, state) | 502 _drawendinglines(lines, extra_interline, edgemap, seen, state) |