[PATCH 09 of 10] phabricator: avoid calling differential.getrawdiff

Augie Fackler raf at durin42.com
Wed Jul 5 18:29:30 EDT 2017


On Tue, Jul 04, 2017 at 06:58:34PM -0700, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu <quark at fb.com>
> # Date 1499219074 25200
> #      Tue Jul 04 18:44:34 2017 -0700
> # Node ID 0e2c9cf54e09bacb4a019bc51693a9fecf1051a3
> # Parent  0f202460887f66efa3ddbd1d9a7d8afca75c0114
> # Available At https://bitbucket.org/quark-zju/hg-draft
> #              hg pull https://bitbucket.org/quark-zju/hg-draft -r 0e2c9cf54e09
> phabricator: avoid calling differential.getrawdiff

[...]

>
> diff --git a/contrib/phabricator.py b/contrib/phabricator.py
> --- a/contrib/phabricator.py
> +++ b/contrib/phabricator.py
> @@ -410,4 +410,95 @@ def getdescfromdrev(drev):
>      return '\n\n'.join(filter(None, [title, summary, testplan, uri]))
>
> +# see https://secure.phabricator.com/diffusion/ARC/browse/master/src/parser/
> +# diff/ArcanistDiffChangeType.php for those constants
> +class changetype(object):
> +    ADD = 1
> +    CHANGE = 2
> +    DELETE = 3
> +    MOVE_AWAY = 4
> +    COPY_AWAY = 5
> +    MOVE_HERE = 6
> +    COPY_HERE = 7
> +    MULTICOPY = 8

Oy. I'm not in love with having to clone their enum here. How stable
can we assume these values are, given that you had to slurp them out
of the arcanist source and not some API documentation?

> +
> +class filetype(object):
> +    TEXT = 1
> +
> +def getpatchbodyfromdiff(diff):
> +    """get patch body (without commit message or metadata) from a diff dict
> +
> +    This is similar to differential.getrawdiff API. But we reconstruct the diff
> +    from a diff object fetched earlier via differential.querydiffs API.
> +
> +    Currently it does not support binary files. However it seems the
> +    "differential.createrawdiff" API (used by phabsend) couldn't really handle
> +    base85 binaries so binary files are broken at uploading time, therefore
> +    this limitation is probably fine.
> +    """
> +    out = util.stringio()
> +    write = out.write
> +
> +    for c in diff[r'changes']:
> +        path = encoding.strtolocal(c[r'currentPath'])
> +        oldpath = encoding.strtolocal(c[r'oldPath'])
> +        patha = 'a/%s' % (oldpath or path)
> +        pathb = 'b/%s' % (path or oldpath)
> +
> +        ftype = int(c[r'fileType'])
> +        if ftype != filetype.TEXT:
> +            raise error.Abort(_('unsupported file type %s: %s') % (ftype, path))
> +
> +        ctype = int(c[r'type'])
> +        if ctype in [changetype.MULTICOPY, changetype.MOVE_AWAY,
> +                     changetype.COPY_AWAY]:
> +            # ignore these, COPY_HERE or MOVE_HERE will cover them
> +            continue
> +
> +        def getmode(name):
> +            s = (c[name] or {}).get(r'unix:filemode', r'100644')
> +            return encoding.strtolocal(s)
> +
> +        oldmode = getmode(r'oldProperties')
> +        newmode = getmode(r'newProperties')
> +
> +        write('diff --git %s %s\n' % (patha, pathb))
> +        if ctype == changetype.ADD:
> +            write('new file mode %s\n' % newmode)
> +            patha = '/dev/null'
> +        elif ctype == changetype.DELETE:
> +            write('deleted file mode %s\n' % oldmode)
> +            pathb = '/dev/null'
> +        else:
> +            if oldmode != newmode:
> +                write('old mode %s\nnew mode %s\n' % (oldmode, newmode))
> +            if ctype == changetype.CHANGE:
> +                pass
> +            elif ctype == changetype.MOVE_HERE:
> +                write('rename from %s\nrename to %s\n' % (oldpath, path))
> +            elif ctype == changetype.COPY_HERE:
> +                write('copy from %s\ncopy to %s\n' % (oldpath, path))
> +            else:
> +                raise error.Abort(_('unsupported change type %s: %s')
> +                                  % (ctype, path))
> +
> +        if c[r'hunks']:
> +            write('--- %s\n+++ %s\n' % (patha, pathb))
> +        for h in c[r'hunks']:
> +            oldoff = int(h[r'oldOffset'])
> +            oldlen = int(h[r'oldLength'])
> +            newoff = int(h[r'newOffset'])
> +            newlen = int(h[r'newLength'])
> +            write('@@ -%d,%d +%d,%d @@\n' % (oldoff, oldlen, newoff, newlen))
> +            write(encoding.strtolocal(h[r'corpus']))
> +
> +    # normalize the patch by trimming context to 3 lines
> +    headers = patch.parsepatch(out.getvalue(), maxcontext=3)
> +    out = util.stringio()
> +    for header in headers:
> +        header.write(out)
> +        for hunk in header.hunks:
> +            hunk.write(out)
> +    return out.getvalue()
> +
>  def readpatch(repo, params, write, stack=False):
>      """generate plain-text patch readable by 'hg import'
> @@ -425,8 +516,6 @@ def readpatch(repo, params, write, stack
>      # Generate patch for each drev
>      for drev in drevs:
> -        repo.ui.note(_('reading D%s\n') % drev[r'id'])
> -
>          diffid = max(int(v) for v in drev[r'diffs'])
> -        body = callconduit(repo, 'differential.getrawdiff', {'diffID': diffid})
> +        body = getpatchbodyfromdiff(diffs[str(diffid)])
>          desc = getdescfromdrev(drev)
>          header = '# HG changeset patch\n'
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list