in eden/scm/edenscm/mercurial/patch.py [0:0]
def filterpatch(ui, headers, operation=None):
"""Interactively filter patch chunks into applied-only chunks"""
messages = getmessages()
if operation is None:
operation = "record"
def prompt(skipfile, skipall, query, chunk):
"""prompt query, and process base inputs
- y/n for the rest of file
- y/n for the rest
- ? (help)
- q (quit)
Return True/False and possibly updated skipfile and skipall.
"""
newpatches = None
if skipall is not None:
return skipall, skipfile, skipall, newpatches
if skipfile is not None:
return skipfile, skipfile, skipall, newpatches
while True:
resps = messages["help"][operation]
r = ui.promptchoice("%s %s" % (query, resps))
ui.write("\n")
if r == 8: # ?
for c, t in ui.extractchoices(resps)[1]:
ui.write("%s - %s\n" % (c, encoding.lower(t)))
continue
elif r == 0: # yes
ret = True
elif r == 1: # no
ret = False
elif r == 2: # Edit patch
if chunk is None:
ui.write(_("cannot edit patch for whole file"))
ui.write("\n")
continue
if chunk.header.binary():
ui.write(_("cannot edit patch for binary file"))
ui.write("\n")
continue
# Patch comment based on the Git one (based on comment at end of
# https://mercurial-scm.org/wiki/RecordExtension)
phelp = "---" + _(
"""
To remove '-' lines, make them ' ' lines (context).
To remove '+' lines, delete them.
Lines starting with # will be removed from the patch.
If the patch applies cleanly, the edited hunk will immediately be
added to the record list. If it does not apply cleanly, a rejects
file will be generated: you can use that when you try again. If
all lines of the hunk are removed, then the edit is aborted and
the hunk is left unchanged.
"""
)
phelp = pycompat.encodeutf8(phelp)
(patchfd, patchfn) = tempfile.mkstemp(
prefix="hg-editor-", suffix=".diff", text=True
)
ncpatchfp = None
try:
# Write the initial patch
f = util.fdopen(patchfd, "wb")
chunk.header.write(f)
chunk.write(f)
f.write(b"\n".join([b"# " + i for i in phelp.splitlines()]))
f.close()
# Start the editor and wait for it to complete
editor = ui.geteditor()
ret = ui.system(
'%s "%s"' % (editor, patchfn),
environ={"HGUSER": ui.username()},
blockedtag="filterpatch",
)
if ret != 0:
ui.warn(_("editor exited with exit code %d\n") % ret)
continue
# Remove comment lines
patchfp = open(patchfn, "rb")
ncpatchfp = stringio()
for line in util.iterfile(patchfp):
if not line.startswith(b"#"):
ncpatchfp.write(line)
patchfp.close()
ncpatchfp.seek(0)
newpatches = parsepatch(ncpatchfp)
finally:
os.unlink(patchfn)
del ncpatchfp
# Signal that the chunk shouldn't be applied as-is, but
# provide the new patch to be used instead.
ret = False
elif r == 3: # Skip
ret = skipfile = False
elif r == 4: # file (Record remaining)
ret = skipfile = True
elif r == 5: # done, skip remaining
ret = skipall = False
elif r == 6: # all
ret = skipall = True
elif r == 7: # quit
raise error.Abort(_("user quit"))
return ret, skipfile, skipall, newpatches
seen = set()
applied = {} # 'filename' -> [] of chunks
skipfile, skipall = None, None
pos, total = 1, sum(len(h.hunks) for h in headers)
class fd(object):
@staticmethod
def write(*args, **opts):
ui.writebytes(*args, **opts)
for h in headers:
pos += len(h.hunks)
skipfile = None
fixoffset = 0
hdr = b"".join(h.header)
if hdr in seen:
continue
seen.add(hdr)
if skipall is None:
h.pretty(fd)
msg = _("examine changes to %s?") % _(" and ").join(
"'%s'" % f for f in h.files()
)
r, skipfile, skipall, np = prompt(skipfile, skipall, msg, None)
if not r:
continue
applied[h.filename()] = [h]
if h.allhunks():
applied[h.filename()] += h.hunks
continue
for i, chunk in enumerate(h.hunks):
if skipfile is None and skipall is None:
chunk.pretty(fd)
if total == 1:
msg = messages["single"][operation] % chunk.filename()
else:
idx = pos - len(h.hunks) + i
msg = messages["multiple"][operation] % (idx, total, chunk.filename())
r, skipfile, skipall, newpatches = prompt(skipfile, skipall, msg, chunk)
if r:
if fixoffset:
chunk = copy.copy(chunk)
chunk.toline += fixoffset
applied[chunk.filename()].append(chunk)
elif newpatches is not None:
for newpatch in newpatches:
for newhunk in newpatch.hunks:
if fixoffset:
newhunk.toline += fixoffset
applied[newhunk.filename()].append(newhunk)
else:
fixoffset += chunk.removed - chunk.added
return (
sum(
[h for h in pycompat.itervalues(applied) if h[0].special() or len(h) > 1],
[],
),
{},
)