comparison hgext/phabricator.py @ 44609:53d75fdeaaaa

phabricator: add basectx arguments to file related `phabsend` utilities This is in support of a future `--fold` option, that allows rolling up several commits into a single review with a diff from the start to the end of the range. There are no functional changes yet- the original `ctx` is also passed as the new `basectx`, which represents the first commit in the review range (similar to `qbase` in MQ parlance). Other functions will need the range of commits, but these deal with status or the diffs, so they only need the end points. Differential Revision: https://phab.mercurial-scm.org/D8306
author Matt Harbison <matt_harbison@yahoo.com>
date Mon, 24 Feb 2020 12:06:34 -0500
parents 7b9aaec17126
children 022bf71515c9
comparison
equal deleted inserted replaced
44608:7b9aaec17126 44609:53d75fdeaaaa
548 break 548 break
549 549
550 return result 550 return result
551 551
552 552
553 def getdiff(ctx, diffopts): 553 def getdiff(basectx, ctx, diffopts):
554 """plain-text diff without header (user, commit message, etc)""" 554 """plain-text diff without header (user, commit message, etc)"""
555 output = util.stringio() 555 output = util.stringio()
556 for chunk, _label in patch.diffui( 556 for chunk, _label in patch.diffui(
557 ctx.repo(), ctx.p1().node(), ctx.node(), None, opts=diffopts 557 ctx.repo(), basectx.p1().node(), ctx.node(), None, opts=diffopts
558 ): 558 ):
559 output.write(chunk) 559 output.write(chunk)
560 return output.getvalue() 560 return output.getvalue()
561 561
562 562
659 self.changes[change.currentPath] = pycompat.byteskwargs( 659 self.changes[change.currentPath] = pycompat.byteskwargs(
660 attr.asdict(change) 660 attr.asdict(change)
661 ) 661 )
662 662
663 663
664 def maketext(pchange, ctx, fname): 664 def maketext(pchange, basectx, ctx, fname):
665 """populate the phabchange for a text file""" 665 """populate the phabchange for a text file"""
666 repo = ctx.repo() 666 repo = ctx.repo()
667 fmatcher = match.exact([fname]) 667 fmatcher = match.exact([fname])
668 diffopts = mdiff.diffopts(git=True, context=32767) 668 diffopts = mdiff.diffopts(git=True, context=32767)
669 _pfctx, _fctx, header, fhunks = next( 669 _pfctx, _fctx, header, fhunks = next(
670 patch.diffhunks(repo, ctx.p1(), ctx, fmatcher, opts=diffopts) 670 patch.diffhunks(repo, basectx.p1(), ctx, fmatcher, opts=diffopts)
671 ) 671 )
672 672
673 for fhunk in fhunks: 673 for fhunk in fhunks:
674 (oldOffset, oldLength, newOffset, newLength), lines = fhunk 674 (oldOffset, oldLength, newOffset, newLength), lines = fhunk
675 corpus = b''.join(lines[1:]) 675 corpus = b''.join(lines[1:])
811 % fctx.path() 811 % fctx.path()
812 ) 812 )
813 return True 813 return True
814 814
815 815
816 def addremoved(pdiff, ctx, removed): 816 def addremoved(pdiff, basectx, ctx, removed):
817 """add removed files to the phabdiff. Shouldn't include moves""" 817 """add removed files to the phabdiff. Shouldn't include moves"""
818 for fname in removed: 818 for fname in removed:
819 pchange = phabchange( 819 pchange = phabchange(
820 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE 820 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE
821 ) 821 )
822 oldfctx = ctx.p1()[fname] 822 oldfctx = basectx.p1()[fname]
823 pchange.addoldmode(gitmode[oldfctx.flags()]) 823 pchange.addoldmode(gitmode[oldfctx.flags()])
824 if not (oldfctx.isbinary() or notutf8(oldfctx)): 824 if not (oldfctx.isbinary() or notutf8(oldfctx)):
825 maketext(pchange, ctx, fname) 825 maketext(pchange, basectx, ctx, fname)
826 826
827 pdiff.addchange(pchange) 827 pdiff.addchange(pchange)
828 828
829 829
830 def addmodified(pdiff, ctx, modified): 830 def addmodified(pdiff, basectx, ctx, modified):
831 """add modified files to the phabdiff""" 831 """add modified files to the phabdiff"""
832 for fname in modified: 832 for fname in modified:
833 fctx = ctx[fname] 833 fctx = ctx[fname]
834 oldfctx = ctx.p1()[fname] 834 oldfctx = basectx.p1()[fname]
835 pchange = phabchange(currentPath=fname, oldPath=fname) 835 pchange = phabchange(currentPath=fname, oldPath=fname)
836 filemode = gitmode[fctx.flags()] 836 filemode = gitmode[fctx.flags()]
837 originalmode = gitmode[oldfctx.flags()] 837 originalmode = gitmode[oldfctx.flags()]
838 if filemode != originalmode: 838 if filemode != originalmode:
839 pchange.addoldmode(originalmode) 839 pchange.addoldmode(originalmode)
846 or notutf8(oldfctx) 846 or notutf8(oldfctx)
847 ): 847 ):
848 makebinary(pchange, fctx) 848 makebinary(pchange, fctx)
849 addoldbinary(pchange, oldfctx, fctx) 849 addoldbinary(pchange, oldfctx, fctx)
850 else: 850 else:
851 maketext(pchange, ctx, fname) 851 maketext(pchange, basectx, ctx, fname)
852 852
853 pdiff.addchange(pchange) 853 pdiff.addchange(pchange)
854 854
855 855
856 def addadded(pdiff, ctx, added, removed): 856 def addadded(pdiff, basectx, ctx, added, removed):
857 """add file adds to the phabdiff, both new files and copies/moves""" 857 """add file adds to the phabdiff, both new files and copies/moves"""
858 # Keep track of files that've been recorded as moved/copied, so if there are 858 # Keep track of files that've been recorded as moved/copied, so if there are
859 # additional copies we can mark them (moves get removed from removed) 859 # additional copies we can mark them (moves get removed from removed)
860 copiedchanges = {} 860 copiedchanges = {}
861 movedchanges = {} 861 movedchanges = {}
867 filemode = gitmode[fctx.flags()] 867 filemode = gitmode[fctx.flags()]
868 renamed = fctx.renamed() 868 renamed = fctx.renamed()
869 869
870 if renamed: 870 if renamed:
871 originalfname = renamed[0] 871 originalfname = renamed[0]
872 oldfctx = ctx.p1()[originalfname] 872 oldfctx = basectx.p1()[originalfname]
873 originalmode = gitmode[oldfctx.flags()] 873 originalmode = gitmode[oldfctx.flags()]
874 pchange.oldPath = originalfname 874 pchange.oldPath = originalfname
875 875
876 if originalfname in removed: 876 if originalfname in removed:
877 origpchange = phabchange( 877 origpchange = phabchange(
912 ): 912 ):
913 makebinary(pchange, fctx) 913 makebinary(pchange, fctx)
914 if renamed: 914 if renamed:
915 addoldbinary(pchange, oldfctx, fctx) 915 addoldbinary(pchange, oldfctx, fctx)
916 else: 916 else:
917 maketext(pchange, ctx, fname) 917 maketext(pchange, basectx, ctx, fname)
918 918
919 pdiff.addchange(pchange) 919 pdiff.addchange(pchange)
920 920
921 for _path, copiedchange in copiedchanges.items(): 921 for _path, copiedchange in copiedchanges.items():
922 pdiff.addchange(copiedchange) 922 pdiff.addchange(copiedchange)
923 for _path, movedchange in movedchanges.items(): 923 for _path, movedchange in movedchanges.items():
924 pdiff.addchange(movedchange) 924 pdiff.addchange(movedchange)
925 925
926 926
927 def creatediff(ctx): 927 def creatediff(basectx, ctx):
928 """create a Differential Diff""" 928 """create a Differential Diff"""
929 repo = ctx.repo() 929 repo = ctx.repo()
930 repophid = getrepophid(repo) 930 repophid = getrepophid(repo)
931 # Create a "Differential Diff" via "differential.creatediff" API 931 # Create a "Differential Diff" via "differential.creatediff" API
932 pdiff = phabdiff( 932 pdiff = phabdiff(
933 sourceControlBaseRevision=b'%s' % ctx.p1().hex(), 933 sourceControlBaseRevision=b'%s' % basectx.p1().hex(),
934 branch=b'%s' % ctx.branch(), 934 branch=b'%s' % ctx.branch(),
935 ) 935 )
936 modified, added, removed, _d, _u, _i, _c = ctx.p1().status(ctx) 936 modified, added, removed, _d, _u, _i, _c = basectx.p1().status(ctx)
937 # addadded will remove moved files from removed, so addremoved won't get 937 # addadded will remove moved files from removed, so addremoved won't get
938 # them 938 # them
939 addadded(pdiff, ctx, added, removed) 939 addadded(pdiff, basectx, ctx, added, removed)
940 addmodified(pdiff, ctx, modified) 940 addmodified(pdiff, basectx, ctx, modified)
941 addremoved(pdiff, ctx, removed) 941 addremoved(pdiff, basectx, ctx, removed)
942 if repophid: 942 if repophid:
943 pdiff.repositoryPHID = repophid 943 pdiff.repositoryPHID = repophid
944 diff = callconduit( 944 diff = callconduit(
945 repo.ui, 945 repo.ui,
946 b'differential.creatediff', 946 b'differential.creatediff',
947 pycompat.byteskwargs(attr.asdict(pdiff)), 947 pycompat.byteskwargs(attr.asdict(pdiff)),
948 ) 948 )
949 if not diff: 949 if not diff:
950 raise error.Abort(_(b'cannot create diff for %s') % ctx) 950 if basectx != ctx:
951 msg = _(b'cannot create diff for %s::%s') % (basectx, ctx)
952 else:
953 msg = _(b'cannot create diff for %s') % ctx
954 raise error.Abort(msg)
951 return diff 955 return diff
952 956
953 957
954 def writediffproperties(ctx, diff): 958 def writediffproperties(ctx, diff):
955 """write metadata to diff so patches could be applied losslessly""" 959 """write metadata to diff so patches could be applied losslessly"""
1006 If oldnode is not None, check if the patch content (without commit message 1010 If oldnode is not None, check if the patch content (without commit message
1007 and metadata) has changed before creating another diff. 1011 and metadata) has changed before creating another diff.
1008 1012
1009 If actions is not None, they will be appended to the transaction. 1013 If actions is not None, they will be appended to the transaction.
1010 """ 1014 """
1015 basectx = ctx
1011 repo = ctx.repo() 1016 repo = ctx.repo()
1012 if oldnode: 1017 if oldnode:
1013 diffopts = mdiff.diffopts(git=True, context=32767) 1018 diffopts = mdiff.diffopts(git=True, context=32767)
1014 oldctx = repo.unfiltered()[oldnode] 1019 oldctx = repo.unfiltered()[oldnode]
1015 neednewdiff = getdiff(ctx, diffopts) != getdiff(oldctx, diffopts) 1020 oldbasectx = oldctx
1021 neednewdiff = getdiff(basectx, ctx, diffopts) != getdiff(
1022 oldbasectx, oldctx, diffopts
1023 )
1016 else: 1024 else:
1017 neednewdiff = True 1025 neednewdiff = True
1018 1026
1019 transactions = [] 1027 transactions = []
1020 if neednewdiff: 1028 if neednewdiff:
1021 diff = creatediff(ctx) 1029 diff = creatediff(basectx, ctx)
1022 transactions.append({b'type': b'update', b'value': diff[b'phid']}) 1030 transactions.append({b'type': b'update', b'value': diff[b'phid']})
1023 if comment: 1031 if comment:
1024 transactions.append({b'type': b'comment', b'value': comment}) 1032 transactions.append({b'type': b'comment', b'value': comment})
1025 else: 1033 else:
1026 # Even if we don't need to upload a new diff because the patch content 1034 # Even if we don't need to upload a new diff because the patch content