phabricator: add the uploadfile function
This is needed to be able to submit binary files such as images in commits (and
also non-UTF-8 text files). One of the primary disadvantages of the current
use of createrawdiff is that Phabricator simply drops any binary diffs included
in the patch, but not the files, so if such a diff is then committed it
corrupts any binary files in it.
Differential Revision: https://phab.mercurial-scm.org/D7047
--- a/hgext/phabricator.py Sun Oct 06 15:04:54 2019 +0100
+++ b/hgext/phabricator.py Sun Oct 06 15:16:47 2019 +0100
@@ -43,6 +43,7 @@
import base64
import contextlib
+import hashlib
import itertools
import json
import operator
@@ -608,6 +609,43 @@
progress.complete()
+def uploadfile(fctx):
+ """upload binary files to Phabricator"""
+ repo = fctx.repo()
+ ui = repo.ui
+ fname = fctx.path()
+ size = fctx.size()
+ fhash = pycompat.bytestr(hashlib.sha256(fctx.data()).hexdigest())
+
+ # an allocate call is required first to see if an upload is even required
+ # (Phab might already have it) and to determine if chunking is needed
+ allocateparams = {
+ b'name': fname,
+ b'contentLength': size,
+ b'contentHash': fhash,
+ }
+ filealloc = callconduit(ui, b'file.allocate', allocateparams)
+ fphid = filealloc[b'filePHID']
+
+ if filealloc[b'upload']:
+ ui.write(_(b'uploading %s\n') % bytes(fctx))
+ if not fphid:
+ uploadparams = {
+ b'name': fname,
+ b'data_base64': base64.b64encode(fctx.data()),
+ }
+ fphid = callconduit(ui, b'file.upload', uploadparams)
+ else:
+ uploadchunks(fctx, fphid)
+ else:
+ ui.debug(b'server already has %s\n' % bytes(fctx))
+
+ if not fphid:
+ raise error.Abort(b'Upload of %s failed.' % bytes(fctx))
+
+ return fphid
+
+
def creatediff(ctx):
"""create a Differential Diff"""
repo = ctx.repo()