Mercurial > public > mercurial-scm > hg
comparison mercurial/graphmod.py @ 28376:fa2cd0c9a567
graphmod: augment the graph to include more information about the edges
The walker knows when an edge leads to a direct parent, a grandparent (skipping
revisions not part of the revset) and parents that are missing altogether
(neither it nor a grandparent is in the revset). Add this information to the
parents sequence yielded.
author | Martijn Pieters <mjpieters@fb.com> |
---|---|
date | Fri, 04 Mar 2016 14:44:32 +0000 |
parents | 97cb1aeaca78 |
children | 0d6137891114 |
comparison
equal
deleted
inserted
replaced
28375:97cb1aeaca78 | 28376:fa2cd0c9a567 |
---|---|
26 revset, | 26 revset, |
27 util, | 27 util, |
28 ) | 28 ) |
29 | 29 |
30 CHANGESET = 'C' | 30 CHANGESET = 'C' |
31 PARENT = 'P' | |
32 GRANDPARENT = 'G' | |
33 MISSINGPARENT = 'M' | |
31 | 34 |
32 def groupbranchiter(revs, parentsfunc, firstbranch=()): | 35 def groupbranchiter(revs, parentsfunc, firstbranch=()): |
33 """Yield revisions from heads to roots one (topo) branch at a time. | 36 """Yield revisions from heads to roots one (topo) branch at a time. |
34 | 37 |
35 This function aims to be used by a graph generator that wishes to minimize | 38 This function aims to be used by a graph generator that wishes to minimize |
226 for g in groups: | 229 for g in groups: |
227 for r in g[0]: | 230 for r in g[0]: |
228 yield r | 231 yield r |
229 | 232 |
230 def dagwalker(repo, revs): | 233 def dagwalker(repo, revs): |
231 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples | 234 """cset DAG generator yielding (id, CHANGESET, ctx, [parentinfo]) tuples |
232 | 235 |
233 This generator function walks through revisions (which should be ordered | 236 This generator function walks through revisions (which should be ordered |
234 from bigger to lower). It returns a tuple for each node. The node and parent | 237 from bigger to lower). It returns a tuple for each node. |
235 ids are arbitrary integers which identify a node in the context of the graph | 238 |
239 Each parentinfo entry is a tuple with (edgetype, parentid), where edgetype | |
240 is one of PARENT, GRANDPARENT or MISSINGPARENT. The node and parent ids | |
241 are arbitrary integers which identify a node in the context of the graph | |
236 returned. | 242 returned. |
243 | |
237 """ | 244 """ |
238 if not revs: | 245 if not revs: |
239 return | 246 return |
240 | 247 |
241 gpcache = {} | 248 gpcache = {} |
250 revs = groupbranchiter(revs, parentrevs, firstbranch) | 257 revs = groupbranchiter(revs, parentrevs, firstbranch) |
251 revs = revset.baseset(revs) | 258 revs = revset.baseset(revs) |
252 | 259 |
253 for rev in revs: | 260 for rev in revs: |
254 ctx = repo[rev] | 261 ctx = repo[rev] |
255 parents = sorted(set([p.rev() for p in ctx.parents() | 262 # partition into parents in the rev set and missing parents, then |
256 if p.rev() in revs])) | 263 # augment the lists with markers, to inform graph drawing code about |
257 mpars = [p.rev() for p in ctx.parents() if | 264 # what kind of edge to draw between nodes. |
258 p.rev() != nullrev and p.rev() not in parents] | 265 pset = set(p.rev() for p in ctx.parents() if p.rev() in revs) |
266 mpars = [p.rev() for p in ctx.parents() | |
267 if p.rev() != nullrev and p.rev() not in pset] | |
268 parents = [(PARENT, p) for p in sorted(pset)] | |
259 | 269 |
260 for mpar in mpars: | 270 for mpar in mpars: |
261 gp = gpcache.get(mpar) | 271 gp = gpcache.get(mpar) |
262 if gp is None: | 272 if gp is None: |
263 # precompute slow query as we know reachableroots() goes | 273 # precompute slow query as we know reachableroots() goes |
264 # through all revs (issue4782) | 274 # through all revs (issue4782) |
265 if not isinstance(revs, revset.baseset): | 275 if not isinstance(revs, revset.baseset): |
266 revs = revset.baseset(revs) | 276 revs = revset.baseset(revs) |
267 gp = gpcache[mpar] = revset.reachableroots(repo, revs, [mpar]) | 277 gp = gpcache[mpar] = sorted(set(revset.reachableroots( |
278 repo, revs, [mpar]))) | |
268 if not gp: | 279 if not gp: |
269 parents.append(mpar) | 280 parents.append((MISSINGPARENT, mpar)) |
281 pset.add(mpar) | |
270 else: | 282 else: |
271 parents.extend(g for g in gp if g not in parents) | 283 parents.extend((GRANDPARENT, g) for g in gp if g not in pset) |
284 pset.update(gp) | |
272 | 285 |
273 yield (ctx.rev(), CHANGESET, ctx, parents) | 286 yield (ctx.rev(), CHANGESET, ctx, parents) |
274 | 287 |
275 def nodes(repo, nodes): | 288 def nodes(repo, nodes): |
276 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples | 289 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples |
279 that are in nodes, too. | 292 that are in nodes, too. |
280 """ | 293 """ |
281 include = set(nodes) | 294 include = set(nodes) |
282 for node in nodes: | 295 for node in nodes: |
283 ctx = repo[node] | 296 ctx = repo[node] |
284 parents = set([p.rev() for p in ctx.parents() if p.node() in include]) | 297 parents = set((PARENT, p.rev()) for p in ctx.parents() |
298 if p.node() in include) | |
285 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) | 299 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) |
286 | 300 |
287 def colored(dag, repo): | 301 def colored(dag, repo): |
288 """annotates a DAG with colored edge information | 302 """annotates a DAG with colored edge information |
289 | 303 |
328 col = seen.index(cur) | 342 col = seen.index(cur) |
329 color = colors.pop(cur) | 343 color = colors.pop(cur) |
330 next = seen[:] | 344 next = seen[:] |
331 | 345 |
332 # Add parents to next | 346 # Add parents to next |
333 addparents = [p for p in parents if p not in next] | 347 addparents = [p for pt, p in parents if p not in next] |
334 next[col:col + 1] = addparents | 348 next[col:col + 1] = addparents |
335 | 349 |
336 # Set colors for the parents | 350 # Set colors for the parents |
337 for i, p in enumerate(addparents): | 351 for i, p in enumerate(addparents): |
338 if not i: | 352 if not i: |
349 edges.append(( | 363 edges.append(( |
350 ecol, next.index(eid), colors[eid], | 364 ecol, next.index(eid), colors[eid], |
351 bconf.get('width', -1), | 365 bconf.get('width', -1), |
352 bconf.get('color', ''))) | 366 bconf.get('color', ''))) |
353 elif eid == cur: | 367 elif eid == cur: |
354 for p in parents: | 368 for ptype, p in parents: |
355 bconf = getconf(p) | 369 bconf = getconf(p) |
356 edges.append(( | 370 edges.append(( |
357 ecol, next.index(p), color, | 371 ecol, next.index(p), color, |
358 bconf.get('width', -1), | 372 bconf.get('width', -1), |
359 bconf.get('color', ''))) | 373 bconf.get('color', ''))) |
369 seen.append(rev) | 383 seen.append(rev) |
370 nodeidx = seen.index(rev) | 384 nodeidx = seen.index(rev) |
371 | 385 |
372 knownparents = [] | 386 knownparents = [] |
373 newparents = [] | 387 newparents = [] |
374 for parent in parents: | 388 for ptype, parent in parents: |
375 if parent in seen: | 389 if parent in seen: |
376 knownparents.append(parent) | 390 knownparents.append(parent) |
377 else: | 391 else: |
378 newparents.append(parent) | 392 newparents.append(parent) |
379 | 393 |