312 # Map from "hg:meta" keys to header understood by "hg import". The order is |
312 # Map from "hg:meta" keys to header understood by "hg import". The order is |
313 # consistent with "hg export" output. |
313 # consistent with "hg export" output. |
314 _metanamemap = util.sortdict([(r'user', 'User'), (r'date', 'Date'), |
314 _metanamemap = util.sortdict([(r'user', 'User'), (r'date', 'Date'), |
315 (r'node', 'Node ID'), (r'parent', 'Parent ')]) |
315 (r'node', 'Node ID'), (r'parent', 'Parent ')]) |
316 |
316 |
317 def readpatch(repo, params, recursive=False): |
317 def querydrev(repo, params, stack=False): |
|
318 """return a list of "Differential Revision" dicts |
|
319 |
|
320 params is the input of "differential.query" API, and is expected to match |
|
321 just a single Differential Revision. |
|
322 |
|
323 A "Differential Revision dict" looks like: |
|
324 |
|
325 { |
|
326 "id": "2", |
|
327 "phid": "PHID-DREV-672qvysjcczopag46qty", |
|
328 "title": "example", |
|
329 "uri": "https://phab.example.com/D2", |
|
330 "dateCreated": "1499181406", |
|
331 "dateModified": "1499182103", |
|
332 "authorPHID": "PHID-USER-tv3ohwc4v4jeu34otlye", |
|
333 "status": "0", |
|
334 "statusName": "Needs Review", |
|
335 "properties": [], |
|
336 "branch": null, |
|
337 "summary": "", |
|
338 "testPlan": "", |
|
339 "lineCount": "2", |
|
340 "activeDiffPHID": "PHID-DIFF-xoqnjkobbm6k4dk6hi72", |
|
341 "diffs": [ |
|
342 "3", |
|
343 "4", |
|
344 ], |
|
345 "commits": [], |
|
346 "reviewers": [], |
|
347 "ccs": [], |
|
348 "hashes": [], |
|
349 "auxiliary": { |
|
350 "phabricator:projects": [], |
|
351 "phabricator:depends-on": [ |
|
352 "PHID-DREV-gbapp366kutjebt7agcd" |
|
353 ] |
|
354 }, |
|
355 "repositoryPHID": "PHID-REPO-hub2hx62ieuqeheznasv", |
|
356 "sourcePath": null |
|
357 } |
|
358 |
|
359 If stack is True, return a list of "Differential Revision dict"s in an |
|
360 order that the latter ones depend on the former ones. Otherwise, return a |
|
361 list of a unique "Differential Revision dict". |
|
362 """ |
|
363 result = [] |
|
364 queue = [params] |
|
365 while queue: |
|
366 params = queue.pop() |
|
367 drevs = callconduit(repo, 'differential.query', params) |
|
368 if len(drevs) != 1: |
|
369 raise error.Abort(_('cannot get Differential Revision %r') % params) |
|
370 drev = drevs[0] |
|
371 result.append(drev) |
|
372 if stack: |
|
373 auxiliary = drev.get(r'auxiliary', {}) |
|
374 depends = auxiliary.get(r'phabricator:depends-on', []) |
|
375 for phid in depends: |
|
376 queue.append({'phids': [phid]}) |
|
377 result.reverse() |
|
378 return result |
|
379 |
|
380 def readpatch(repo, params, write, stack=False): |
318 """generate plain-text patch readable by 'hg import' |
381 """generate plain-text patch readable by 'hg import' |
319 |
382 |
320 params is passed to "differential.query". If recursive is True, also return |
383 write is usually ui.write. params is passed to "differential.query". If |
321 dependent patches. |
384 stack is True, also write dependent patches. |
322 """ |
385 """ |
323 # Differential Revisions |
386 # Differential Revisions |
324 drevs = callconduit(repo, 'differential.query', params) |
387 drevs = querydrev(repo, params, stack) |
325 if len(drevs) == 1: |
388 |
326 drev = drevs[0] |
389 # Prefetch hg:meta property for all diffs |
327 else: |
390 diffids = sorted(set(max(int(v) for v in drev[r'diffs']) for drev in drevs)) |
328 raise error.Abort(_('cannot get Differential Revision %r') % params) |
391 diffs = callconduit(repo, 'differential.querydiffs', {'ids': diffids}) |
329 |
392 |
330 repo.ui.note(_('reading D%s\n') % drev[r'id']) |
393 # Generate patch for each drev |
331 |
394 for drev in drevs: |
332 diffid = max(int(v) for v in drev[r'diffs']) |
395 repo.ui.note(_('reading D%s\n') % drev[r'id']) |
333 body = callconduit(repo, 'differential.getrawdiff', {'diffID': diffid}) |
396 |
334 desc = callconduit(repo, 'differential.getcommitmessage', |
397 diffid = max(int(v) for v in drev[r'diffs']) |
335 {'revision_id': drev[r'id']}) |
398 body = callconduit(repo, 'differential.getrawdiff', {'diffID': diffid}) |
336 header = '# HG changeset patch\n' |
399 desc = callconduit(repo, 'differential.getcommitmessage', |
337 |
400 {'revision_id': drev[r'id']}) |
338 # Remove potential empty "Summary:" |
401 header = '# HG changeset patch\n' |
339 desc = _summaryre.sub('', desc) |
402 |
340 |
403 # Remove potential empty "Summary:" |
341 # Try to preserve metadata from hg:meta property. Write hg patch headers |
404 desc = _summaryre.sub('', desc) |
342 # that can be read by the "import" command. See patchheadermap and extract |
405 |
343 # in mercurial/patch.py for supported headers. |
406 # Try to preserve metadata from hg:meta property. Write hg patch |
344 diffs = callconduit(repo, 'differential.querydiffs', {'ids': [diffid]}) |
407 # headers that can be read by the "import" command. See patchheadermap |
345 props = diffs[str(diffid)][r'properties'] # could be empty list or dict |
408 # and extract in mercurial/patch.py for supported headers. |
346 if props and r'hg:meta' in props: |
409 props = diffs[str(diffid)][r'properties'] # could be empty list or dict |
347 meta = props[r'hg:meta'] |
410 if props and r'hg:meta' in props: |
348 for k in _metanamemap.keys(): |
411 meta = props[r'hg:meta'] |
349 if k in meta: |
412 for k in _metanamemap.keys(): |
350 header += '# %s %s\n' % (_metanamemap[k], meta[k]) |
413 if k in meta: |
351 |
414 header += '# %s %s\n' % (_metanamemap[k], meta[k]) |
352 patch = ('%s%s\n%s') % (header, desc, body) |
415 |
353 |
416 write(('%s%s\n%s') % (header, desc, body)) |
354 # Check dependencies |
|
355 if recursive: |
|
356 auxiliary = drev.get(r'auxiliary', {}) |
|
357 depends = auxiliary.get(r'phabricator:depends-on', []) |
|
358 for phid in depends: |
|
359 patch = readpatch(repo, {'phids': [phid]}, recursive=True) + patch |
|
360 return patch |
|
361 |
417 |
362 @command('phabread', |
418 @command('phabread', |
363 [('', 'stack', False, _('read dependencies'))], |
419 [('', 'stack', False, _('read dependencies'))], |
364 _('REVID [OPTIONS]')) |
420 _('REVID [OPTIONS]')) |
365 def phabread(ui, repo, revid, **opts): |
421 def phabread(ui, repo, revid, **opts): |