comparison hgext/phabricator.py @ 43263:06a33a501aa2

phabricator: treat non-utf-8 text files as binary as phabricator requires Phabricator can't cope with text files that are not UTF-8, so requires them to be submitted as binary files instead. This has the unfortunate effect of making them practically unreviewable in Phabricator since it will only display the separate versions of the file in other views, not a diff. `phabread`ing such submissions are similar, since it will just output the binary patch, but `hg import` copes with it fine and `hg diff` afterwards will show the actual changes. It is still a marked improvement over trying to submit them as text, which just leads to corruption (Phabricator will either output ? or HTML entities for non-UTF-8 characters, depending on context). Running decode on the whole file like this seems slightly unfortunate, but I'm not aware of a better way. Needs to be done to p1() version as well to detect conversions to UTF-8. Differential Revision: https://phab.mercurial-scm.org/D7054
author Ian Moody <moz-ian@perix.co.uk>
date Thu, 10 Oct 2019 22:05:28 +0100
parents af067d29b19e
children a4da1c3b82ab
comparison
equal deleted inserted replaced
43262:af067d29b19e 43263:06a33a501aa2
695 695
696 # Copied from mercurial/patch.py 696 # Copied from mercurial/patch.py
697 gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'} 697 gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
698 698
699 699
700 def notutf8(fctx):
701 """detect non-UTF-8 text files since Phabricator requires them to be marked
702 as binary
703 """
704 try:
705 fctx.data().decode('utf-8')
706 if fctx.parents():
707 fctx.p1().data().decode('utf-8')
708 return False
709 except UnicodeDecodeError:
710 fctx.repo().ui.write(
711 _(b'file %s detected as non-UTF-8, marked as binary\n')
712 % fctx.path()
713 )
714 return True
715
716
700 def addremoved(pdiff, ctx, removed): 717 def addremoved(pdiff, ctx, removed):
701 """add removed files to the phabdiff. Shouldn't include moves""" 718 """add removed files to the phabdiff. Shouldn't include moves"""
702 for fname in removed: 719 for fname in removed:
703 pchange = phabchange( 720 pchange = phabchange(
704 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE 721 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE
705 ) 722 )
706 pchange.addoldmode(gitmode[ctx.p1()[fname].flags()]) 723 pchange.addoldmode(gitmode[ctx.p1()[fname].flags()])
707 fctx = ctx.p1()[fname] 724 fctx = ctx.p1()[fname]
708 if not fctx.isbinary(): 725 if not (fctx.isbinary() or notutf8(fctx)):
709 maketext(pchange, ctx, fname) 726 maketext(pchange, ctx, fname)
710 727
711 pdiff.addchange(pchange) 728 pdiff.addchange(pchange)
712 729
713 730
720 originalmode = gitmode[ctx.p1()[fname].flags()] 737 originalmode = gitmode[ctx.p1()[fname].flags()]
721 if filemode != originalmode: 738 if filemode != originalmode:
722 pchange.addoldmode(originalmode) 739 pchange.addoldmode(originalmode)
723 pchange.addnewmode(filemode) 740 pchange.addnewmode(filemode)
724 741
725 if fctx.isbinary(): 742 if fctx.isbinary() or notutf8(fctx):
726 makebinary(pchange, fctx) 743 makebinary(pchange, fctx)
727 addoldbinary(pchange, fctx, fname) 744 addoldbinary(pchange, fctx, fname)
728 else: 745 else:
729 maketext(pchange, ctx, fname) 746 maketext(pchange, ctx, fname)
730 747
779 pchange.addnewmode(filemode) 796 pchange.addnewmode(filemode)
780 else: # Brand-new file 797 else: # Brand-new file
781 pchange.addnewmode(gitmode[fctx.flags()]) 798 pchange.addnewmode(gitmode[fctx.flags()])
782 pchange.type = DiffChangeType.ADD 799 pchange.type = DiffChangeType.ADD
783 800
784 if fctx.isbinary(): 801 if fctx.isbinary() or notutf8(fctx):
785 makebinary(pchange, fctx) 802 makebinary(pchange, fctx)
786 if renamed: 803 if renamed:
787 addoldbinary(pchange, fctx, originalfname) 804 addoldbinary(pchange, fctx, originalfname)
788 else: 805 else:
789 maketext(pchange, ctx, fname) 806 maketext(pchange, ctx, fname)