##// END OF EJS Templates
drawdag: port to python 3
Augie Fackler -
r34204:5a1b4126 default
parent child Browse files
Show More
@@ -92,6 +92,7 b' from mercurial import ('
92 92 error,
93 93 node,
94 94 obsolete,
95 pycompat,
95 96 registrar,
96 97 scmutil,
97 98 tags as tagsmod,
@@ -100,9 +101,9 b' from mercurial import ('
100 101 cmdtable = {}
101 102 command = registrar.command(cmdtable)
102 103
103 _pipechars = '\\/+-|'
104 _nonpipechars = ''.join(chr(i) for i in xrange(33, 127)
105 if chr(i) not in _pipechars)
104 _pipechars = b'\\/+-|'
105 _nonpipechars = b''.join(pycompat.bytechr(i) for i in range(33, 127)
106 if pycompat.bytechr(i) not in _pipechars)
106 107
107 108 def _isname(ch):
108 109 """char -> bool. return True if ch looks like part of a name, False
@@ -113,7 +114,7 b' def _parseasciigraph(text):'
113 114 r"""str -> {str : [str]}. convert the ASCII graph to edges
114 115
115 116 >>> import pprint
116 >>> pprint.pprint({k: [vv for vv in v]
117 >>> pprint.pprint({pycompat.sysstr(k): [pycompat.sysstr(vv) for vv in v]
117 118 ... for k, v in _parseasciigraph(br'''
118 119 ... G
119 120 ... |
@@ -132,7 +133,7 b' def _parseasciigraph(text):'
132 133 'G': ['F'],
133 134 'H': ['A'],
134 135 'I': ['H']}
135 >>> pprint.pprint({k: [vv for vv in v]
136 >>> pprint.pprint({pycompat.sysstr(k): [pycompat.sysstr(vv) for vv in v]
136 137 ... for k, v in _parseasciigraph(br'''
137 138 ... o foo
138 139 ... |\
@@ -163,16 +164,16 b' def _parseasciigraph(text):'
163 164 """(int, int) -> char. give a coordinate, return the char. return a
164 165 space for anything out of range"""
165 166 if x < 0 or y < 0:
166 return ' '
167 return b' '
167 168 try:
168 return lines[y][x]
169 return lines[y][x:x + 1] or b' '
169 170 except IndexError:
170 return ' '
171 return b' '
171 172
172 173 def getname(y, x):
173 174 """(int, int) -> str. like get(y, x) but concatenate left and right
174 175 parts. if name is an 'o', try to replace it to the right"""
175 result = ''
176 result = b''
176 177 for i in itertools.count(0):
177 178 ch = get(y, x - i)
178 179 if not _isname(ch):
@@ -183,17 +184,17 b' def _parseasciigraph(text):'
183 184 if not _isname(ch):
184 185 break
185 186 result += ch
186 if result == 'o':
187 if result == b'o':
187 188 # special handling, find the name to the right
188 result = ''
189 result = b''
189 190 for i in itertools.count(2):
190 191 ch = get(y, x + i)
191 if ch == ' ' or ch in _pipechars:
192 if ch == b' ' or ch in _pipechars:
192 193 if result or x + i >= len(lines[y]):
193 194 break
194 195 else:
195 196 result += ch
196 return result or 'o'
197 return result or b'o'
197 198 return result
198 199
199 200 def parents(y, x):
@@ -209,19 +210,19 b' def _parseasciigraph(text):'
209 210 if '-' (or '+') is not in excepted, and get(y, x) is '-' (or '+'),
210 211 the next line (y + 1, x) will be checked instead."""
211 212 ch = get(y, x)
212 if any(ch == c and c not in expected for c in '-+'):
213 if any(ch == c and c not in expected for c in (b'-', b'+')):
213 214 y += 1
214 215 return follow(y + 1, x, expected)
215 if ch in expected or ('o' in expected and _isname(ch)):
216 if ch in expected or (b'o' in expected and _isname(ch)):
216 217 visit.append((y, x))
217 218
218 219 # -o- # starting point:
219 220 # /|\ # follow '-' (horizontally), and '/|\' (to the bottom)
220 follow(y + 1, x, '|')
221 follow(y + 1, x - 1, '/')
222 follow(y + 1, x + 1, '\\')
223 follow(y, x - 1, '-')
224 follow(y, x + 1, '-')
221 follow(y + 1, x, b'|')
222 follow(y + 1, x - 1, b'/')
223 follow(y + 1, x + 1, b'\\')
224 follow(y, x - 1, b'-')
225 follow(y, x + 1, b'-')
225 226
226 227 while visit:
227 228 y, x = visit.pop()
@@ -232,28 +233,28 b' def _parseasciigraph(text):'
232 233 if _isname(ch):
233 234 result.append(getname(y, x))
234 235 continue
235 elif ch == '|':
236 follow(y + 1, x, '/|o')
237 follow(y + 1, x - 1, '/')
238 follow(y + 1, x + 1, '\\')
239 elif ch == '+':
240 follow(y, x - 1, '-')
241 follow(y, x + 1, '-')
242 follow(y + 1, x - 1, '/')
243 follow(y + 1, x + 1, '\\')
244 follow(y + 1, x, '|')
245 elif ch == '\\':
246 follow(y + 1, x + 1, '\\|o')
247 elif ch == '/':
248 follow(y + 1, x - 1, '/|o')
249 elif ch == '-':
250 follow(y, x - 1, '-+o')
251 follow(y, x + 1, '-+o')
236 elif ch == b'|':
237 follow(y + 1, x, b'/|o')
238 follow(y + 1, x - 1, b'/')
239 follow(y + 1, x + 1, b'\\')
240 elif ch == b'+':
241 follow(y, x - 1, b'-')
242 follow(y, x + 1, b'-')
243 follow(y + 1, x - 1, b'/')
244 follow(y + 1, x + 1, b'\\')
245 follow(y + 1, x, b'|')
246 elif ch == b'\\':
247 follow(y + 1, x + 1, b'\\|o')
248 elif ch == b'/':
249 follow(y + 1, x - 1, b'/|o')
250 elif ch == b'-':
251 follow(y, x - 1, b'-+o')
252 follow(y, x + 1, b'-+o')
252 253 return result
253 254
254 255 for y, line in enumerate(lines):
255 for x, ch in enumerate(line):
256 if ch == '#': # comment
256 for x, ch in enumerate(pycompat.bytestr(line)):
257 if ch == b'#': # comment
257 258 break
258 259 if _isname(ch):
259 260 edges[getname(y, x)] += parents(y, x)
@@ -278,14 +279,14 b' class simplefilectx(object):'
278 279 return None
279 280
280 281 def flags(self):
281 return ''
282 return b''
282 283
283 284 class simplecommitctx(context.committablectx):
284 285 def __init__(self, repo, name, parentctxs, added):
285 286 opts = {
286 287 'changes': scmutil.status([], list(added), [], [], [], [], []),
287 'date': '0 0',
288 'extra': {'branch': 'default'},
288 'date': b'0 0',
289 'extra': {b'branch': b'default'},
289 290 }
290 291 super(simplecommitctx, self).__init__(self, name, **opts)
291 292 self._repo = repo
@@ -304,7 +305,7 b' def _walkgraph(edges):'
304 305 """yield node, parents in topologically order"""
305 306 visible = set(edges.keys())
306 307 remaining = {} # {str: [str]}
307 for k, vs in edges.iteritems():
308 for k, vs in edges.items():
308 309 for v in vs:
309 310 if v not in remaining:
310 311 remaining[v] = []
@@ -317,13 +318,13 b' def _walkgraph(edges):'
317 318 if leaf in visible:
318 319 yield leaf, edges[leaf]
319 320 del remaining[leaf]
320 for k, v in remaining.iteritems():
321 for k, v in remaining.items():
321 322 if leaf in v:
322 323 v.remove(leaf)
323 324
324 325 def _getcomments(text):
325 326 """
326 >>> [s for s in _getcomments(br'''
327 >>> [pycompat.sysstr(s) for s in _getcomments(br'''
327 328 ... G
328 329 ... |
329 330 ... I D C F # split: B -> E, F, G
@@ -335,11 +336,11 b' def _getcomments(text):'
335 336 ['split: B -> E, F, G', 'replace: C -> D -> H', 'prune: F, I']
336 337 """
337 338 for line in text.splitlines():
338 if ' # ' not in line:
339 if b' # ' not in line:
339 340 continue
340 yield line.split(' # ', 1)[1].split(' # ')[0].strip()
341 yield line.split(b' # ', 1)[1].split(b' # ')[0].strip()
341 342
342 @command('debugdrawdag', [])
343 @command(b'debugdrawdag', [])
343 344 def debugdrawdag(ui, repo, **opts):
344 345 """read an ASCII graph from stdin and create changesets
345 346
@@ -360,22 +361,22 b' def debugdrawdag(ui, repo, **opts):'
360 361
361 362 # parse the graph and make sure len(parents) <= 2 for each node
362 363 edges = _parseasciigraph(text)
363 for k, v in edges.iteritems():
364 for k, v in edges.items():
364 365 if len(v) > 2:
365 366 raise error.Abort(_('%s: too many parents: %s')
366 % (k, ' '.join(v)))
367 % (k, b' '.join(v)))
367 368
368 369 # parse comments to get extra file content instructions
369 370 files = collections.defaultdict(dict) # {(name, path): content}
370 371 comments = list(_getcomments(text))
371 filere = re.compile(r'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
372 for name, path, content in filere.findall('\n'.join(comments)):
373 files[name][path] = content.replace(r'\n', '\n')
372 filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
373 for name, path, content in filere.findall(b'\n'.join(comments)):
374 files[name][path] = content.replace(br'\n', b'\n')
374 375
375 376 committed = {None: node.nullid} # {name: node}
376 377
377 378 # for leaf nodes, try to find existing nodes in repo
378 for name, parents in edges.iteritems():
379 for name, parents in edges.items():
379 380 if len(parents) == 0:
380 381 try:
381 382 committed[name] = scmutil.revsingle(repo, name)
@@ -407,27 +408,27 b' def debugdrawdag(ui, repo, **opts):'
407 408 local=True)
408 409
409 410 # handle special comments
410 with repo.wlock(), repo.lock(), repo.transaction('drawdag'):
411 with repo.wlock(), repo.lock(), repo.transaction(b'drawdag'):
411 412 getctx = lambda x: repo.unfiltered()[committed[x.strip()]]
412 413 for comment in comments:
413 414 rels = [] # obsolete relationships
414 args = comment.split(':', 1)
415 args = comment.split(b':', 1)
415 416 if len(args) <= 1:
416 417 continue
417 418
418 419 cmd = args[0].strip()
419 420 arg = args[1].strip()
420 421
421 if cmd in ('replace', 'rebase', 'amend'):
422 nodes = [getctx(m) for m in arg.split('->')]
422 if cmd in (b'replace', b'rebase', b'amend'):
423 nodes = [getctx(m) for m in arg.split(b'->')]
423 424 for i in range(len(nodes) - 1):
424 425 rels.append((nodes[i], (nodes[i + 1],)))
425 elif cmd in ('split',):
426 pre, succs = arg.split('->')
427 succs = succs.split(',')
426 elif cmd in (b'split',):
427 pre, succs = arg.split(b'->')
428 succs = succs.split(b',')
428 429 rels.append((getctx(pre), (getctx(s) for s in succs)))
429 elif cmd in ('prune',):
430 for n in arg.split(','):
430 elif cmd in (b'prune',):
431 for n in arg.split(b','):
431 432 rels.append((getctx(n), ()))
432 433 if rels:
433 434 obsolete.createmarkers(repo, rels, date=(0, 0), operation=cmd)
General Comments 0
You need to be logged in to leave comments. Login now