Show More
@@ -59,6 +59,22 b' sections for diff tool arguments, when n' | |||
|
59 | 59 | [diff-tools] |
|
60 | 60 | kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child |
|
61 | 61 | |
|
62 | If a program has a graphical interface, it might be interesting to tell | |
|
63 | Mercurial about it. It will prevent the program from being mistakenly | |
|
64 | used in a terminal-only environment (such as an SSH terminal session), | |
|
65 | and will make :hg:`extdiff --per-file` open multiple file diffs at once | |
|
66 | instead of one by one (if you still want to open file diffs one by one, | |
|
67 | you can use the --confirm option). | |
|
68 | ||
|
69 | Declaring that a tool has a graphical interface can be done with the | |
|
70 | ``gui`` flag next to where ``diffargs`` are specified: | |
|
71 | ||
|
72 | :: | |
|
73 | ||
|
74 | [diff-tools] | |
|
75 | kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child | |
|
76 | kdiff3.gui = true | |
|
77 | ||
|
62 | 78 | You can use -I/-X and list of file or directory names like normal |
|
63 | 79 | :hg:`diff` command. The extdiff extension makes snapshots of only |
|
64 | 80 | needed files, so running the external diff program will actually be |
@@ -71,6 +87,7 b' import os' | |||
|
71 | 87 | import re |
|
72 | 88 | import shutil |
|
73 | 89 | import stat |
|
90 | import subprocess | |
|
74 | 91 | |
|
75 | 92 | from mercurial.i18n import _ |
|
76 | 93 | from mercurial.node import ( |
@@ -105,11 +122,19 b" configitem('extdiff', br'opts\\..*'," | |||
|
105 | 122 | generic=True, |
|
106 | 123 | ) |
|
107 | 124 | |
|
125 | configitem('extdiff', br'gui\..*', | |
|
126 | generic=True, | |
|
127 | ) | |
|
128 | ||
|
108 | 129 | configitem('diff-tools', br'.*\.diffargs$', |
|
109 | 130 | default=None, |
|
110 | 131 | generic=True, |
|
111 | 132 | ) |
|
112 | 133 | |
|
134 | configitem('diff-tools', br'.*\.gui$', | |
|
135 | generic=True, | |
|
136 | ) | |
|
137 | ||
|
113 | 138 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
114 | 139 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
115 | 140 | # be specifying the version(s) of Mercurial they are tested with, or |
@@ -176,13 +201,26 b' def formatcmdline(cmdline, repo_root, do' | |||
|
176 | 201 | cmdline += ' $parent1 $child' |
|
177 | 202 | return re.sub(regex, quote, cmdline) |
|
178 | 203 | |
|
179 | def _runperfilediff(cmdline, repo_root, ui, do3way, confirm, | |
|
204 | def _systembackground(cmd, environ=None, cwd=None): | |
|
205 | ''' like 'procutil.system', but returns the Popen object directly | |
|
206 | so we don't have to wait on it. | |
|
207 | ''' | |
|
208 | cmd = procutil.quotecommand(cmd) | |
|
209 | env = procutil.shellenviron(environ) | |
|
210 | proc = subprocess.Popen(procutil.tonativestr(cmd), | |
|
211 | shell=True, close_fds=procutil.closefds, | |
|
212 | env=procutil.tonativeenv(env), | |
|
213 | cwd=pycompat.rapply(procutil.tonativestr, cwd)) | |
|
214 | return proc | |
|
215 | ||
|
216 | def _runperfilediff(cmdline, repo_root, ui, guitool, do3way, confirm, | |
|
180 | 217 | commonfiles, tmproot, dir1a, dir1b, |
|
181 | 218 | dir2root, dir2, |
|
182 | 219 | rev1a, rev1b, rev2): |
|
183 | 220 | # Note that we need to sort the list of files because it was |
|
184 | 221 | # built in an "unstable" way and it's annoying to get files in a |
|
185 | 222 | # random order, especially when "confirm" mode is enabled. |
|
223 | waitprocs = [] | |
|
186 | 224 | totalfiles = len(commonfiles) |
|
187 | 225 | for idx, commonfile in enumerate(sorted(commonfiles)): |
|
188 | 226 | path1a = os.path.join(tmproot, dir1a, commonfile) |
@@ -228,14 +266,32 b' def _runperfilediff(cmdline, repo_root, ' | |||
|
228 | 266 | parent1=path1a, plabel1=label1a, |
|
229 | 267 | parent2=path1b, plabel2=label1b, |
|
230 | 268 | child=path2, clabel=label2) |
|
231 | ui.debug('running %r in %s\n' % (pycompat.bytestr(curcmdline), | |
|
232 | tmproot)) | |
|
233 | 269 | |
|
270 | if confirm or not guitool: | |
|
234 | 271 | # Run the comparison program and wait for it to exit |
|
235 | 272 | # before we show the next file. |
|
273 | # This is because either we need to wait for confirmation | |
|
274 | # from the user between each invocation, or because, as far | |
|
275 | # as we know, the tool doesn't have a GUI, in which case | |
|
276 | # we can't run multiple CLI programs at the same time. | |
|
277 | ui.debug('running %r in %s\n' % | |
|
278 | (pycompat.bytestr(curcmdline), tmproot)) | |
|
236 | 279 | ui.system(curcmdline, cwd=tmproot, blockedtag='extdiff') |
|
280 | else: | |
|
281 | # Run the comparison program but don't wait, as we're | |
|
282 | # going to rapid-fire each file diff and then wait on | |
|
283 | # the whole group. | |
|
284 | ui.debug('running %r in %s (backgrounded)\n' % | |
|
285 | (pycompat.bytestr(curcmdline), tmproot)) | |
|
286 | proc = _systembackground(curcmdline, cwd=tmproot) | |
|
287 | waitprocs.append(proc) | |
|
237 | 288 | |
|
238 | def dodiff(ui, repo, cmdline, pats, opts): | |
|
289 | if waitprocs: | |
|
290 | with ui.timeblockedsection('extdiff'): | |
|
291 | for proc in waitprocs: | |
|
292 | proc.wait() | |
|
293 | ||
|
294 | def dodiff(ui, repo, cmdline, pats, opts, guitool=False): | |
|
239 | 295 | '''Do the actual diff: |
|
240 | 296 | |
|
241 | 297 | - copy to a temp structure if diffing 2 internal revisions |
@@ -382,7 +438,8 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
382 | 438 | else: |
|
383 | 439 | # Run the external tool once for each pair of files |
|
384 | 440 | _runperfilediff( |
|
385 |
cmdline, repo.root, ui, |
|
|
441 | cmdline, repo.root, ui, guitool=guitool, | |
|
442 | do3way=do3way, confirm=confirm, | |
|
386 | 443 | commonfiles=common, tmproot=tmproot, dir1a=dir1a, dir1b=dir1b, |
|
387 | 444 | dir2root=dir2root, dir2=dir2, |
|
388 | 445 | rev1a=rev1a, rev1b=rev1b, rev2=rev2) |
@@ -446,7 +503,13 b' def extdiff(ui, repo, *pats, **opts):' | |||
|
446 | 503 | to its parent. |
|
447 | 504 | |
|
448 | 505 | The --per-file option runs the external program repeatedly on each |
|
449 | file to diff, instead of once on two directories. | |
|
506 | file to diff, instead of once on two directories. By default, | |
|
507 | this happens one by one, where the next file diff is open in the | |
|
508 | external program only once the previous external program (for the | |
|
509 | previous file diff) has exited. If the external program has a | |
|
510 | graphical interface, it can open all the file diffs at once instead | |
|
511 | of one by one. See :hg:`help -e extdiff` for information about how | |
|
512 | to tell Mercurial that a given program has a graphical interface. | |
|
450 | 513 | |
|
451 | 514 | The --confirm option will prompt the user before each invocation of |
|
452 | 515 | the external program. It is ignored if --per-file isn't specified. |
@@ -475,20 +538,22 b' class savedcmd(object):' | |||
|
475 | 538 | to its parent. |
|
476 | 539 | """ |
|
477 | 540 | |
|
478 | def __init__(self, path, cmdline): | |
|
541 | def __init__(self, path, cmdline, isgui): | |
|
479 | 542 | # We can't pass non-ASCII through docstrings (and path is |
|
480 | 543 | # in an unknown encoding anyway), but avoid double separators on |
|
481 | 544 | # Windows |
|
482 | 545 | docpath = stringutil.escapestr(path).replace(b'\\\\', b'\\') |
|
483 | 546 | self.__doc__ %= {r'path': pycompat.sysstr(stringutil.uirepr(docpath))} |
|
484 | 547 | self._cmdline = cmdline |
|
548 | self._isgui = isgui | |
|
485 | 549 | |
|
486 | 550 | def __call__(self, ui, repo, *pats, **opts): |
|
487 | 551 | opts = pycompat.byteskwargs(opts) |
|
488 | 552 | options = ' '.join(map(procutil.shellquote, opts['option'])) |
|
489 | 553 | if options: |
|
490 | 554 | options = ' ' + options |
|
491 |
return dodiff(ui, repo, self._cmdline + options, pats, opts |
|
|
555 | return dodiff(ui, repo, self._cmdline + options, pats, opts, | |
|
556 | guitool=self._isgui) | |
|
492 | 557 | |
|
493 | 558 | def uisetup(ui): |
|
494 | 559 | for cmd, path in ui.configitems('extdiff'): |
@@ -503,7 +568,8 b' def uisetup(ui):' | |||
|
503 | 568 | cmdline = procutil.shellquote(path) |
|
504 | 569 | if diffopts: |
|
505 | 570 | cmdline += ' ' + diffopts |
|
506 | elif cmd.startswith('opts.'): | |
|
571 | isgui = ui.configbool('extdiff', 'gui.' + cmd) | |
|
572 | elif cmd.startswith('opts.') or cmd.startswith('gui.'): | |
|
507 | 573 | continue |
|
508 | 574 | else: |
|
509 | 575 | if path: |
@@ -517,15 +583,20 b' def uisetup(ui):' | |||
|
517 | 583 | path = filemerge.findexternaltool(ui, cmd) or cmd |
|
518 | 584 | cmdline = procutil.shellquote(path) |
|
519 | 585 | diffopts = False |
|
586 | isgui = ui.configbool('extdiff', 'gui.' + cmd) | |
|
520 | 587 | # look for diff arguments in [diff-tools] then [merge-tools] |
|
521 | 588 | if not diffopts: |
|
522 |
|
|
|
523 | ui.config('merge-tools', cmd+'.diffargs') | |
|
589 | key = cmd + '.diffargs' | |
|
590 | for section in ('diff-tools', 'merge-tools'): | |
|
591 | args = ui.config(section, key) | |
|
524 | 592 | if args: |
|
525 | 593 | cmdline += ' ' + args |
|
594 | if isgui is None: | |
|
595 | isgui = ui.configbool(section, cmd + '.gui') or False | |
|
596 | break | |
|
526 | 597 | command(cmd, extdiffopts[:], _('hg %s [OPTION]... [FILE]...') % cmd, |
|
527 | 598 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
528 | inferrepo=True)(savedcmd(path, cmdline)) | |
|
599 | inferrepo=True)(savedcmd(path, cmdline, isgui)) | |
|
529 | 600 | |
|
530 | 601 | # tell hggettext to extract docstrings from these functions: |
|
531 | 602 | i18nfunctions = [savedcmd] |
@@ -22,6 +22,10 b' Should diff cloned directories:' | |||
|
22 | 22 | > opts.falabala = diffing |
|
23 | 23 | > cmd.edspace = echo |
|
24 | 24 | > opts.edspace = "name <user@example.com>" |
|
25 | > alabalaf = | |
|
26 | > [merge-tools] | |
|
27 | > alabalaf.executable = echo | |
|
28 | > alabalaf.diffargs = diffing | |
|
25 | 29 | > EOF |
|
26 | 30 | |
|
27 | 31 | $ hg falabala |
@@ -144,6 +148,42 b' Test --per-file option:' | |||
|
144 | 148 | diffing */extdiff.*/a.46c0e4daeb72/b a.81906f2b98ac/b (glob) (no-windows !) |
|
145 | 149 | [1] |
|
146 | 150 | |
|
151 | Test --per-file option for gui tool: | |
|
152 | ||
|
153 | $ hg --config extdiff.gui.alabalaf=True alabalaf -c 6 --per-file --debug | |
|
154 | diffing "*\\extdiff.*\\a.46c0e4daeb72\\a" "a.81906f2b98ac\\a" (glob) (windows !) | |
|
155 | diffing */extdiff.*/a.46c0e4daeb72/a a.81906f2b98ac/a (glob) (no-windows !) | |
|
156 | diffing "*\\extdiff.*\\a.46c0e4daeb72\\b" "a.81906f2b98ac\\b" (glob) (windows !) | |
|
157 | diffing */extdiff.*/a.46c0e4daeb72/b a.81906f2b98ac/b (glob) (no-windows !) | |
|
158 | making snapshot of 2 files from rev 46c0e4daeb72 | |
|
159 | a | |
|
160 | b | |
|
161 | making snapshot of 2 files from rev 81906f2b98ac | |
|
162 | a | |
|
163 | b | |
|
164 | running '* diffing * *' in * (backgrounded) (glob) | |
|
165 | running '* diffing * *' in * (backgrounded) (glob) | |
|
166 | cleaning up temp directory | |
|
167 | [1] | |
|
168 | ||
|
169 | Test --per-file option for gui tool again: | |
|
170 | ||
|
171 | $ hg --config merge-tools.alabalaf.gui=True alabalaf -c 6 --per-file --debug | |
|
172 | diffing "*\\extdiff.*\\a.46c0e4daeb72\\a" "a.81906f2b98ac\\a" (glob) (windows !) | |
|
173 | diffing */extdiff.*/a.46c0e4daeb72/a a.81906f2b98ac/a (glob) (no-windows !) | |
|
174 | diffing "*\\extdiff.*\\a.46c0e4daeb72\\b" "a.81906f2b98ac\\b" (glob) (windows !) | |
|
175 | diffing */extdiff.*/a.46c0e4daeb72/b a.81906f2b98ac/b (glob) (no-windows !) | |
|
176 | making snapshot of 2 files from rev 46c0e4daeb72 | |
|
177 | a | |
|
178 | b | |
|
179 | making snapshot of 2 files from rev 81906f2b98ac | |
|
180 | a | |
|
181 | b | |
|
182 | running '* diffing * *' in * (backgrounded) (glob) | |
|
183 | running '* diffing * *' in * (backgrounded) (glob) | |
|
184 | cleaning up temp directory | |
|
185 | [1] | |
|
186 | ||
|
147 | 187 | Test --per-file and --confirm options: |
|
148 | 188 | |
|
149 | 189 | $ hg --config ui.interactive=True falabala -c 6 --per-file --confirm <<EOF |
@@ -823,7 +823,13 b' Extension module help vs command help:' | |||
|
823 | 823 | the working directory files are compared to its parent. |
|
824 | 824 | |
|
825 | 825 | The --per-file option runs the external program repeatedly on each file to |
|
826 | diff, instead of once on two directories. | |
|
826 | diff, instead of once on two directories. By default, this happens one by | |
|
827 | one, where the next file diff is open in the external program only once | |
|
828 | the previous external program (for the previous file diff) has exited. If | |
|
829 | the external program has a graphical interface, it can open all the file | |
|
830 | diffs at once instead of one by one. See 'hg help -e extdiff' for | |
|
831 | information about how to tell Mercurial that a given program has a | |
|
832 | graphical interface. | |
|
827 | 833 | |
|
828 | 834 | The --confirm option will prompt the user before each invocation of the |
|
829 | 835 | external program. It is ignored if --per-file isn't specified. |
@@ -905,6 +911,20 b' Extension module help vs command help:' | |||
|
905 | 911 | [diff-tools] |
|
906 | 912 | kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child |
|
907 | 913 | |
|
914 | If a program has a graphical interface, it might be interesting to tell | |
|
915 | Mercurial about it. It will prevent the program from being mistakenly used in | |
|
916 | a terminal-only environment (such as an SSH terminal session), and will make | |
|
917 | 'hg extdiff --per-file' open multiple file diffs at once instead of one by one | |
|
918 | (if you still want to open file diffs one by one, you can use the --confirm | |
|
919 | option). | |
|
920 | ||
|
921 | Declaring that a tool has a graphical interface can be done with the "gui" | |
|
922 | flag next to where "diffargs" are specified: | |
|
923 | ||
|
924 | [diff-tools] | |
|
925 | kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child | |
|
926 | kdiff3.gui = true | |
|
927 | ||
|
908 | 928 | You can use -I/-X and list of file or directory names like normal 'hg diff' |
|
909 | 929 | command. The extdiff extension makes snapshots of only needed files, so |
|
910 | 930 | running the external diff program will actually be pretty fast (at least |
General Comments 0
You need to be logged in to leave comments.
Login now