diffutil.py
192 lines
| 5.9 KiB
| text/x-python
|
PythonLexer
/ mercurial / diffutil.py
Yuya Nishihara
|
r38607 | # diffutil.py - utility functions related to diff and patch | ||
# | ||||
# Copyright 2006 Brendan Cully <brendan@kublai.com> | ||||
# Copyright 2007 Chris Mason <chris.mason@oracle.com> | ||||
# Copyright 2018 Octobus <octobus@octobus.net> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Matt Harbison
|
r52756 | from __future__ import annotations | ||
Matt Harbison
|
r51142 | import typing | ||
from typing import ( | ||||
Any, | ||||
Dict, | ||||
Optional, | ||||
) | ||||
Yuya Nishihara
|
r38607 | |||
from .i18n import _ | ||||
pacien
|
r52036 | from .node import nullrev | ||
Yuya Nishihara
|
r38607 | |||
from . import ( | ||||
mdiff, | ||||
pycompat, | ||||
) | ||||
Matt Harbison
|
r51142 | if typing.TYPE_CHECKING: | ||
from . import ui as uimod | ||||
# TODO: narrow the value after the config module is typed | ||||
_Opts = Dict[bytes, Any] | ||||
Augie Fackler
|
r43346 | |||
def diffallopts( | ||||
Matt Harbison
|
r51142 | ui: "uimod.ui", | ||
opts: Optional[_Opts] = None, | ||||
untrusted: bool = False, | ||||
section: bytes = b'diff', | ||||
configprefix: bytes = b'', | ||||
) -> mdiff.diffopts: | ||||
Yuya Nishihara
|
r38607 | '''return diffopts with all features supported and parsed''' | ||
Augie Fackler
|
r43346 | return difffeatureopts( | ||
ui, | ||||
opts=opts, | ||||
untrusted=untrusted, | ||||
section=section, | ||||
git=True, | ||||
whitespace=True, | ||||
formatchanging=True, | ||||
configprefix=configprefix, | ||||
) | ||||
Yuya Nishihara
|
r38607 | |||
Augie Fackler
|
r43346 | |||
def difffeatureopts( | ||||
Matt Harbison
|
r51142 | ui: "uimod.ui", | ||
opts: Optional[_Opts] = None, | ||||
untrusted: bool = False, | ||||
section: bytes = b'diff', | ||||
git: bool = False, | ||||
whitespace: bool = False, | ||||
formatchanging: bool = False, | ||||
configprefix: bytes = b'', | ||||
) -> mdiff.diffopts: | ||||
Augie Fackler
|
r46554 | """return diffopts with only opted-in features parsed | ||
Yuya Nishihara
|
r38607 | |||
Features: | ||||
- git: git-style diffs | ||||
- whitespace: whitespace options like ignoreblanklines and ignorews | ||||
- formatchanging: options that will likely break or cause correctness issues | ||||
with most diff parsers | ||||
Augie Fackler
|
r46554 | """ | ||
Augie Fackler
|
r43346 | |||
Matt Harbison
|
r51142 | def get( | ||
key: bytes, | ||||
name: Optional[bytes] = None, | ||||
getter=ui.configbool, | ||||
forceplain: Optional[bool] = None, | ||||
) -> Any: | ||||
Yuya Nishihara
|
r38607 | if opts: | ||
v = opts.get(key) | ||||
# diffopts flags are either None-default (which is passed | ||||
# through unchanged, so we can identify unset values), or | ||||
# some other falsey default (eg --unified, which defaults | ||||
# to an empty string). We only want to override the config | ||||
# entries from hgrc with command line values if they | ||||
# appear to have been set, which is any truthy value, | ||||
# True, or False. | ||||
if v or isinstance(v, bool): | ||||
return v | ||||
if forceplain is not None and ui.plain(): | ||||
return forceplain | ||||
Augie Fackler
|
r43346 | return getter( | ||
section, configprefix + (name or key), untrusted=untrusted | ||||
) | ||||
Yuya Nishihara
|
r38607 | |||
# core options, expected to be understood by every diff parser | ||||
buildopts = { | ||||
Augie Fackler
|
r43347 | b'nodates': get(b'nodates'), | ||
b'showfunc': get(b'show_function', b'showfunc'), | ||||
b'context': get(b'unified', getter=ui.config), | ||||
Yuya Nishihara
|
r38607 | } | ||
Augie Fackler
|
r43347 | buildopts[b'xdiff'] = ui.configbool(b'experimental', b'xdiff') | ||
Yuya Nishihara
|
r38607 | |||
if git: | ||||
Augie Fackler
|
r43347 | buildopts[b'git'] = get(b'git') | ||
Yuya Nishihara
|
r38607 | |||
# since this is in the experimental section, we need to call | ||||
# ui.configbool directory | ||||
Augie Fackler
|
r43347 | buildopts[b'showsimilarity'] = ui.configbool( | ||
b'experimental', b'extendedheader.similarity' | ||||
Augie Fackler
|
r43346 | ) | ||
Yuya Nishihara
|
r38607 | |||
# need to inspect the ui object instead of using get() since we want to | ||||
# test for an int | ||||
Augie Fackler
|
r43347 | hconf = ui.config(b'experimental', b'extendedheader.index') | ||
Yuya Nishihara
|
r38607 | if hconf is not None: | ||
hlen = None | ||||
try: | ||||
# the hash config could be an integer (for length of hash) or a | ||||
# word (e.g. short, full, none) | ||||
hlen = int(hconf) | ||||
if hlen < 0 or hlen > 40: | ||||
Augie Fackler
|
r43347 | msg = _(b"invalid length for extendedheader.index: '%d'\n") | ||
Yuya Nishihara
|
r38607 | ui.warn(msg % hlen) | ||
except ValueError: | ||||
# default value | ||||
Augie Fackler
|
r43347 | if hconf == b'short' or hconf == b'': | ||
Yuya Nishihara
|
r38607 | hlen = 12 | ||
Augie Fackler
|
r43347 | elif hconf == b'full': | ||
Yuya Nishihara
|
r38607 | hlen = 40 | ||
Augie Fackler
|
r43347 | elif hconf != b'none': | ||
msg = _(b"invalid value for extendedheader.index: '%s'\n") | ||||
Yuya Nishihara
|
r38607 | ui.warn(msg % hconf) | ||
finally: | ||||
Augie Fackler
|
r43347 | buildopts[b'index'] = hlen | ||
Yuya Nishihara
|
r38607 | |||
if whitespace: | ||||
Augie Fackler
|
r43347 | buildopts[b'ignorews'] = get(b'ignore_all_space', b'ignorews') | ||
buildopts[b'ignorewsamount'] = get( | ||||
b'ignore_space_change', b'ignorewsamount' | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r43347 | buildopts[b'ignoreblanklines'] = get( | ||
b'ignore_blank_lines', b'ignoreblanklines' | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r43347 | buildopts[b'ignorewseol'] = get(b'ignore_space_at_eol', b'ignorewseol') | ||
Yuya Nishihara
|
r38607 | if formatchanging: | ||
Matt Harbison
|
r50793 | buildopts[b'text'] = None if opts is None else opts.get(b'text') | ||
Augie Fackler
|
r43347 | binary = None if opts is None else opts.get(b'binary') | ||
buildopts[b'nobinary'] = ( | ||||
Augie Fackler
|
r43346 | not binary | ||
if binary is not None | ||||
Augie Fackler
|
r43347 | else get(b'nobinary', forceplain=False) | ||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r43347 | buildopts[b'noprefix'] = get(b'noprefix', forceplain=False) | ||
buildopts[b'worddiff'] = get( | ||||
b'word_diff', b'word-diff', forceplain=False | ||||
) | ||||
Yuya Nishihara
|
r38607 | |||
return mdiff.diffopts(**pycompat.strkwargs(buildopts)) | ||||
pacien
|
r52036 | |||
def diff_parent(ctx): | ||||
"""get the context object to use as parent when diffing | ||||
If diff.merge is enabled, an overlayworkingctx of the auto-merged parents will be returned. | ||||
""" | ||||
repo = ctx.repo() | ||||
if repo.ui.configbool(b"diff", b"merge") and ctx.p2().rev() != nullrev: | ||||
# avoid circular import | ||||
from . import ( | ||||
context, | ||||
merge, | ||||
) | ||||
wctx = context.overlayworkingctx(repo) | ||||
wctx.setbase(ctx.p1()) | ||||
with repo.ui.configoverride( | ||||
{ | ||||
( | ||||
b"ui", | ||||
b"forcemerge", | ||||
): b"internal:merge3-lie-about-conflicts", | ||||
}, | ||||
b"merge-diff", | ||||
): | ||||
with repo.ui.silent(): | ||||
merge.merge(ctx.p2(), wc=wctx) | ||||
return wctx | ||||
else: | ||||
return ctx.p1() | ||||