comparison mercurial/patch.py @ 41657:d4c9eebdd72d

patch: replace "prefix" and "relroot" arguments by "pathfn" (API) The two arguments serve a very similar purpose: "relroot" is stripped from the front of the path, and then "prefix" (a subrepo path) is added (also to the front). Passing in a function that does that is more generic and will make it easier to respect ui.relative-paths in later patches (don't worry, I'm not going to respect that option for regular patches, only for --stat). I'm deliberately not calling it "uipathfn", because it's generally for producing valid diffs (including when prefix is non-empty), so things like using backslash on Windows is not an option. Differential Revision: https://phab.mercurial-scm.org/D5894
author Martin von Zweigbergk <martinvonz@google.com>
date Wed, 06 Feb 2019 23:12:56 -0800
parents 3751595ec45e
children aaad36b88298
comparison
equal deleted inserted replaced
41656:2306158314e9 41657:d4c9eebdd72d
13 import copy 13 import copy
14 import email 14 import email
15 import errno 15 import errno
16 import hashlib 16 import hashlib
17 import os 17 import os
18 import posixpath
19 import re 18 import re
20 import shutil 19 import shutil
21 import zlib 20 import zlib
22 21
23 from .i18n import _ 22 from .i18n import _
2237 diffopts = diffutil.diffallopts 2236 diffopts = diffutil.diffallopts
2238 diffallopts = diffutil.diffallopts 2237 diffallopts = diffutil.diffallopts
2239 difffeatureopts = diffutil.difffeatureopts 2238 difffeatureopts = diffutil.difffeatureopts
2240 2239
2241 def diff(repo, node1=None, node2=None, match=None, changes=None, 2240 def diff(repo, node1=None, node2=None, match=None, changes=None,
2242 opts=None, losedatafn=None, prefix='', relroot='', copy=None, 2241 opts=None, losedatafn=None, pathfn=None, copy=None,
2243 copysourcematch=None, hunksfilterfn=None): 2242 copysourcematch=None, hunksfilterfn=None):
2244 '''yields diff of changes to files between two nodes, or node and 2243 '''yields diff of changes to files between two nodes, or node and
2245 working directory. 2244 working directory.
2246 2245
2247 if node1 is None, use first dirstate parent instead. 2246 if node1 is None, use first dirstate parent instead.
2275 2274
2276 ctx1 = repo[node1] 2275 ctx1 = repo[node1]
2277 ctx2 = repo[node2] 2276 ctx2 = repo[node2]
2278 2277
2279 for fctx1, fctx2, hdr, hunks in diffhunks( 2278 for fctx1, fctx2, hdr, hunks in diffhunks(
2280 repo, ctx1=ctx1, ctx2=ctx2, 2279 repo, ctx1=ctx1, ctx2=ctx2, match=match, changes=changes, opts=opts,
2281 match=match, changes=changes, opts=opts, 2280 losedatafn=losedatafn, pathfn=pathfn, copy=copy,
2282 losedatafn=losedatafn, prefix=prefix, relroot=relroot, copy=copy,
2283 copysourcematch=copysourcematch): 2281 copysourcematch=copysourcematch):
2284 if hunksfilterfn is not None: 2282 if hunksfilterfn is not None:
2285 # If the file has been removed, fctx2 is None; but this should 2283 # If the file has been removed, fctx2 is None; but this should
2286 # not occur here since we catch removed files early in 2284 # not occur here since we catch removed files early in
2287 # logcmdutil.getlinerangerevs() for 'hg log -L'. 2285 # logcmdutil.getlinerangerevs() for 'hg log -L'.
2292 if hdr and (text or len(hdr) > 1): 2290 if hdr and (text or len(hdr) > 1):
2293 yield '\n'.join(hdr) + '\n' 2291 yield '\n'.join(hdr) + '\n'
2294 if text: 2292 if text:
2295 yield text 2293 yield text
2296 2294
2297 def diffhunks(repo, ctx1, ctx2, match=None, changes=None, 2295 def diffhunks(repo, ctx1, ctx2, match=None, changes=None, opts=None,
2298 opts=None, losedatafn=None, prefix='', relroot='', copy=None, 2296 losedatafn=None, pathfn=None, copy=None, copysourcematch=None):
2299 copysourcematch=None):
2300 """Yield diff of changes to files in the form of (`header`, `hunks`) tuples 2297 """Yield diff of changes to files in the form of (`header`, `hunks`) tuples
2301 where `header` is a list of diff headers and `hunks` is an iterable of 2298 where `header` is a list of diff headers and `hunks` is an iterable of
2302 (`hunkrange`, `hunklines`) tuples. 2299 (`hunkrange`, `hunklines`) tuples.
2303 2300
2304 See diff() for the meaning of parameters. 2301 See diff() for the meaning of parameters.
2374 repo, list(modifiedset | addedset | removedset)) 2371 repo, list(modifiedset | addedset | removedset))
2375 scmutil.prefetchfiles(repo, [ctx1.rev(), ctx2.rev()], prefetchmatch) 2372 scmutil.prefetchfiles(repo, [ctx1.rev(), ctx2.rev()], prefetchmatch)
2376 2373
2377 def difffn(opts, losedata): 2374 def difffn(opts, losedata):
2378 return trydiff(repo, revs, ctx1, ctx2, modified, added, removed, 2375 return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2379 copy, getfilectx, opts, losedata, prefix, relroot) 2376 copy, getfilectx, opts, losedata, pathfn)
2380 if opts.upgrade and not opts.git: 2377 if opts.upgrade and not opts.git:
2381 try: 2378 try:
2382 def losedata(fn): 2379 def losedata(fn):
2383 if not losedatafn or not losedatafn(fn=fn): 2380 if not losedatafn or not losedatafn(fn=fn):
2384 raise GitDiffRequired 2381 raise GitDiffRequired
2589 and copy[copyto[f]] == f): 2586 and copy[copyto[f]] == f):
2590 continue 2587 continue
2591 yield f1, f2, copyop 2588 yield f1, f2, copyop
2592 2589
2593 def trydiff(repo, revs, ctx1, ctx2, modified, added, removed, 2590 def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
2594 copy, getfilectx, opts, losedatafn, prefix, relroot): 2591 copy, getfilectx, opts, losedatafn, pathfn):
2595 '''given input data, generate a diff and yield it in blocks 2592 '''given input data, generate a diff and yield it in blocks
2596 2593
2597 If generating a diff would lose data like flags or binary data and 2594 If generating a diff would lose data like flags or binary data and
2598 losedatafn is not None, it will be called. 2595 losedatafn is not None, it will be called.
2599 2596
2600 relroot is removed and prefix is added to every path in the diff output. 2597 pathfn is applied to every path in the diff output.
2601 2598 '''
2602 If relroot is not empty, this function expects every path in modified,
2603 added, removed and copy to start with it.'''
2604 2599
2605 def gitindex(text): 2600 def gitindex(text):
2606 if not text: 2601 if not text:
2607 text = "" 2602 text = ""
2608 l = len(text) 2603 l = len(text)
2626 date1 = dateutil.datestr(ctx1.date()) 2621 date1 = dateutil.datestr(ctx1.date())
2627 date2 = dateutil.datestr(ctx2.date()) 2622 date2 = dateutil.datestr(ctx2.date())
2628 2623
2629 gitmode = {'l': '120000', 'x': '100755', '': '100644'} 2624 gitmode = {'l': '120000', 'x': '100755', '': '100644'}
2630 2625
2631 if relroot != '' and (repo.ui.configbool('devel', 'all-warnings') 2626 if not pathfn:
2632 or repo.ui.configbool('devel', 'check-relroot')): 2627 pathfn = lambda f: f
2633 for f in modified + added + removed + list(copy) + list(copy.values()):
2634 if f is not None and not f.startswith(relroot):
2635 raise AssertionError(
2636 "file %s doesn't start with relroot %s" % (f, relroot))
2637 2628
2638 for f1, f2, copyop in _filepairs(modified, added, removed, copy, opts): 2629 for f1, f2, copyop in _filepairs(modified, added, removed, copy, opts):
2639 content1 = None 2630 content1 = None
2640 content2 = None 2631 content2 = None
2641 fctx1 = None 2632 fctx1 = None
2668 (not f1 and flag2) or 2659 (not f1 and flag2) or
2669 # change flags 2660 # change flags
2670 (f1 and f2 and flag1 != flag2)): 2661 (f1 and f2 and flag1 != flag2)):
2671 losedatafn(f2 or f1) 2662 losedatafn(f2 or f1)
2672 2663
2673 path1 = f1 or f2 2664 path1 = pathfn(f1 or f2)
2674 path2 = f2 or f1 2665 path2 = pathfn(f2 or f1)
2675 path1 = posixpath.join(prefix, path1[len(relroot):])
2676 path2 = posixpath.join(prefix, path2[len(relroot):])
2677 header = [] 2666 header = []
2678 if opts.git: 2667 if opts.git:
2679 header.append('diff --git %s%s %s%s' % 2668 header.append('diff --git %s%s %s%s' %
2680 (aprefix, path1, bprefix, path2)) 2669 (aprefix, path1, bprefix, path2))
2681 if not f1: # added 2670 if not f1: # added