D5094: merge-tools: when calling external merge tool, describe the resolve inputs
This revision was automatically updated to reflect the committed changes. Closed by commit rHG86dfae98a3a2: merge-tools: when calling external merge tool, describe the resolve inputs (authored by spectral, committed by ). CHANGED PRIOR TO COMMIT https://phab.mercurial-scm.org/D5094?vs=12369=12380#toc REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5094?vs=12369=12380 REVISION DETAIL https://phab.mercurial-scm.org/D5094 AFFECTED FILES mercurial/configitems.py mercurial/filemerge.py mercurial/help/config.txt tests/test-merge-tools.t CHANGE DETAILS diff --git a/tests/test-merge-tools.t b/tests/test-merge-tools.t --- a/tests/test-merge-tools.t +++ b/tests/test-merge-tools.t @@ -1946,6 +1946,25 @@ : 00 01 02 03 || $ hg merge --abort -q +Check that the extra information is printed correctly + + $ hg merge 9 \ + > --config merge-tools.testecho.executable='echo' \ + > --config merge-tools.testecho.args='merge runs here ...' \ + > --config merge-tools.testecho.binary=True \ + > --config ui.merge=testecho \ + > --config ui.pre-merge-tool-output-template='\n{label("extmerge.running_merge_tool", "Running merge tool for {path} ({toolpath}):")}\n{separate("\n", extmerge_section(local), extmerge_section(base), extmerge_section(other))}\n' \ + > --config 'templatealias.extmerge_section(sect)="- {pad("{sect.name} ({sect.label})", 20, left=True)}: {revset(sect.node)%"{rev}:{shortest(node,8)} {desc|firstline} {separate(" ", tags, bookmarks, branch)}"}"' + merging b + + Running merge tool for b (*/bin/echo): (glob) + - local (working copy): 10:2d1f533d add binary file (#2) tip default + - base (base): -1: default + -other (merge rev): 9:1e7ad7d7 add binary file (#1) default + merge runs here ... + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + Check that debugpicktool examines which merge tool is chosen for specified file as expected diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -2296,6 +2296,16 @@ On Windows, this configuration option is ignored and the command aborted. +``pre-merge-tool-output-template`` +A template that is printed before executing an external merge tool. This can +be used to print out additional context that might be useful to have during +the conflict resolution, such as the description of the various commits +involved or bookmarks/tags. + +Additional information is available in the ``local`, ``base``, and ``other`` +dicts. For example: ``{local.label}``, ``{base.name}``, or +``{other.islink}``. + ``quiet`` Reduce the amount of output printed. (default: False) diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -13,7 +13,11 @@ import shutil from .i18n import _ -from .node import nullid, short +from .node import ( +hex, +nullid, +short, +) from . import ( encoding, @@ -27,6 +31,7 @@ tagmerge, templatekw, templater, +templateutil, util, ) @@ -536,6 +541,44 @@ raise error.InMemoryMergeConflictsError('in-memory merge does not support ' 'external merge tools') +def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args): +tmpl = ui.config('ui', 'pre-merge-tool-output-template') +if not tmpl: +return + +mappingdict = templateutil.mappingdict +props = {'ctx': fcl.changectx(), + 'node': hex(mynode), + 'path': fcl.path(), + 'local': mappingdict({'ctx': fcl.changectx(), + 'fctx': fcl, + 'node': hex(mynode), + 'name': _('local'), + 'islink': 'l' in fcl.flags(), + 'label': env['HG_MY_LABEL']}), + 'base': mappingdict({'ctx': fcb.changectx(), + 'fctx': fcb, + 'name': _('base'), + 'islink': 'l' in fcb.flags(), + 'label': env['HG_BASE_LABEL']}), + 'other': mappingdict({'ctx': fco.changectx(), + 'fctx': fco, + 'name': _('other'), + 'islink': 'l' in fco.flags(), + 'label': env['HG_OTHER_LABEL']}), + 'toolpath': toolpath, + 'toolargs': args} + +# TODO: make all of this something that can be specified on a per-tool basis +tmpl = templater.unquotestring(tmpl) + +# Not using cmdutil.rendertemplate here since it causes errors
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
yuja added a comment. > > class mappingdict(mappable, _mappingsequence): > > """Wrapper for a single template mapping > > > > This isn't a sequence in a way that the underlying dict won't be iterated > > as a dict, but shares most of the _mappingsequence functions. > > """ > > > > def __init__(self, mapping, name=None, tmpl=None): > > super(mappingdict, self).__init__(name, tmpl) > > self._mapping = mapping > > > > def tomap(self, context): > > return self._mapping > > > > def tobool(self, context, mapping): > > # no idea when a template mapping should be considered an empty, but > > # a mapping dict should have at least one item in practice, so always > > # mark this as non-empty. > > return True > > > > def tovalue(self, context, mapping): > > return super(mappingdict, self).tovalue(context, mapping)[0] > > I copy/pasted this to https://phab.mercurial-scm.org/D5211. :) I sent my version with `{p1}/{p2}` example. You don't need to update this series. I'll queue it once my patches are accepted. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 To: spectral, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5094: merge-tools: when calling external merge tool, describe the resolve inputs
> > class mappingdict(mappable, _mappingsequence): > > """Wrapper for a single template mapping > > > > This isn't a sequence in a way that the underlying dict won't be > iterated > > as a dict, but shares most of the _mappingsequence functions. > > """ > > > > def __init__(self, mapping, name=None, tmpl=None): > > super(mappingdict, self).__init__(name, tmpl) > > self._mapping = mapping > > > > def tomap(self, context): > > return self._mapping > > > > def tobool(self, context, mapping): > > # no idea when a template mapping should be considered an > empty, but > > # a mapping dict should have at least one item in practice, so > always > > # mark this as non-empty. > > return True > > > > def tovalue(self, context, mapping): > > return super(mappingdict, self).tovalue(context, mapping)[0] > > I copy/pasted this to https://phab.mercurial-scm.org/D5211. :) I sent my version with `{p1}/{p2}` example. You don't need to update this series. I'll queue it once my patches are accepted. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
spectral added a comment. In https://phab.mercurial-scm.org/D5094#77146, @yuja wrote: > > > We might want to structure these variables as `base.node|short` instead of > > > `base_node` for example, but that would require more work. > > [...] > > > Unfortunately, this doesn't work super well, when using the following flags: > > There isn't a building block for a mapping dict holding mapping dicts, and > the formatter API doesn't support such structure either. > > Fortunately, we don't need a formatter here since we just want to apply > a template to a single item. So if we had a wrapper for a single mapping > dict, the templater can be rendered as follows: > > props = { > 'base': templateutil.mappingdict({'ctx': fca.changectx(), 'fctx': fca, > 'label': baselabel}) > ... > } > cmdutil.rendertemplate(fcd.changectx(), tmpl, props) > > > And `base.path`, `base.node`, etc. should just work. Done. > I'll post the dict wrapper if you like the idea. > > class mappingdict(mappable, _mappingsequence): > """Wrapper for a single template mapping > > This isn't a sequence in a way that the underlying dict won't be iterated > as a dict, but shares most of the _mappingsequence functions. > """ > > def __init__(self, mapping, name=None, tmpl=None): > super(mappingdict, self).__init__(name, tmpl) > self._mapping = mapping > > def tomap(self, context): > return self._mapping > > def tobool(self, context, mapping): > # no idea when a template mapping should be considered an empty, but > # a mapping dict should have at least one item in practice, so always > # mark this as non-empty. > return True > > def tovalue(self, context, mapping): > return super(mappingdict, self).tovalue(context, mapping)[0] I copy/pasted this to https://phab.mercurial-scm.org/D5211. :) REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 To: spectral, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
spectral updated this revision to Diff 12369. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5094?vs=12106=12369 REVISION DETAIL https://phab.mercurial-scm.org/D5094 AFFECTED FILES mercurial/configitems.py mercurial/filemerge.py mercurial/help/config.txt tests/test-merge-tools.t CHANGE DETAILS diff --git a/tests/test-merge-tools.t b/tests/test-merge-tools.t --- a/tests/test-merge-tools.t +++ b/tests/test-merge-tools.t @@ -1942,6 +1942,25 @@ : 00 01 02 03 || $ hg merge --abort -q +Check that the extra information is printed correctly + + $ hg merge 9 \ + > --config merge-tools.testecho.executable='echo' \ + > --config merge-tools.testecho.args='merge runs here ...' \ + > --config merge-tools.testecho.binary=True \ + > --config ui.merge=testecho \ + > --config ui.pre-merge-tool-output-template='\n{label("extmerge.running_merge_tool", "Running merge tool for {path} ({toolpath}):")}\n{separate("\n", extmerge_section(local), extmerge_section(base), extmerge_section(other))}\n' \ + > --config 'templatealias.extmerge_section(sect)="- {pad("{sect.name} ({sect.label})", 20, left=True)}: {revset(sect.node)%"{rev}:{shortest(node,8)} {desc|firstline} {separate(" ", tags, bookmarks, branch)}"}"' + merging b + + Running merge tool for b (/bin/echo): + - local (working copy): 10:2d1f533d add binary file (#2) tip default + - base (base): -1: default + -other (merge rev): 9:1e7ad7d7 add binary file (#1) default + merge runs here ... + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + Check that debugpicktool examines which merge tool is chosen for specified file as expected diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -2296,6 +2296,16 @@ On Windows, this configuration option is ignored and the command aborted. +``pre-merge-tool-output-template`` +A template that is printed before executing an external merge tool. This can +be used to print out additional context that might be useful to have during +the conflict resolution, such as the description of the various commits +involved or bookmarks/tags. + +Additional information is available in the ``local`, ``base``, and ``other`` +dicts. For example: ``{local.label}``, ``{base.name}``, or +``{other.islink}``. + ``quiet`` Reduce the amount of output printed. (default: False) diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -13,7 +13,11 @@ import shutil from .i18n import _ -from .node import nullid, short +from .node import ( +hex, +nullid, +short, +) from . import ( encoding, @@ -27,6 +31,7 @@ tagmerge, templatekw, templater, +templateutil, util, ) @@ -536,6 +541,45 @@ raise error.InMemoryMergeConflictsError('in-memory merge does not support ' 'external merge tools') +def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args): +tmpl = ui.config('ui', 'pre-merge-tool-output-template') +if not tmpl: +return + +mappingdict = templateutil.mappingdict +props = {'ctx': fcl.changectx(), + 'node': hex(mynode), + 'path': fcl.path(), + 'local': mappingdict({'ctx': fcl.changectx(), + 'fctx': fcl, + 'node': hex(mynode), + 'name': _('local'), + 'islink': 'l' in fcl.flags(), + 'label': env['HG_MY_LABEL']}), + 'base': mappingdict({'ctx': fcb.changectx(), + 'fctx': fcb, + 'name': _('base'), + 'islink': 'l' in fcb.flags(), + 'label': env['HG_BASE_LABEL']}), + 'other': mappingdict({'ctx': fco.changectx(), + 'fctx': fco, + 'name': _('other'), + 'islink': 'l' in fco.flags(), + 'label': env['HG_OTHER_LABEL']}), + 'toolpath': toolpath, + 'toolargs': args} + + +# TODO: make all of this something that can be specified on a per-tool basis +tmpl = templater.unquotestring(tmpl) + +# Not using cmdutil.rendertemplate here since it causes errors importing +# things for us to import cmdutil. +tres = formatter.templateresources(ui, repo) +t = formatter.maketemplater(ui, tmpl, defaults=templatekw.keywords, +resources=tres) +ui.status(t.renderdefault(props)) + def
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
yuja added a comment. > > We might want to structure these variables as `base.node|short` instead of > > `base_node` for example, but that would require more work. [...] > Unfortunately, this doesn't work super well, when using the following flags: There isn't a building block for a mapping dict holding mapping dicts, and the formatter API doesn't support such structure either. Fortunately, we don't need a formatter here since we just want to apply a template to a single item. So if we had a wrapper for a single mapping dict, the templater can be rendered as follows: props = { 'base': templateutil.mappingdict({'ctx': fca.changectx(), 'fctx': fca, 'label': baselabel}) ... } cmdutil.rendertemplate(fcd.changectx(), tmpl, props) And `base.path`, `base.node`, etc. should just work. I'll post the dict wrapper if you like the idea. class mappingdict(mappable, _mappingsequence): """Wrapper for a single template mapping This isn't a sequence in a way that the underlying dict won't be iterated as a dict, but shares most of the _mappingsequence functions. """ def __init__(self, mapping, name=None, tmpl=None): super(mappingdict, self).__init__(name, tmpl) self._mapping = mapping def tomap(self, context): return self._mapping def tobool(self, context, mapping): # no idea when a template mapping should be considered an empty, but # a mapping dict should have at least one item in practice, so always # mark this as non-empty. return True def tovalue(self, context, mapping): return super(mappingdict, self).tovalue(context, mapping)[0] REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 To: spectral, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5094: merge-tools: when calling external merge tool, describe the resolve inputs
> > We might want to structure these variables as `base.node|short` instead of > > `base_node` for example, but that would require more work. [...] > Unfortunately, this doesn't work super well, when using the following flags: There isn't a building block for a mapping dict holding mapping dicts, and the formatter API doesn't support such structure either. Fortunately, we don't need a formatter here since we just want to apply a template to a single item. So if we had a wrapper for a single mapping dict, the templater can be rendered as follows: ``` props = { 'base': templateutil.mappingdict({'ctx': fca.changectx(), 'fctx': fca, 'label': baselabel}) ... } cmdutil.rendertemplate(fcd.changectx(), tmpl, props) ``` And `base.path`, `base.node`, etc. should just work. I'll post the dict wrapper if you like the idea. ``` class mappingdict(mappable, _mappingsequence): """Wrapper for a single template mapping This isn't a sequence in a way that the underlying dict won't be iterated as a dict, but shares most of the _mappingsequence functions. """ def __init__(self, mapping, name=None, tmpl=None): super(mappingdict, self).__init__(name, tmpl) self._mapping = mapping def tomap(self, context): return self._mapping def tobool(self, context, mapping): # no idea when a template mapping should be considered an empty, but # a mapping dict should have at least one item in practice, so always # mark this as non-empty. return True def tovalue(self, context, mapping): return super(mappingdict, self).tovalue(context, mapping)[0] ``` ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
spectral planned changes to this revision. spectral added a comment. In https://phab.mercurial-scm.org/D5094#76457, @yuja wrote: > > +def _describemerge(ui, repo, env, toolpath, args): > > +template = ui.config('ui', 'pre-merge-tool-output-template') > > +if not template: > > +return > > + > > +# Remove HG_ prefix from entries in `env` and lowercase them > > +def sanitizeenv(k): > > +if k.startswith('HG_'): > > +return k[3:].lower() > > +return k > > Nit: `HG_FILE` should be called as `path` per > https://www.mercurial-scm.org/wiki/GenericTemplatingPlan#Dictionary Done. > We might want to structure these variables as `base.node|short` instead of > `base_node` for example, but that would require more work. I tried to do this, producing this json output: { "base": {"islink": false, "label": "base", "name": "base", "node": "TZ>fP͏~\u0019��%`��z3��)"}, "local": {"islink": false, "label": "working copy", "name": "local", "node": "ot���G-���Ò���xq���\u0001��o1c��"}, "other": {"islink": false, "label": "merge rev", "name": "other", "node": " ���`���\u0013s_\u0011��0��\u0002�K��"}, "path": "mercurial/dispatch.py", "toolargs": "/usr/local/google/home/spectral/src/hg/hg_work/mercurial/dispatch.py '/usr/local/google/tmp/tmp/dispatch~base.erx9yG.py' '/usr/local/google/tmp/tmp/dispatch~other.gbxRqg.py'", "toolpath": "/bin/false" } Unfortunately, this doesn't work super well, when using the following flags: --config ui.pre-merge-tool-output-template='{myfunc(local)}' --config 'templatealias.myfunc(d)="{d.label}"' I get this error: hg: parse error: {'node': 'ot\xc4G-\xd0\xc3\x92\xdcxq\x97\x01\x90\xdbo1c\xb1\x95', 'name': 'local', 'islink': False, 'label': 'working copy'} is not a dictionary (keyword 'local' does not support member operation) I can fix this with a pretty simple patch to templateutil's makewrapped, making it return hybriddict or hybridlist if it receives a dict or a list. I couldn't find any other similar ways of causing this error, though, so it's possible I'm doing something wrong? Things I tried: ≻ hg log -r . -T'{myfunc(dict(k1="hi", k2="bye"))}' --config 'templatealias.myfunc(d)="{d.k1}"' hi ≻ hg log -r . -T'{myfunc(namespaces)}' --config 'templatealias.myfunc(d)="{d.tags}"' tip I looked through all functions that accept 'formatteropts' and couldn't find any hg command that produces a dict that's *not* in a list. I also couldn't identify any way of interacting with these dicts-inside-of-lists as a single unit (i.e. `hg version -T'{extensions%"{extension|json}"}'` doesn't work: 'extension' isn't a way of referring to the dictionary that's in the 'extensions' list. I have to do something like `hg version -T'{extensions%dict(name, ver, bundled)|json)}'` to re-create the dictionary.) >> +data = {sanitizeenv(k): v for k, v in env.items()} >> +data['toolpath'] = toolpath >> +data['toolargs'] = args >> + >> +# TODO: make all of this something that can be specified on a per-tool basis >> +template = templater.unquotestring(template) >> + >> +fm = ui.formatter("extmerge", pycompat.byteskwargs({'template': template})) > > > > Unnecessary. It's bytes dict. Done. > > >> +fm.data(repo=repo, **data) > > ^^ > > Here pycompat.strkwargs() would be needed. Done. > And use `fm.context(repo=repo)` or `fm.context(fctx=fcd)` since `repo` is > unprintable. Done. Did both (fm.context(repo=repo, fctx=fcl)) > > >> +coreconfigitem('ui', 'pre-merge-tool-output-template', >> +default=None, >> +) > > Can you update the help/config.txt as well? Will do before sending final version (marking as 'changes planned' for now - I'm going to be unavailable for several days). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 To: spectral, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
yuja added a comment. > +def _describemerge(ui, repo, env, toolpath, args): > +template = ui.config('ui', 'pre-merge-tool-output-template') > +if not template: > +return > + > +# Remove HG_ prefix from entries in `env` and lowercase them > +def sanitizeenv(k): > +if k.startswith('HG_'): > +return k[3:].lower() > +return k Nit: `HG_FILE` should be called as `path` per https://www.mercurial-scm.org/wiki/GenericTemplatingPlan#Dictionary We might want to structure these variables as `base.node|short` instead of `base_node` for example, but that would require more work. > +data = {sanitizeenv(k): v for k, v in env.items()} > +data['toolpath'] = toolpath > +data['toolargs'] = args > + > +# TODO: make all of this something that can be specified on a per-tool basis > +template = templater.unquotestring(template) > + > +fm = ui.formatter("extmerge", pycompat.byteskwargs({'template': template})) Unnecessary. It's bytes dict. > +fm.data(repo=repo, **data) ^^ Here pycompat.strkwargs() would be needed. And use `fm.context(repo=repo)` or `fm.context(fctx=fcd)` since `repo` is unprintable. > +coreconfigitem('ui', 'pre-merge-tool-output-template', > +default=None, > +) Can you update the help/config.txt as well? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 To: spectral, #hg-reviewers Cc: yuja, mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D5094: merge-tools: when calling external merge tool, describe the resolve inputs
> +def _describemerge(ui, repo, env, toolpath, args): > +template = ui.config('ui', 'pre-merge-tool-output-template') > +if not template: > +return > + > +# Remove HG_ prefix from entries in `env` and lowercase them > +def sanitizeenv(k): > +if k.startswith('HG_'): > +return k[3:].lower() > +return k Nit: `HG_FILE` should be called as `path` per https://www.mercurial-scm.org/wiki/GenericTemplatingPlan#Dictionary We might want to structure these variables as `base.node|short` instead of `base_node` for example, but that would require more work. > +data = {sanitizeenv(k): v for k, v in env.items()} > +data['toolpath'] = toolpath > +data['toolargs'] = args > + > +# TODO: make all of this something that can be specified on a per-tool > basis > +template = templater.unquotestring(template) > + > +fm = ui.formatter("extmerge", pycompat.byteskwargs({'template': > template})) Unnecessary. It's bytes dict. > +fm.data(repo=repo, **data) ^^ Here pycompat.strkwargs() would be needed. And use `fm.context(repo=repo)` or `fm.context(fctx=fcd)` since `repo` is unprintable. > +coreconfigitem('ui', 'pre-merge-tool-output-template', > +default=None, > +) Can you update the help/config.txt as well? ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
spectral updated this revision to Diff 12106. Herald added a subscriber: mjpieters. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D5094?vs=12105=12106 REVISION DETAIL https://phab.mercurial-scm.org/D5094 AFFECTED FILES mercurial/configitems.py mercurial/filemerge.py tests/test-merge-tools.t CHANGE DETAILS diff --git a/tests/test-merge-tools.t b/tests/test-merge-tools.t --- a/tests/test-merge-tools.t +++ b/tests/test-merge-tools.t @@ -1942,6 +1942,25 @@ : 00 01 02 03 || $ hg merge --abort -q +Check that the extra information is printed correctly + + $ hg merge 9 \ + > --config merge-tools.testecho.executable='/bin/echo' \ + > --config merge-tools.testecho.args='merge runs here ...' \ + > --config merge-tools.testecho.binary=True \ + > --config ui.merge=testecho \ + > --config ui.pre-merge-tool-output-template='\n{label("extmerge.running_merge_tool", "Running merge tool for {file} ({toolpath}):")}\n{extmerge_section("local", my_label, my_node)}\n{extmerge_section("base", base_label, base_node)}\n{extmerge_section("other", other_label, other_node)}\n' \ + > --config 'templatealias.extmerge_section(name, label, node)="- {pad("{name} ({label})", 20, left=True)}: {revset(node)%"{rev}:{shortest(node,8)} {desc|firstline} {separate(tags, bookmarks, branch)}"}"' + merging b + + Running merge tool for b (/bin/echo): + - local (working copy): 10:2d1f533d add binary file (#2) default + - base (base): -1: default + -other (merge rev): 9:1e7ad7d7 add binary file (#1) default + merge runs here ... + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + Check that debugpicktool examines which merge tool is chosen for specified file as expected diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -536,6 +536,29 @@ raise error.InMemoryMergeConflictsError('in-memory merge does not support ' 'external merge tools') +def _describemerge(ui, repo, env, toolpath, args): +template = ui.config('ui', 'pre-merge-tool-output-template') +if not template: +return + +# Remove HG_ prefix from entries in `env` and lowercase them +def sanitizeenv(k): +if k.startswith('HG_'): +return k[3:].lower() +return k + +data = {sanitizeenv(k): v for k, v in env.items()} +data['toolpath'] = toolpath +data['toolargs'] = args + +# TODO: make all of this something that can be specified on a per-tool basis +template = templater.unquotestring(template) + +fm = ui.formatter("extmerge", pycompat.byteskwargs({'template': template})) +fm.startitem() +fm.data(repo=repo, **data) +fm.end() + def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None): tool, toolpath, binary, symlink, scriptfn = toolconf if fcd.isabsent() or fco.isabsent(): @@ -584,6 +607,7 @@ if scriptfn is None: cmd = toolpath + ' ' + args repo.ui.debug('launching merge tool: %s\n' % cmd) +_describemerge(ui, repo, env, toolpath, args) r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool') else: diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -1173,6 +1173,9 @@ coreconfigitem('ui', 'patch', default=None, ) +coreconfigitem('ui', 'pre-merge-tool-output-template', +default=None, +) coreconfigitem('ui', 'portablefilenames', default='warn', ) To: spectral, #hg-reviewers Cc: mjpieters, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D5094: merge-tools: when calling external merge tool, describe the resolve inputs
spectral created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY It is a common complaint that a user will be running some operation (histedit, rebase, evolve, etc.), get into a merge-conflict situation, and not understand what they are seeing - it is possible that the merge tool is configured to display the hash, but it's difficult for most merge tools to display a good snippet of the description. In the worst case, configuring this template will lead to output that is immediately covered by a terminal application, maybe the user can hit ctrl-z to see it. In the common case, the output will be in a terminal window and a GUI program will start, and it should be possible to view both the terminal and the GUI program at the same time. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D5094 AFFECTED FILES mercurial/filemerge.py CHANGE DETAILS diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -536,6 +536,27 @@ raise error.InMemoryMergeConflictsError('in-memory merge does not support ' 'external merge tools') +def _describemerge(ui, repo, env, toolpath, args): +template = ui.config('ui', 'pre-merge-tool-output-template') +if not template: +return + +# Remove HG_ prefix from entries in `env` and lowercase them +def sanitizeenv(k): +if k.startswith('HG_'): +return k[3:].lower() +return k + +data = {sanitizeenv(k): v for k, v in env.items()} + +# TODO: make all of this something that can be specified on a per-tool basis +template = templater.unquotestring(template) + +fm = ui.formatter("extmerge", pycompat.byteskwargs({'template': template})) +fm.startitem() +fm.data(repo=repo, **data) +fm.end() + def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None): tool, toolpath, binary, symlink, scriptfn = toolconf if fcd.isabsent() or fco.isabsent(): @@ -584,6 +605,7 @@ if scriptfn is None: cmd = toolpath + ' ' + args repo.ui.debug('launching merge tool: %s\n' % cmd) +_describemerge(ui, repo, env, toolpath, args) r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool') else: To: spectral, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel