contrib/phabricator.py
changeset 33267 dba9f88659a3
parent 33266 5b2391b46906
child 33268 85391b95961d
equal deleted inserted replaced
33266:5b2391b46906 33267:dba9f88659a3
   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):
   372     """
   428     """
   373     try:
   429     try:
   374         revid = int(revid.split('/')[-1].replace('D', ''))
   430         revid = int(revid.split('/')[-1].replace('D', ''))
   375     except ValueError:
   431     except ValueError:
   376         raise error.Abort(_('invalid Revision ID: %s') % revid)
   432         raise error.Abort(_('invalid Revision ID: %s') % revid)
   377     patch = readpatch(repo, {'ids': [revid]}, recursive=opts.get('stack'))
   433     readpatch(repo, {'ids': [revid]}, ui.write, opts.get('stack'))
   378     ui.write(patch)