Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/graphmod.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | faa8a59f4a06 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
25 pycompat, | 25 pycompat, |
26 smartset, | 26 smartset, |
27 util, | 27 util, |
28 ) | 28 ) |
29 | 29 |
30 CHANGESET = 'C' | 30 CHANGESET = b'C' |
31 PARENT = 'P' | 31 PARENT = b'P' |
32 GRANDPARENT = 'G' | 32 GRANDPARENT = b'G' |
33 MISSINGPARENT = 'M' | 33 MISSINGPARENT = b'M' |
34 # Style of line to draw. None signals a line that ends and is removed at this | 34 # Style of line to draw. None signals a line that ends and is removed at this |
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: b'|', GRANDPARENT: b':', MISSINGPARENT: None} |
39 | 39 |
40 | 40 |
41 def dagwalker(repo, revs): | 41 def dagwalker(repo, revs): |
42 """cset DAG generator yielding (id, CHANGESET, ctx, [parentinfo]) tuples | 42 """cset DAG generator yielding (id, CHANGESET, ctx, [parentinfo]) tuples |
43 | 43 |
116 seen = [] | 116 seen = [] |
117 colors = {} | 117 colors = {} |
118 newcolor = 1 | 118 newcolor = 1 |
119 config = {} | 119 config = {} |
120 | 120 |
121 for key, val in repo.ui.configitems('graph'): | 121 for key, val in repo.ui.configitems(b'graph'): |
122 if '.' in key: | 122 if b'.' in key: |
123 branch, setting = key.rsplit('.', 1) | 123 branch, setting = key.rsplit(b'.', 1) |
124 # Validation | 124 # Validation |
125 if setting == "width" and val.isdigit(): | 125 if setting == b"width" and val.isdigit(): |
126 config.setdefault(branch, {})[setting] = int(val) | 126 config.setdefault(branch, {})[setting] = int(val) |
127 elif setting == "color" and val.isalnum(): | 127 elif setting == b"color" and val.isalnum(): |
128 config.setdefault(branch, {})[setting] = val | 128 config.setdefault(branch, {})[setting] = val |
129 | 129 |
130 if config: | 130 if config: |
131 getconf = util.lrucachefunc( | 131 getconf = util.lrucachefunc( |
132 lambda rev: config.get(repo[rev].branch(), {}) | 132 lambda rev: config.get(repo[rev].branch(), {}) |
166 edges.append( | 166 edges.append( |
167 ( | 167 ( |
168 ecol, | 168 ecol, |
169 next.index(eid), | 169 next.index(eid), |
170 colors[eid], | 170 colors[eid], |
171 bconf.get('width', -1), | 171 bconf.get(b'width', -1), |
172 bconf.get('color', ''), | 172 bconf.get(b'color', b''), |
173 ) | 173 ) |
174 ) | 174 ) |
175 elif eid == cur: | 175 elif eid == cur: |
176 for ptype, p in parents: | 176 for ptype, p in parents: |
177 bconf = getconf(p) | 177 bconf = getconf(p) |
178 edges.append( | 178 edges.append( |
179 ( | 179 ( |
180 ecol, | 180 ecol, |
181 next.index(p), | 181 next.index(p), |
182 color, | 182 color, |
183 bconf.get('width', -1), | 183 bconf.get(b'width', -1), |
184 bconf.get('color', ''), | 184 bconf.get(b'color', b''), |
185 ) | 185 ) |
186 ) | 186 ) |
187 | 187 |
188 # Yield and move on | 188 # Yield and move on |
189 yield (cur, type, data, (col, color), edges) | 189 yield (cur, type, data, (col, color), edges) |
190 seen = next | 190 seen = next |
191 | 191 |
192 | 192 |
193 def asciiedges(type, char, state, rev, parents): | 193 def asciiedges(type, char, state, rev, parents): |
194 """adds edge info to changelog DAG walk suitable for ascii()""" | 194 """adds edge info to changelog DAG walk suitable for ascii()""" |
195 seen = state['seen'] | 195 seen = state[b'seen'] |
196 if rev not in seen: | 196 if rev not in seen: |
197 seen.append(rev) | 197 seen.append(rev) |
198 nodeidx = seen.index(rev) | 198 nodeidx = seen.index(rev) |
199 | 199 |
200 knownparents = [] | 200 knownparents = [] |
205 continue | 205 continue |
206 if parent in seen: | 206 if parent in seen: |
207 knownparents.append(parent) | 207 knownparents.append(parent) |
208 else: | 208 else: |
209 newparents.append(parent) | 209 newparents.append(parent) |
210 state['edges'][parent] = state['styles'].get(ptype, '|') | 210 state[b'edges'][parent] = state[b'styles'].get(ptype, b'|') |
211 | 211 |
212 ncols = len(seen) | 212 ncols = len(seen) |
213 width = 1 + ncols * 2 | 213 width = 1 + ncols * 2 |
214 nextseen = seen[:] | 214 nextseen = seen[:] |
215 nextseen[nodeidx : nodeidx + 1] = newparents | 215 nextseen[nodeidx : nodeidx + 1] = newparents |
224 edges.append((nodeidx, nodeidx)) | 224 edges.append((nodeidx, nodeidx)) |
225 edges.append((nodeidx, nodeidx + 1)) | 225 edges.append((nodeidx, nodeidx + 1)) |
226 nmorecols = 1 | 226 nmorecols = 1 |
227 width += 2 | 227 width += 2 |
228 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) | 228 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) |
229 char = '\\' | 229 char = b'\\' |
230 nodeidx += 1 | 230 nodeidx += 1 |
231 ncols += 1 | 231 ncols += 1 |
232 edges = [] | 232 edges = [] |
233 del newparents[0] | 233 del newparents[0] |
234 | 234 |
238 edges.append((nodeidx, nodeidx + 1)) | 238 edges.append((nodeidx, nodeidx + 1)) |
239 nmorecols = len(nextseen) - ncols | 239 nmorecols = len(nextseen) - ncols |
240 if nmorecols > 0: | 240 if nmorecols > 0: |
241 width += 2 | 241 width += 2 |
242 # remove current node from edge characters, no longer needed | 242 # remove current node from edge characters, no longer needed |
243 state['edges'].pop(rev, None) | 243 state[b'edges'].pop(rev, None) |
244 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) | 244 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) |
245 | 245 |
246 | 246 |
247 def _fixlongrightedges(edges): | 247 def _fixlongrightedges(edges): |
248 for (i, (start, end)) in enumerate(edges): | 248 for (i, (start, end)) in enumerate(edges): |
254 if fix_tail and coldiff == pdiff and coldiff != 0: | 254 if fix_tail and coldiff == pdiff and coldiff != 0: |
255 # Still going in the same non-vertical direction. | 255 # Still going in the same non-vertical direction. |
256 if coldiff == -1: | 256 if coldiff == -1: |
257 start = max(idx + 1, pidx) | 257 start = max(idx + 1, pidx) |
258 tail = echars[idx * 2 : (start - 1) * 2] | 258 tail = echars[idx * 2 : (start - 1) * 2] |
259 tail.extend(["/", " "] * (ncols - start)) | 259 tail.extend([b"/", b" "] * (ncols - start)) |
260 return tail | 260 return tail |
261 else: | 261 else: |
262 return ["\\", " "] * (ncols - idx - 1) | 262 return [b"\\", b" "] * (ncols - idx - 1) |
263 else: | 263 else: |
264 remainder = ncols - idx - 1 | 264 remainder = ncols - idx - 1 |
265 return echars[-(remainder * 2) :] if remainder > 0 else [] | 265 return echars[-(remainder * 2) :] if remainder > 0 else [] |
266 | 266 |
267 | 267 |
268 def _drawedges(echars, edges, nodeline, interline): | 268 def _drawedges(echars, edges, nodeline, interline): |
269 for (start, end) in edges: | 269 for (start, end) in edges: |
270 if start == end + 1: | 270 if start == end + 1: |
271 interline[2 * end + 1] = "/" | 271 interline[2 * end + 1] = b"/" |
272 elif start == end - 1: | 272 elif start == end - 1: |
273 interline[2 * start + 1] = "\\" | 273 interline[2 * start + 1] = b"\\" |
274 elif start == end: | 274 elif start == end: |
275 interline[2 * start] = echars[2 * start] | 275 interline[2 * start] = echars[2 * start] |
276 else: | 276 else: |
277 if 2 * end >= len(nodeline): | 277 if 2 * end >= len(nodeline): |
278 continue | 278 continue |
279 nodeline[2 * end] = "+" | 279 nodeline[2 * end] = b"+" |
280 if start > end: | 280 if start > end: |
281 (start, end) = (end, start) | 281 (start, end) = (end, start) |
282 for i in range(2 * start + 1, 2 * end): | 282 for i in range(2 * start + 1, 2 * end): |
283 if nodeline[i] != "+": | 283 if nodeline[i] != b"+": |
284 nodeline[i] = "-" | 284 nodeline[i] = b"-" |
285 | 285 |
286 | 286 |
287 def _getpaddingline(echars, idx, ncols, edges): | 287 def _getpaddingline(echars, idx, ncols, edges): |
288 # all edges up to the current node | 288 # all edges up to the current node |
289 line = echars[: idx * 2] | 289 line = echars[: idx * 2] |
295 # | | X | | X | | | 295 # | | X | | X | | |
296 # | |/ / | |/ / | 296 # | |/ / | |/ / |
297 # | | | | | | | 297 # | | | | | | |
298 line.extend(echars[idx * 2 : (idx + 1) * 2]) | 298 line.extend(echars[idx * 2 : (idx + 1) * 2]) |
299 else: | 299 else: |
300 line.extend([' ', ' ']) | 300 line.extend([b' ', b' ']) |
301 # all edges to the right of the current node | 301 # all edges to the right of the current node |
302 remainder = ncols - idx - 1 | 302 remainder = ncols - idx - 1 |
303 if remainder > 0: | 303 if remainder > 0: |
304 line.extend(echars[-(remainder * 2) :]) | 304 line.extend(echars[-(remainder * 2) :]) |
305 return line | 305 return line |
320 # We need enough space to draw adjustment lines for these. | 320 # We need enough space to draw adjustment lines for these. |
321 edgechars = extra[::2] | 321 edgechars = extra[::2] |
322 while edgechars and edgechars[-1] is None: | 322 while edgechars and edgechars[-1] is None: |
323 edgechars.pop() | 323 edgechars.pop() |
324 shift_size = max((edgechars.count(None) * 2) - 1, 0) | 324 shift_size = max((edgechars.count(None) * 2) - 1, 0) |
325 minlines = 3 if not state['graphshorten'] else 2 | 325 minlines = 3 if not state[b'graphshorten'] else 2 |
326 while len(lines) < minlines + shift_size: | 326 while len(lines) < minlines + shift_size: |
327 lines.append(extra[:]) | 327 lines.append(extra[:]) |
328 | 328 |
329 if shift_size: | 329 if shift_size: |
330 empties = [] | 330 empties = [] |
336 else: | 336 else: |
337 toshift.append(i * 2) | 337 toshift.append(i * 2) |
338 targets = list(range(first_empty, first_empty + len(toshift) * 2, 2)) | 338 targets = list(range(first_empty, first_empty + len(toshift) * 2, 2)) |
339 positions = toshift[:] | 339 positions = toshift[:] |
340 for line in lines[-shift_size:]: | 340 for line in lines[-shift_size:]: |
341 line[first_empty:] = [' '] * (len(line) - first_empty) | 341 line[first_empty:] = [b' '] * (len(line) - first_empty) |
342 for i in range(len(positions)): | 342 for i in range(len(positions)): |
343 pos = positions[i] - 1 | 343 pos = positions[i] - 1 |
344 positions[i] = max(pos, targets[i]) | 344 positions[i] = max(pos, targets[i]) |
345 line[pos] = '/' if pos > targets[i] else extra[toshift[i]] | 345 line[pos] = b'/' if pos > targets[i] else extra[toshift[i]] |
346 | 346 |
347 map = {1: '|', 2: '~'} if not state['graphshorten'] else {1: '~'} | 347 map = {1: b'|', 2: b'~'} if not state[b'graphshorten'] else {1: b'~'} |
348 for i, line in enumerate(lines): | 348 for i, line in enumerate(lines): |
349 if None not in line: | 349 if None not in line: |
350 continue | 350 continue |
351 line[:] = [c or map.get(i, ' ') for c in line] | 351 line[:] = [c or map.get(i, b' ') for c in line] |
352 | 352 |
353 # remove edges that ended | 353 # remove edges that ended |
354 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] |
355 for parent in remove: | 355 for parent in remove: |
356 del edgemap[parent] | 356 del edgemap[parent] |
358 | 358 |
359 | 359 |
360 def asciistate(): | 360 def asciistate(): |
361 """returns the initial value for the "state" argument to ascii()""" | 361 """returns the initial value for the "state" argument to ascii()""" |
362 return { | 362 return { |
363 'seen': [], | 363 b'seen': [], |
364 'edges': {}, | 364 b'edges': {}, |
365 'lastcoldiff': 0, | 365 b'lastcoldiff': 0, |
366 'lastindex': 0, | 366 b'lastindex': 0, |
367 'styles': EDGES.copy(), | 367 b'styles': EDGES.copy(), |
368 'graphshorten': False, | 368 b'graphshorten': False, |
369 } | 369 } |
370 | 370 |
371 | 371 |
372 def outputgraph(ui, graph): | 372 def outputgraph(ui, graph): |
373 """outputs an ASCII graph of a DAG | 373 """outputs an ASCII graph of a DAG |
381 | 381 |
382 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 |
383 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() |
384 """ | 384 """ |
385 for (ln, logstr) in graph: | 385 for (ln, logstr) in graph: |
386 ui.write((ln + logstr).rstrip() + "\n") | 386 ui.write((ln + logstr).rstrip() + b"\n") |
387 | 387 |
388 | 388 |
389 def ascii(ui, state, type, char, text, coldata): | 389 def ascii(ui, state, type, char, text, coldata): |
390 """prints an ASCII graph of the DAG | 390 """prints an ASCII graph of the DAG |
391 | 391 |
407 0 means no columns added or removed; 1 means one column added. | 407 0 means no columns added or removed; 1 means one column added. |
408 """ | 408 """ |
409 idx, edges, ncols, coldiff = coldata | 409 idx, edges, ncols, coldiff = coldata |
410 assert -2 < coldiff < 2 | 410 assert -2 < coldiff < 2 |
411 | 411 |
412 edgemap, seen = state['edges'], state['seen'] | 412 edgemap, seen = state[b'edges'], state[b'seen'] |
413 # Be tolerant of history issues; make sure we have at least ncols + coldiff | 413 # Be tolerant of history issues; make sure we have at least ncols + coldiff |
414 # elements to work with. See test-glog.t for broken history test cases. | 414 # elements to work with. See test-glog.t for broken history test cases. |
415 echars = [c for p in seen for c in (edgemap.get(p, '|'), ' ')] | 415 echars = [c for p in seen for c in (edgemap.get(p, b'|'), b' ')] |
416 echars.extend(('|', ' ') * max(ncols + coldiff - len(seen), 0)) | 416 echars.extend((b'|', b' ') * max(ncols + coldiff - len(seen), 0)) |
417 | 417 |
418 if coldiff == -1: | 418 if coldiff == -1: |
419 # Transform | 419 # Transform |
420 # | 420 # |
421 # | | | | | | | 421 # | | | | | | |
444 # o | | o | | | 444 # o | | o | | |
445 fix_nodeline_tail = len(text) <= 2 and not add_padding_line | 445 fix_nodeline_tail = len(text) <= 2 and not add_padding_line |
446 | 446 |
447 # nodeline is the line containing the node character (typically o) | 447 # nodeline is the line containing the node character (typically o) |
448 nodeline = echars[: idx * 2] | 448 nodeline = echars[: idx * 2] |
449 nodeline.extend([char, " "]) | 449 nodeline.extend([char, b" "]) |
450 | 450 |
451 nodeline.extend( | 451 nodeline.extend( |
452 _getnodelineedgestail( | 452 _getnodelineedgestail( |
453 echars, | 453 echars, |
454 idx, | 454 idx, |
455 state['lastindex'], | 455 state[b'lastindex'], |
456 ncols, | 456 ncols, |
457 coldiff, | 457 coldiff, |
458 state['lastcoldiff'], | 458 state[b'lastcoldiff'], |
459 fix_nodeline_tail, | 459 fix_nodeline_tail, |
460 ) | 460 ) |
461 ) | 461 ) |
462 | 462 |
463 # shift_interline is the line containing the non-vertical | 463 # shift_interline is the line containing the non-vertical |
464 # edges between this entry and the next | 464 # edges between this entry and the next |
465 shift_interline = echars[: idx * 2] | 465 shift_interline = echars[: idx * 2] |
466 for i in pycompat.xrange(2 + coldiff): | 466 for i in pycompat.xrange(2 + coldiff): |
467 shift_interline.append(' ') | 467 shift_interline.append(b' ') |
468 count = ncols - idx - 1 | 468 count = ncols - idx - 1 |
469 if coldiff == -1: | 469 if coldiff == -1: |
470 for i in pycompat.xrange(count): | 470 for i in pycompat.xrange(count): |
471 shift_interline.extend(['/', ' ']) | 471 shift_interline.extend([b'/', b' ']) |
472 elif coldiff == 0: | 472 elif coldiff == 0: |
473 shift_interline.extend(echars[(idx + 1) * 2 : ncols * 2]) | 473 shift_interline.extend(echars[(idx + 1) * 2 : ncols * 2]) |
474 else: | 474 else: |
475 for i in pycompat.xrange(count): | 475 for i in pycompat.xrange(count): |
476 shift_interline.extend(['\\', ' ']) | 476 shift_interline.extend([b'\\', b' ']) |
477 | 477 |
478 # draw edges from the current node to its parents | 478 # draw edges from the current node to its parents |
479 _drawedges(echars, edges, nodeline, shift_interline) | 479 _drawedges(echars, edges, nodeline, shift_interline) |
480 | 480 |
481 # lines is the list of all graph lines to print | 481 # lines is the list of all graph lines to print |
483 if add_padding_line: | 483 if add_padding_line: |
484 lines.append(_getpaddingline(echars, idx, ncols, edges)) | 484 lines.append(_getpaddingline(echars, idx, ncols, edges)) |
485 | 485 |
486 # If 'graphshorten' config, only draw shift_interline | 486 # If 'graphshorten' config, only draw shift_interline |
487 # when there is any non vertical flow in graph. | 487 # when there is any non vertical flow in graph. |
488 if state['graphshorten']: | 488 if state[b'graphshorten']: |
489 if any(c in br'\/' for c in shift_interline if c): | 489 if any(c in br'\/' for c in shift_interline if c): |
490 lines.append(shift_interline) | 490 lines.append(shift_interline) |
491 # Else, no 'graphshorten' config so draw shift_interline. | 491 # Else, no 'graphshorten' config so draw shift_interline. |
492 else: | 492 else: |
493 lines.append(shift_interline) | 493 lines.append(shift_interline) |
500 lines.append(extra_interline[:]) | 500 lines.append(extra_interline[:]) |
501 | 501 |
502 _drawendinglines(lines, extra_interline, edgemap, seen, state) | 502 _drawendinglines(lines, extra_interline, edgemap, seen, state) |
503 | 503 |
504 while len(text) < len(lines): | 504 while len(text) < len(lines): |
505 text.append("") | 505 text.append(b"") |
506 | 506 |
507 # print lines | 507 # print lines |
508 indentation_level = max(ncols, ncols + coldiff) | 508 indentation_level = max(ncols, ncols + coldiff) |
509 lines = ["%-*s " % (2 * indentation_level, "".join(line)) for line in lines] | 509 lines = [ |
510 b"%-*s " % (2 * indentation_level, b"".join(line)) for line in lines | |
511 ] | |
510 outputgraph(ui, zip(lines, text)) | 512 outputgraph(ui, zip(lines, text)) |
511 | 513 |
512 # ... and start over | 514 # ... and start over |
513 state['lastcoldiff'] = coldiff | 515 state[b'lastcoldiff'] = coldiff |
514 state['lastindex'] = idx | 516 state[b'lastindex'] = idx |