##// END OF EJS Templates
configitems: register the 'ui.mergemarkertemplate' config
Boris Feld -
r33523:11025c4f default
parent child Browse files
Show More
@@ -1,578 +1,586 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import functools
11 11
12 12 from . import (
13 13 error,
14 14 )
15 15
16 16 def loadconfigtable(ui, extname, configtable):
17 17 """update config item known to the ui with the extension ones"""
18 18 for section, items in configtable.items():
19 19 knownitems = ui._knownconfig.setdefault(section, {})
20 20 knownkeys = set(knownitems)
21 21 newkeys = set(items)
22 22 for key in sorted(knownkeys & newkeys):
23 23 msg = "extension '%s' overwrite config item '%s.%s'"
24 24 msg %= (extname, section, key)
25 25 ui.develwarn(msg, config='warn-config')
26 26
27 27 knownitems.update(items)
28 28
29 29 class configitem(object):
30 30 """represent a known config item
31 31
32 32 :section: the official config section where to find this item,
33 33 :name: the official name within the section,
34 34 :default: default value for this item,
35 35 :alias: optional list of tuples as alternatives.
36 36 """
37 37
38 38 def __init__(self, section, name, default=None, alias=()):
39 39 self.section = section
40 40 self.name = name
41 41 self.default = default
42 42 self.alias = list(alias)
43 43
44 44 coreitems = {}
45 45
46 46 def _register(configtable, *args, **kwargs):
47 47 item = configitem(*args, **kwargs)
48 48 section = configtable.setdefault(item.section, {})
49 49 if item.name in section:
50 50 msg = "duplicated config item registration for '%s.%s'"
51 51 raise error.ProgrammingError(msg % (item.section, item.name))
52 52 section[item.name] = item
53 53
54 54 # special value for case where the default is derived from other values
55 55 dynamicdefault = object()
56 56
57 57 # Registering actual config items
58 58
59 59 def getitemregister(configtable):
60 60 return functools.partial(_register, configtable)
61 61
62 62 coreconfigitem = getitemregister(coreitems)
63 63
64 64 coreconfigitem('auth', 'cookiefile',
65 65 default=None,
66 66 )
67 67 # bookmarks.pushing: internal hack for discovery
68 68 coreconfigitem('bookmarks', 'pushing',
69 69 default=list,
70 70 )
71 71 # bundle.mainreporoot: internal hack for bundlerepo
72 72 coreconfigitem('bundle', 'mainreporoot',
73 73 default='',
74 74 )
75 75 # bundle.reorder: experimental config
76 76 coreconfigitem('bundle', 'reorder',
77 77 default='auto',
78 78 )
79 79 coreconfigitem('censor', 'policy',
80 80 default='abort',
81 81 )
82 82 coreconfigitem('chgserver', 'idletimeout',
83 83 default=3600,
84 84 )
85 85 coreconfigitem('chgserver', 'skiphash',
86 86 default=False,
87 87 )
88 88 coreconfigitem('cmdserver', 'log',
89 89 default=None,
90 90 )
91 91 coreconfigitem('color', 'mode',
92 92 default='auto',
93 93 )
94 94 coreconfigitem('color', 'pagermode',
95 95 default=dynamicdefault,
96 96 )
97 97 coreconfigitem('commands', 'status.relative',
98 98 default=False,
99 99 )
100 100 coreconfigitem('commands', 'update.requiredest',
101 101 default=False,
102 102 )
103 103 coreconfigitem('devel', 'all-warnings',
104 104 default=False,
105 105 )
106 106 coreconfigitem('devel', 'bundle2.debug',
107 107 default=False,
108 108 )
109 109 coreconfigitem('devel', 'check-locks',
110 110 default=False,
111 111 )
112 112 coreconfigitem('devel', 'check-relroot',
113 113 default=False,
114 114 )
115 115 coreconfigitem('devel', 'default-date',
116 116 default=None,
117 117 )
118 118 coreconfigitem('devel', 'deprec-warn',
119 119 default=False,
120 120 )
121 121 coreconfigitem('devel', 'disableloaddefaultcerts',
122 122 default=False,
123 123 )
124 124 coreconfigitem('devel', 'legacy.exchange',
125 125 default=list,
126 126 )
127 127 coreconfigitem('devel', 'servercafile',
128 128 default='',
129 129 )
130 130 coreconfigitem('devel', 'serverexactprotocol',
131 131 default='',
132 132 )
133 133 coreconfigitem('devel', 'serverrequirecert',
134 134 default=False,
135 135 )
136 136 coreconfigitem('devel', 'strip-obsmarkers',
137 137 default=True,
138 138 )
139 139 coreconfigitem('email', 'charsets',
140 140 default=list,
141 141 )
142 142 coreconfigitem('email', 'method',
143 143 default='smtp',
144 144 )
145 145 coreconfigitem('experimental', 'bundle-phases',
146 146 default=False,
147 147 )
148 148 coreconfigitem('experimental', 'bundle2-advertise',
149 149 default=True,
150 150 )
151 151 coreconfigitem('experimental', 'bundle2-output-capture',
152 152 default=False,
153 153 )
154 154 coreconfigitem('experimental', 'bundle2.pushback',
155 155 default=False,
156 156 )
157 157 coreconfigitem('experimental', 'bundle2lazylocking',
158 158 default=False,
159 159 )
160 160 coreconfigitem('experimental', 'bundlecomplevel',
161 161 default=None,
162 162 )
163 163 coreconfigitem('experimental', 'changegroup3',
164 164 default=False,
165 165 )
166 166 coreconfigitem('experimental', 'clientcompressionengines',
167 167 default=list,
168 168 )
169 169 coreconfigitem('experimental', 'crecordtest',
170 170 default=None,
171 171 )
172 172 coreconfigitem('experimental', 'disablecopytrace',
173 173 default=False,
174 174 )
175 175 coreconfigitem('experimental', 'editortmpinhg',
176 176 default=False,
177 177 )
178 178 coreconfigitem('experimental', 'evolution',
179 179 default=list,
180 180 )
181 181 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
182 182 default=False,
183 183 )
184 184 coreconfigitem('experimental', 'evolution.track-operation',
185 185 default=False,
186 186 )
187 187 coreconfigitem('experimental', 'exportableenviron',
188 188 default=list,
189 189 )
190 190 coreconfigitem('experimental', 'extendedheader.index',
191 191 default=None,
192 192 )
193 193 coreconfigitem('experimental', 'extendedheader.similarity',
194 194 default=False,
195 195 )
196 196 coreconfigitem('experimental', 'format.compression',
197 197 default='zlib',
198 198 )
199 199 coreconfigitem('experimental', 'graphshorten',
200 200 default=False,
201 201 )
202 202 coreconfigitem('experimental', 'hook-track-tags',
203 203 default=False,
204 204 )
205 205 coreconfigitem('experimental', 'httppostargs',
206 206 default=False,
207 207 )
208 208 coreconfigitem('experimental', 'manifestv2',
209 209 default=False,
210 210 )
211 211 coreconfigitem('experimental', 'mergedriver',
212 212 default=None,
213 213 )
214 214 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
215 215 default=False,
216 216 )
217 217 coreconfigitem('experimental', 'revertalternateinteractivemode',
218 218 default=True,
219 219 )
220 220 coreconfigitem('experimental', 'revlogv2',
221 221 default=None,
222 222 )
223 223 coreconfigitem('experimental', 'spacemovesdown',
224 224 default=False,
225 225 )
226 226 coreconfigitem('experimental', 'treemanifest',
227 227 default=False,
228 228 )
229 229 coreconfigitem('experimental', 'updatecheck',
230 230 default=None,
231 231 )
232 232 coreconfigitem('format', 'aggressivemergedeltas',
233 233 default=False,
234 234 )
235 235 coreconfigitem('format', 'chunkcachesize',
236 236 default=None,
237 237 )
238 238 coreconfigitem('format', 'dotencode',
239 239 default=True,
240 240 )
241 241 coreconfigitem('format', 'generaldelta',
242 242 default=False,
243 243 )
244 244 coreconfigitem('format', 'manifestcachesize',
245 245 default=None,
246 246 )
247 247 coreconfigitem('format', 'maxchainlen',
248 248 default=None,
249 249 )
250 250 coreconfigitem('format', 'obsstore-version',
251 251 default=None,
252 252 )
253 253 coreconfigitem('format', 'usefncache',
254 254 default=True,
255 255 )
256 256 coreconfigitem('format', 'usegeneraldelta',
257 257 default=True,
258 258 )
259 259 coreconfigitem('format', 'usestore',
260 260 default=True,
261 261 )
262 262 coreconfigitem('hostsecurity', 'ciphers',
263 263 default=None,
264 264 )
265 265 coreconfigitem('hostsecurity', 'disabletls10warning',
266 266 default=False,
267 267 )
268 268 coreconfigitem('http_proxy', 'always',
269 269 default=False,
270 270 )
271 271 coreconfigitem('http_proxy', 'host',
272 272 default=None,
273 273 )
274 274 coreconfigitem('http_proxy', 'no',
275 275 default=list,
276 276 )
277 277 coreconfigitem('http_proxy', 'passwd',
278 278 default=None,
279 279 )
280 280 coreconfigitem('http_proxy', 'user',
281 281 default=None,
282 282 )
283 283 coreconfigitem('merge', 'followcopies',
284 284 default=True,
285 285 )
286 286 coreconfigitem('pager', 'ignore',
287 287 default=list,
288 288 )
289 289 coreconfigitem('patch', 'eol',
290 290 default='strict',
291 291 )
292 292 coreconfigitem('patch', 'fuzz',
293 293 default=2,
294 294 )
295 295 coreconfigitem('paths', 'default',
296 296 default=None,
297 297 )
298 298 coreconfigitem('paths', 'default-push',
299 299 default=None,
300 300 )
301 301 coreconfigitem('phases', 'checksubrepos',
302 302 default='follow',
303 303 )
304 304 coreconfigitem('phases', 'publish',
305 305 default=True,
306 306 )
307 307 coreconfigitem('profiling', 'enabled',
308 308 default=False,
309 309 )
310 310 coreconfigitem('profiling', 'format',
311 311 default='text',
312 312 )
313 313 coreconfigitem('profiling', 'freq',
314 314 default=1000,
315 315 )
316 316 coreconfigitem('profiling', 'limit',
317 317 default=30,
318 318 )
319 319 coreconfigitem('profiling', 'nested',
320 320 default=0,
321 321 )
322 322 coreconfigitem('profiling', 'sort',
323 323 default='inlinetime',
324 324 )
325 325 coreconfigitem('profiling', 'statformat',
326 326 default='hotpath',
327 327 )
328 328 coreconfigitem('progress', 'assume-tty',
329 329 default=False,
330 330 )
331 331 coreconfigitem('progress', 'changedelay',
332 332 default=1,
333 333 )
334 334 coreconfigitem('progress', 'clear-complete',
335 335 default=True,
336 336 )
337 337 coreconfigitem('progress', 'debug',
338 338 default=False,
339 339 )
340 340 coreconfigitem('progress', 'delay',
341 341 default=3,
342 342 )
343 343 coreconfigitem('progress', 'disable',
344 344 default=False,
345 345 )
346 346 coreconfigitem('progress', 'estimate',
347 347 default=2,
348 348 )
349 349 coreconfigitem('progress', 'refresh',
350 350 default=0.1,
351 351 )
352 352 coreconfigitem('progress', 'width',
353 353 default=dynamicdefault,
354 354 )
355 355 coreconfigitem('server', 'bundle1',
356 356 default=True,
357 357 )
358 358 coreconfigitem('server', 'bundle1gd',
359 359 default=None,
360 360 )
361 361 coreconfigitem('server', 'compressionengines',
362 362 default=list,
363 363 )
364 364 coreconfigitem('server', 'concurrent-push-mode',
365 365 default='strict',
366 366 )
367 367 coreconfigitem('server', 'disablefullbundle',
368 368 default=False,
369 369 )
370 370 coreconfigitem('server', 'maxhttpheaderlen',
371 371 default=1024,
372 372 )
373 373 coreconfigitem('server', 'preferuncompressed',
374 374 default=False,
375 375 )
376 376 coreconfigitem('server', 'uncompressed',
377 377 default=True,
378 378 )
379 379 coreconfigitem('server', 'uncompressedallowsecret',
380 380 default=False,
381 381 )
382 382 coreconfigitem('server', 'validate',
383 383 default=False,
384 384 )
385 385 coreconfigitem('server', 'zliblevel',
386 386 default=-1,
387 387 )
388 388 coreconfigitem('smtp', 'host',
389 389 default=None,
390 390 )
391 391 coreconfigitem('smtp', 'local_hostname',
392 392 default=None,
393 393 )
394 394 coreconfigitem('smtp', 'password',
395 395 default=None,
396 396 )
397 397 coreconfigitem('smtp', 'tls',
398 398 default='none',
399 399 )
400 400 coreconfigitem('smtp', 'username',
401 401 default=None,
402 402 )
403 403 coreconfigitem('sparse', 'missingwarning',
404 404 default=True,
405 405 )
406 406 coreconfigitem('trusted', 'groups',
407 407 default=list,
408 408 )
409 409 coreconfigitem('trusted', 'users',
410 410 default=list,
411 411 )
412 412 coreconfigitem('ui', '_usedassubrepo',
413 413 default=False,
414 414 )
415 415 coreconfigitem('ui', 'allowemptycommit',
416 416 default=False,
417 417 )
418 418 coreconfigitem('ui', 'archivemeta',
419 419 default=True,
420 420 )
421 421 coreconfigitem('ui', 'askusername',
422 422 default=False,
423 423 )
424 424 coreconfigitem('ui', 'clonebundlefallback',
425 425 default=False,
426 426 )
427 427 coreconfigitem('ui', 'clonebundleprefers',
428 428 default=list,
429 429 )
430 430 coreconfigitem('ui', 'clonebundles',
431 431 default=True,
432 432 )
433 433 coreconfigitem('ui', 'color',
434 434 default='auto',
435 435 )
436 436 coreconfigitem('ui', 'commitsubrepos',
437 437 default=False,
438 438 )
439 439 coreconfigitem('ui', 'debug',
440 440 default=False,
441 441 )
442 442 coreconfigitem('ui', 'debugger',
443 443 default=None,
444 444 )
445 445 coreconfigitem('ui', 'fallbackencoding',
446 446 default=None,
447 447 )
448 448 coreconfigitem('ui', 'forcecwd',
449 449 default=None,
450 450 )
451 451 coreconfigitem('ui', 'forcemerge',
452 452 default=None,
453 453 )
454 454 coreconfigitem('ui', 'formatdebug',
455 455 default=False,
456 456 )
457 457 coreconfigitem('ui', 'formatjson',
458 458 default=False,
459 459 )
460 460 coreconfigitem('ui', 'formatted',
461 461 default=None,
462 462 )
463 463 coreconfigitem('ui', 'graphnodetemplate',
464 464 default=None,
465 465 )
466 466 coreconfigitem('ui', 'http2debuglevel',
467 467 default=None,
468 468 )
469 469 coreconfigitem('ui', 'interactive',
470 470 default=None,
471 471 )
472 472 coreconfigitem('ui', 'interface',
473 473 default=None,
474 474 )
475 475 coreconfigitem('ui', 'logblockedtimes',
476 476 default=False,
477 477 )
478 478 coreconfigitem('ui', 'logtemplate',
479 479 default=None,
480 480 )
481 481 coreconfigitem('ui', 'merge',
482 482 default=None,
483 483 )
484 484 coreconfigitem('ui', 'mergemarkers',
485 485 default='basic',
486 486 )
487 coreconfigitem('ui', 'mergemarkertemplate',
488 default=('{node|short} '
489 '{ifeq(tags, "tip", "", '
490 'ifeq(tags, "", "", "{tags} "))}'
491 '{if(bookmarks, "{bookmarks} ")}'
492 '{ifeq(branch, "default", "", "{branch} ")}'
493 '- {author|user}: {desc|firstline}')
494 )
487 495 coreconfigitem('ui', 'nontty',
488 496 default=False,
489 497 )
490 498 coreconfigitem('ui', 'origbackuppath',
491 499 default=None,
492 500 )
493 501 coreconfigitem('ui', 'paginate',
494 502 default=True,
495 503 )
496 504 coreconfigitem('ui', 'patch',
497 505 default=None,
498 506 )
499 507 coreconfigitem('ui', 'portablefilenames',
500 508 default='warn',
501 509 )
502 510 coreconfigitem('ui', 'promptecho',
503 511 default=False,
504 512 )
505 513 coreconfigitem('ui', 'quiet',
506 514 default=False,
507 515 )
508 516 coreconfigitem('ui', 'quietbookmarkmove',
509 517 default=False,
510 518 )
511 519 coreconfigitem('ui', 'remotecmd',
512 520 default='hg',
513 521 )
514 522 coreconfigitem('ui', 'report_untrusted',
515 523 default=True,
516 524 )
517 525 coreconfigitem('ui', 'rollback',
518 526 default=True,
519 527 )
520 528 coreconfigitem('ui', 'slash',
521 529 default=False,
522 530 )
523 531 coreconfigitem('ui', 'ssh',
524 532 default='ssh',
525 533 )
526 534 coreconfigitem('ui', 'statuscopies',
527 535 default=False,
528 536 )
529 537 coreconfigitem('ui', 'strict',
530 538 default=False,
531 539 )
532 540 coreconfigitem('ui', 'style',
533 541 default='',
534 542 )
535 543 coreconfigitem('ui', 'supportcontact',
536 544 default=None,
537 545 )
538 546 coreconfigitem('ui', 'textwidth',
539 547 default=78,
540 548 )
541 549 coreconfigitem('ui', 'timeout',
542 550 default='600',
543 551 )
544 552 coreconfigitem('ui', 'traceback',
545 553 default=False,
546 554 )
547 555 coreconfigitem('ui', 'tweakdefaults',
548 556 default=False,
549 557 )
550 558 coreconfigitem('ui', 'usehttp2',
551 559 default=False,
552 560 )
553 561 coreconfigitem('ui', 'username',
554 562 alias=[('ui', 'user')]
555 563 )
556 564 coreconfigitem('ui', 'verbose',
557 565 default=False,
558 566 )
559 567 coreconfigitem('verify', 'skipflags',
560 568 default=None,
561 569 )
562 570 coreconfigitem('worker', 'backgroundclose',
563 571 default=dynamicdefault,
564 572 )
565 573 # Windows defaults to a limit of 512 open files. A buffer of 128
566 574 # should give us enough headway.
567 575 coreconfigitem('worker', 'backgroundclosemaxqueue',
568 576 default=384,
569 577 )
570 578 coreconfigitem('worker', 'backgroundcloseminfilecount',
571 579 default=2048,
572 580 )
573 581 coreconfigitem('worker', 'backgroundclosethreadcount',
574 582 default=4,
575 583 )
576 584 coreconfigitem('worker', 'numcpus',
577 585 default=None,
578 586 )
@@ -1,754 +1,747 b''
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import filecmp
11 11 import os
12 12 import re
13 13 import tempfile
14 14
15 15 from .i18n import _
16 16 from .node import nullid, short
17 17
18 18 from . import (
19 19 encoding,
20 20 error,
21 21 formatter,
22 22 match,
23 23 pycompat,
24 24 scmutil,
25 25 simplemerge,
26 26 tagmerge,
27 27 templatekw,
28 28 templater,
29 29 util,
30 30 )
31 31
32 32 def _toolstr(ui, tool, part, default=""):
33 33 return ui.config("merge-tools", tool + "." + part, default)
34 34
35 35 def _toolbool(ui, tool, part, default=False):
36 36 return ui.configbool("merge-tools", tool + "." + part, default)
37 37
38 38 def _toollist(ui, tool, part, default=None):
39 39 if default is None:
40 40 default = []
41 41 return ui.configlist("merge-tools", tool + "." + part, default)
42 42
43 43 internals = {}
44 44 # Merge tools to document.
45 45 internalsdoc = {}
46 46
47 47 # internal tool merge types
48 48 nomerge = None
49 49 mergeonly = 'mergeonly' # just the full merge, no premerge
50 50 fullmerge = 'fullmerge' # both premerge and merge
51 51
52 52 _localchangedotherdeletedmsg = _(
53 53 "local%(l)s changed %(fd)s which other%(o)s deleted\n"
54 54 "use (c)hanged version, (d)elete, or leave (u)nresolved?"
55 55 "$$ &Changed $$ &Delete $$ &Unresolved")
56 56
57 57 _otherchangedlocaldeletedmsg = _(
58 58 "other%(o)s changed %(fd)s which local%(l)s deleted\n"
59 59 "use (c)hanged version, leave (d)eleted, or "
60 60 "leave (u)nresolved?"
61 61 "$$ &Changed $$ &Deleted $$ &Unresolved")
62 62
63 63 class absentfilectx(object):
64 64 """Represents a file that's ostensibly in a context but is actually not
65 65 present in it.
66 66
67 67 This is here because it's very specific to the filemerge code for now --
68 68 other code is likely going to break with the values this returns."""
69 69 def __init__(self, ctx, f):
70 70 self._ctx = ctx
71 71 self._f = f
72 72
73 73 def path(self):
74 74 return self._f
75 75
76 76 def size(self):
77 77 return None
78 78
79 79 def data(self):
80 80 return None
81 81
82 82 def filenode(self):
83 83 return nullid
84 84
85 85 _customcmp = True
86 86 def cmp(self, fctx):
87 87 """compare with other file context
88 88
89 89 returns True if different from fctx.
90 90 """
91 91 return not (fctx.isabsent() and
92 92 fctx.ctx() == self.ctx() and
93 93 fctx.path() == self.path())
94 94
95 95 def flags(self):
96 96 return ''
97 97
98 98 def changectx(self):
99 99 return self._ctx
100 100
101 101 def isbinary(self):
102 102 return False
103 103
104 104 def isabsent(self):
105 105 return True
106 106
107 107 def internaltool(name, mergetype, onfailure=None, precheck=None):
108 108 '''return a decorator for populating internal merge tool table'''
109 109 def decorator(func):
110 110 fullname = ':' + name
111 111 func.__doc__ = (pycompat.sysstr("``%s``\n" % fullname)
112 112 + func.__doc__.strip())
113 113 internals[fullname] = func
114 114 internals['internal:' + name] = func
115 115 internalsdoc[fullname] = func
116 116 func.mergetype = mergetype
117 117 func.onfailure = onfailure
118 118 func.precheck = precheck
119 119 return func
120 120 return decorator
121 121
122 122 def _findtool(ui, tool):
123 123 if tool in internals:
124 124 return tool
125 125 return findexternaltool(ui, tool)
126 126
127 127 def findexternaltool(ui, tool):
128 128 for kn in ("regkey", "regkeyalt"):
129 129 k = _toolstr(ui, tool, kn)
130 130 if not k:
131 131 continue
132 132 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
133 133 if p:
134 134 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
135 135 if p:
136 136 return p
137 137 exe = _toolstr(ui, tool, "executable", tool)
138 138 return util.findexe(util.expandpath(exe))
139 139
140 140 def _picktool(repo, ui, path, binary, symlink, changedelete):
141 141 def supportscd(tool):
142 142 return tool in internals and internals[tool].mergetype == nomerge
143 143
144 144 def check(tool, pat, symlink, binary, changedelete):
145 145 tmsg = tool
146 146 if pat:
147 147 tmsg = _("%s (for pattern %s)") % (tool, pat)
148 148 if not _findtool(ui, tool):
149 149 if pat: # explicitly requested tool deserves a warning
150 150 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
151 151 else: # configured but non-existing tools are more silent
152 152 ui.note(_("couldn't find merge tool %s\n") % tmsg)
153 153 elif symlink and not _toolbool(ui, tool, "symlink"):
154 154 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
155 155 elif binary and not _toolbool(ui, tool, "binary"):
156 156 ui.warn(_("tool %s can't handle binary\n") % tmsg)
157 157 elif changedelete and not supportscd(tool):
158 158 # the nomerge tools are the only tools that support change/delete
159 159 # conflicts
160 160 pass
161 161 elif not util.gui() and _toolbool(ui, tool, "gui"):
162 162 ui.warn(_("tool %s requires a GUI\n") % tmsg)
163 163 else:
164 164 return True
165 165 return False
166 166
167 167 # internal config: ui.forcemerge
168 168 # forcemerge comes from command line arguments, highest priority
169 169 force = ui.config('ui', 'forcemerge')
170 170 if force:
171 171 toolpath = _findtool(ui, force)
172 172 if changedelete and not supportscd(toolpath):
173 173 return ":prompt", None
174 174 else:
175 175 if toolpath:
176 176 return (force, util.shellquote(toolpath))
177 177 else:
178 178 # mimic HGMERGE if given tool not found
179 179 return (force, force)
180 180
181 181 # HGMERGE takes next precedence
182 182 hgmerge = encoding.environ.get("HGMERGE")
183 183 if hgmerge:
184 184 if changedelete and not supportscd(hgmerge):
185 185 return ":prompt", None
186 186 else:
187 187 return (hgmerge, hgmerge)
188 188
189 189 # then patterns
190 190 for pat, tool in ui.configitems("merge-patterns"):
191 191 mf = match.match(repo.root, '', [pat])
192 192 if mf(path) and check(tool, pat, symlink, False, changedelete):
193 193 toolpath = _findtool(ui, tool)
194 194 return (tool, util.shellquote(toolpath))
195 195
196 196 # then merge tools
197 197 tools = {}
198 198 disabled = set()
199 199 for k, v in ui.configitems("merge-tools"):
200 200 t = k.split('.')[0]
201 201 if t not in tools:
202 202 tools[t] = int(_toolstr(ui, t, "priority", "0"))
203 203 if _toolbool(ui, t, "disabled", False):
204 204 disabled.add(t)
205 205 names = tools.keys()
206 206 tools = sorted([(-p, tool) for tool, p in tools.items()
207 207 if tool not in disabled])
208 208 uimerge = ui.config("ui", "merge")
209 209 if uimerge:
210 210 # external tools defined in uimerge won't be able to handle
211 211 # change/delete conflicts
212 212 if uimerge not in names and not changedelete:
213 213 return (uimerge, uimerge)
214 214 tools.insert(0, (None, uimerge)) # highest priority
215 215 tools.append((None, "hgmerge")) # the old default, if found
216 216 for p, t in tools:
217 217 if check(t, None, symlink, binary, changedelete):
218 218 toolpath = _findtool(ui, t)
219 219 return (t, util.shellquote(toolpath))
220 220
221 221 # internal merge or prompt as last resort
222 222 if symlink or binary or changedelete:
223 223 if not changedelete and len(tools):
224 224 # any tool is rejected by capability for symlink or binary
225 225 ui.warn(_("no tool found to merge %s\n") % path)
226 226 return ":prompt", None
227 227 return ":merge", None
228 228
229 229 def _eoltype(data):
230 230 "Guess the EOL type of a file"
231 231 if '\0' in data: # binary
232 232 return None
233 233 if '\r\n' in data: # Windows
234 234 return '\r\n'
235 235 if '\r' in data: # Old Mac
236 236 return '\r'
237 237 if '\n' in data: # UNIX
238 238 return '\n'
239 239 return None # unknown
240 240
241 241 def _matcheol(file, origfile):
242 242 "Convert EOL markers in a file to match origfile"
243 243 tostyle = _eoltype(util.readfile(origfile))
244 244 if tostyle:
245 245 data = util.readfile(file)
246 246 style = _eoltype(data)
247 247 if style:
248 248 newdata = data.replace(style, tostyle)
249 249 if newdata != data:
250 250 util.writefile(file, newdata)
251 251
252 252 @internaltool('prompt', nomerge)
253 253 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
254 254 """Asks the user which of the local `p1()` or the other `p2()` version to
255 255 keep as the merged version."""
256 256 ui = repo.ui
257 257 fd = fcd.path()
258 258
259 259 prompts = partextras(labels)
260 260 prompts['fd'] = fd
261 261 try:
262 262 if fco.isabsent():
263 263 index = ui.promptchoice(
264 264 _localchangedotherdeletedmsg % prompts, 2)
265 265 choice = ['local', 'other', 'unresolved'][index]
266 266 elif fcd.isabsent():
267 267 index = ui.promptchoice(
268 268 _otherchangedlocaldeletedmsg % prompts, 2)
269 269 choice = ['other', 'local', 'unresolved'][index]
270 270 else:
271 271 index = ui.promptchoice(
272 272 _("keep (l)ocal%(l)s, take (o)ther%(o)s, or leave (u)nresolved"
273 273 " for %(fd)s?"
274 274 "$$ &Local $$ &Other $$ &Unresolved") % prompts, 2)
275 275 choice = ['local', 'other', 'unresolved'][index]
276 276
277 277 if choice == 'other':
278 278 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf,
279 279 labels)
280 280 elif choice == 'local':
281 281 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf,
282 282 labels)
283 283 elif choice == 'unresolved':
284 284 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf,
285 285 labels)
286 286 except error.ResponseExpected:
287 287 ui.write("\n")
288 288 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf,
289 289 labels)
290 290
291 291 @internaltool('local', nomerge)
292 292 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
293 293 """Uses the local `p1()` version of files as the merged version."""
294 294 return 0, fcd.isabsent()
295 295
296 296 @internaltool('other', nomerge)
297 297 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
298 298 """Uses the other `p2()` version of files as the merged version."""
299 299 if fco.isabsent():
300 300 # local changed, remote deleted -- 'deleted' picked
301 301 _underlyingfctxifabsent(fcd).remove()
302 302 deleted = True
303 303 else:
304 304 _underlyingfctxifabsent(fcd).write(fco.data(), fco.flags())
305 305 deleted = False
306 306 return 0, deleted
307 307
308 308 @internaltool('fail', nomerge)
309 309 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
310 310 """
311 311 Rather than attempting to merge files that were modified on both
312 312 branches, it marks them as unresolved. The resolve command must be
313 313 used to resolve these conflicts."""
314 314 # for change/delete conflicts write out the changed version, then fail
315 315 if fcd.isabsent():
316 316 _underlyingfctxifabsent(fcd).write(fco.data(), fco.flags())
317 317 return 1, False
318 318
319 319 def _underlyingfctxifabsent(filectx):
320 320 """Sometimes when resolving, our fcd is actually an absentfilectx, but
321 321 we want to write to it (to do the resolve). This helper returns the
322 322 underyling workingfilectx in that case.
323 323 """
324 324 if filectx.isabsent():
325 325 return filectx.changectx()[filectx.path()]
326 326 else:
327 327 return filectx
328 328
329 329 def _premerge(repo, fcd, fco, fca, toolconf, files, labels=None):
330 330 tool, toolpath, binary, symlink = toolconf
331 331 if symlink or fcd.isabsent() or fco.isabsent():
332 332 return 1
333 333 a, b, c, back = files
334 334
335 335 ui = repo.ui
336 336
337 337 validkeep = ['keep', 'keep-merge3']
338 338
339 339 # do we attempt to simplemerge first?
340 340 try:
341 341 premerge = _toolbool(ui, tool, "premerge", not binary)
342 342 except error.ConfigError:
343 343 premerge = _toolstr(ui, tool, "premerge").lower()
344 344 if premerge not in validkeep:
345 345 _valid = ', '.join(["'" + v + "'" for v in validkeep])
346 346 raise error.ConfigError(_("%s.premerge not valid "
347 347 "('%s' is neither boolean nor %s)") %
348 348 (tool, premerge, _valid))
349 349
350 350 if premerge:
351 351 if premerge == 'keep-merge3':
352 352 if not labels:
353 353 labels = _defaultconflictlabels
354 354 if len(labels) < 3:
355 355 labels.append('base')
356 356 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
357 357 if not r:
358 358 ui.debug(" premerge successful\n")
359 359 return 0
360 360 if premerge not in validkeep:
361 361 util.copyfile(back, a) # restore from backup and try again
362 362 return 1 # continue merging
363 363
364 364 def _mergecheck(repo, mynode, orig, fcd, fco, fca, toolconf):
365 365 tool, toolpath, binary, symlink = toolconf
366 366 if symlink:
367 367 repo.ui.warn(_('warning: internal %s cannot merge symlinks '
368 368 'for %s\n') % (tool, fcd.path()))
369 369 return False
370 370 if fcd.isabsent() or fco.isabsent():
371 371 repo.ui.warn(_('warning: internal %s cannot merge change/delete '
372 372 'conflict for %s\n') % (tool, fcd.path()))
373 373 return False
374 374 return True
375 375
376 376 def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
377 377 """
378 378 Uses the internal non-interactive simple merge algorithm for merging
379 379 files. It will fail if there are any conflicts and leave markers in
380 380 the partially merged file. Markers will have two sections, one for each side
381 381 of merge, unless mode equals 'union' which suppresses the markers."""
382 382 a, b, c, back = files
383 383
384 384 ui = repo.ui
385 385
386 386 r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
387 387 return True, r, False
388 388
389 389 @internaltool('union', fullmerge,
390 390 _("warning: conflicts while merging %s! "
391 391 "(edit, then use 'hg resolve --mark')\n"),
392 392 precheck=_mergecheck)
393 393 def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
394 394 """
395 395 Uses the internal non-interactive simple merge algorithm for merging
396 396 files. It will use both left and right sides for conflict regions.
397 397 No markers are inserted."""
398 398 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
399 399 files, labels, 'union')
400 400
401 401 @internaltool('merge', fullmerge,
402 402 _("warning: conflicts while merging %s! "
403 403 "(edit, then use 'hg resolve --mark')\n"),
404 404 precheck=_mergecheck)
405 405 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
406 406 """
407 407 Uses the internal non-interactive simple merge algorithm for merging
408 408 files. It will fail if there are any conflicts and leave markers in
409 409 the partially merged file. Markers will have two sections, one for each side
410 410 of merge."""
411 411 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
412 412 files, labels, 'merge')
413 413
414 414 @internaltool('merge3', fullmerge,
415 415 _("warning: conflicts while merging %s! "
416 416 "(edit, then use 'hg resolve --mark')\n"),
417 417 precheck=_mergecheck)
418 418 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
419 419 """
420 420 Uses the internal non-interactive simple merge algorithm for merging
421 421 files. It will fail if there are any conflicts and leave markers in
422 422 the partially merged file. Marker will have three sections, one from each
423 423 side of the merge and one for the base content."""
424 424 if not labels:
425 425 labels = _defaultconflictlabels
426 426 if len(labels) < 3:
427 427 labels.append('base')
428 428 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
429 429
430 430 def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
431 431 labels=None, localorother=None):
432 432 """
433 433 Generic driver for _imergelocal and _imergeother
434 434 """
435 435 assert localorother is not None
436 436 tool, toolpath, binary, symlink = toolconf
437 437 a, b, c, back = files
438 438 r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
439 439 localorother=localorother)
440 440 return True, r
441 441
442 442 @internaltool('merge-local', mergeonly, precheck=_mergecheck)
443 443 def _imergelocal(*args, **kwargs):
444 444 """
445 445 Like :merge, but resolve all conflicts non-interactively in favor
446 446 of the local `p1()` changes."""
447 447 success, status = _imergeauto(localorother='local', *args, **kwargs)
448 448 return success, status, False
449 449
450 450 @internaltool('merge-other', mergeonly, precheck=_mergecheck)
451 451 def _imergeother(*args, **kwargs):
452 452 """
453 453 Like :merge, but resolve all conflicts non-interactively in favor
454 454 of the other `p2()` changes."""
455 455 success, status = _imergeauto(localorother='other', *args, **kwargs)
456 456 return success, status, False
457 457
458 458 @internaltool('tagmerge', mergeonly,
459 459 _("automatic tag merging of %s failed! "
460 460 "(use 'hg resolve --tool :merge' or another merge "
461 461 "tool of your choice)\n"))
462 462 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
463 463 """
464 464 Uses the internal tag merge algorithm (experimental).
465 465 """
466 466 success, status = tagmerge.merge(repo, fcd, fco, fca)
467 467 return success, status, False
468 468
469 469 @internaltool('dump', fullmerge)
470 470 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
471 471 """
472 472 Creates three versions of the files to merge, containing the
473 473 contents of local, other and base. These files can then be used to
474 474 perform a merge manually. If the file to be merged is named
475 475 ``a.txt``, these files will accordingly be named ``a.txt.local``,
476 476 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
477 477 same directory as ``a.txt``.
478 478
479 479 This implies permerge. Therefore, files aren't dumped, if premerge
480 480 runs successfully. Use :forcedump to forcibly write files out.
481 481 """
482 482 a, b, c, back = files
483 483
484 484 fd = fcd.path()
485 485
486 486 util.copyfile(a, a + ".local")
487 487 repo.wwrite(fd + ".other", fco.data(), fco.flags())
488 488 repo.wwrite(fd + ".base", fca.data(), fca.flags())
489 489 return False, 1, False
490 490
491 491 @internaltool('forcedump', mergeonly)
492 492 def _forcedump(repo, mynode, orig, fcd, fco, fca, toolconf, files,
493 493 labels=None):
494 494 """
495 495 Creates three versions of the files as same as :dump, but omits premerge.
496 496 """
497 497 return _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files,
498 498 labels=labels)
499 499
500 500 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
501 501 tool, toolpath, binary, symlink = toolconf
502 502 if fcd.isabsent() or fco.isabsent():
503 503 repo.ui.warn(_('warning: %s cannot merge change/delete conflict '
504 504 'for %s\n') % (tool, fcd.path()))
505 505 return False, 1, None
506 506 a, b, c, back = files
507 507 out = ""
508 508 env = {'HG_FILE': fcd.path(),
509 509 'HG_MY_NODE': short(mynode),
510 510 'HG_OTHER_NODE': str(fco.changectx()),
511 511 'HG_BASE_NODE': str(fca.changectx()),
512 512 'HG_MY_ISLINK': 'l' in fcd.flags(),
513 513 'HG_OTHER_ISLINK': 'l' in fco.flags(),
514 514 'HG_BASE_ISLINK': 'l' in fca.flags(),
515 515 }
516 516
517 517 ui = repo.ui
518 518
519 519 args = _toolstr(ui, tool, "args", '$local $base $other')
520 520 if "$output" in args:
521 521 out, a = a, back # read input from backup, write to original
522 522 replace = {'local': a, 'base': b, 'other': c, 'output': out}
523 523 args = util.interpolate(r'\$', replace, args,
524 524 lambda s: util.shellquote(util.localpath(s)))
525 525 cmd = toolpath + ' ' + args
526 526 if _toolbool(ui, tool, "gui"):
527 527 repo.ui.status(_('running merge tool %s for file %s\n') %
528 528 (tool, fcd.path()))
529 529 repo.ui.debug('launching merge tool: %s\n' % cmd)
530 530 r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool')
531 531 repo.ui.debug('merge tool returned: %s\n' % r)
532 532 return True, r, False
533 533
534 534 def _formatconflictmarker(repo, ctx, template, label, pad):
535 535 """Applies the given template to the ctx, prefixed by the label.
536 536
537 537 Pad is the minimum width of the label prefix, so that multiple markers
538 538 can have aligned templated parts.
539 539 """
540 540 if ctx.node() is None:
541 541 ctx = ctx.p1()
542 542
543 543 props = templatekw.keywords.copy()
544 544 props['templ'] = template
545 545 props['ctx'] = ctx
546 546 props['repo'] = repo
547 547 templateresult = template.render(props)
548 548
549 549 label = ('%s:' % label).ljust(pad + 1)
550 550 mark = '%s %s' % (label, templateresult)
551 551
552 552 if mark:
553 553 mark = mark.splitlines()[0] # split for safety
554 554
555 555 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
556 556 return util.ellipsis(mark, 80 - 8)
557 557
558 _defaultconflictmarker = ('{node|short} '
559 '{ifeq(tags, "tip", "", '
560 'ifeq(tags, "", "", "{tags} "))}'
561 '{if(bookmarks, "{bookmarks} ")}'
562 '{ifeq(branch, "default", "", "{branch} ")}'
563 '- {author|user}: {desc|firstline}')
564
565 558 _defaultconflictlabels = ['local', 'other']
566 559
567 560 def _formatlabels(repo, fcd, fco, fca, labels):
568 561 """Formats the given labels using the conflict marker template.
569 562
570 563 Returns a list of formatted labels.
571 564 """
572 565 cd = fcd.changectx()
573 566 co = fco.changectx()
574 567 ca = fca.changectx()
575 568
576 569 ui = repo.ui
577 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
570 template = ui.config('ui', 'mergemarkertemplate')
578 571 template = templater.unquotestring(template)
579 572 tmpl = formatter.maketemplater(ui, template)
580 573
581 574 pad = max(len(l) for l in labels)
582 575
583 576 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
584 577 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
585 578 if len(labels) > 2:
586 579 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
587 580 return newlabels
588 581
589 582 def partextras(labels):
590 583 """Return a dictionary of extra labels for use in prompts to the user
591 584
592 585 Intended use is in strings of the form "(l)ocal%(l)s".
593 586 """
594 587 if labels is None:
595 588 return {
596 589 "l": "",
597 590 "o": "",
598 591 }
599 592
600 593 return {
601 594 "l": " [%s]" % labels[0],
602 595 "o": " [%s]" % labels[1],
603 596 }
604 597
605 598 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None):
606 599 """perform a 3-way merge in the working directory
607 600
608 601 premerge = whether this is a premerge
609 602 mynode = parent node before merge
610 603 orig = original local filename before merge
611 604 fco = other file context
612 605 fca = ancestor file context
613 606 fcd = local file context for current/destination file
614 607
615 608 Returns whether the merge is complete, the return value of the merge, and
616 609 a boolean indicating whether the file was deleted from disk."""
617 610
618 611 def temp(prefix, ctx):
619 612 fullbase, ext = os.path.splitext(ctx.path())
620 613 pre = "%s~%s." % (os.path.basename(fullbase), prefix)
621 614 (fd, name) = tempfile.mkstemp(prefix=pre, suffix=ext)
622 615 data = repo.wwritedata(ctx.path(), ctx.data())
623 616 f = os.fdopen(fd, pycompat.sysstr("wb"))
624 617 f.write(data)
625 618 f.close()
626 619 return name
627 620
628 621 if not fco.cmp(fcd): # files identical?
629 622 return True, None, False
630 623
631 624 ui = repo.ui
632 625 fd = fcd.path()
633 626 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
634 627 symlink = 'l' in fcd.flags() + fco.flags()
635 628 changedelete = fcd.isabsent() or fco.isabsent()
636 629 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
637 630 if tool in internals and tool.startswith('internal:'):
638 631 # normalize to new-style names (':merge' etc)
639 632 tool = tool[len('internal'):]
640 633 ui.debug("picked tool '%s' for %s (binary %s symlink %s changedelete %s)\n"
641 634 % (tool, fd, pycompat.bytestr(binary), pycompat.bytestr(symlink),
642 635 pycompat.bytestr(changedelete)))
643 636
644 637 if tool in internals:
645 638 func = internals[tool]
646 639 mergetype = func.mergetype
647 640 onfailure = func.onfailure
648 641 precheck = func.precheck
649 642 else:
650 643 func = _xmerge
651 644 mergetype = fullmerge
652 645 onfailure = _("merging %s failed!\n")
653 646 precheck = None
654 647
655 648 toolconf = tool, toolpath, binary, symlink
656 649
657 650 if mergetype == nomerge:
658 651 r, deleted = func(repo, mynode, orig, fcd, fco, fca, toolconf, labels)
659 652 return True, r, deleted
660 653
661 654 if premerge:
662 655 if orig != fco.path():
663 656 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
664 657 else:
665 658 ui.status(_("merging %s\n") % fd)
666 659
667 660 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
668 661
669 662 if precheck and not precheck(repo, mynode, orig, fcd, fco, fca,
670 663 toolconf):
671 664 if onfailure:
672 665 ui.warn(onfailure % fd)
673 666 return True, 1, False
674 667
675 668 a = repo.wjoin(fd)
676 669 b = temp("base", fca)
677 670 c = temp("other", fco)
678 671 if not fcd.isabsent():
679 672 back = scmutil.origpath(ui, repo, a)
680 673 if premerge:
681 674 util.copyfile(a, back)
682 675 else:
683 676 back = None
684 677 files = (a, b, c, back)
685 678
686 679 r = 1
687 680 try:
688 681 markerstyle = ui.config('ui', 'mergemarkers')
689 682 if not labels:
690 683 labels = _defaultconflictlabels
691 684 if markerstyle != 'basic':
692 685 labels = _formatlabels(repo, fcd, fco, fca, labels)
693 686
694 687 if premerge and mergetype == fullmerge:
695 688 r = _premerge(repo, fcd, fco, fca, toolconf, files, labels=labels)
696 689 # complete if premerge successful (r is 0)
697 690 return not r, r, False
698 691
699 692 needcheck, r, deleted = func(repo, mynode, orig, fcd, fco, fca,
700 693 toolconf, files, labels=labels)
701 694
702 695 if needcheck:
703 696 r = _check(r, ui, tool, fcd, files)
704 697
705 698 if r:
706 699 if onfailure:
707 700 ui.warn(onfailure % fd)
708 701
709 702 return True, r, deleted
710 703 finally:
711 704 if not r and back is not None:
712 705 util.unlink(back)
713 706 util.unlink(b)
714 707 util.unlink(c)
715 708
716 709 def _check(r, ui, tool, fcd, files):
717 710 fd = fcd.path()
718 711 a, b, c, back = files
719 712
720 713 if not r and (_toolbool(ui, tool, "checkconflicts") or
721 714 'conflicts' in _toollist(ui, tool, "check")):
722 715 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
723 716 re.MULTILINE):
724 717 r = 1
725 718
726 719 checked = False
727 720 if 'prompt' in _toollist(ui, tool, "check"):
728 721 checked = True
729 722 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
730 723 "$$ &Yes $$ &No") % fd, 1):
731 724 r = 1
732 725
733 726 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
734 727 'changed' in
735 728 _toollist(ui, tool, "check")):
736 729 if back is not None and filecmp.cmp(a, back):
737 730 if ui.promptchoice(_(" output file %s appears unchanged\n"
738 731 "was merge successful (yn)?"
739 732 "$$ &Yes $$ &No") % fd, 1):
740 733 r = 1
741 734
742 735 if back is not None and _toolbool(ui, tool, "fixeol"):
743 736 _matcheol(a, back)
744 737
745 738 return r
746 739
747 740 def premerge(repo, mynode, orig, fcd, fco, fca, labels=None):
748 741 return _filemerge(True, repo, mynode, orig, fcd, fco, fca, labels=labels)
749 742
750 743 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
751 744 return _filemerge(False, repo, mynode, orig, fcd, fco, fca, labels=labels)
752 745
753 746 # tell hggettext to extract docstrings from these functions:
754 747 i18nfunctions = internals.values()
General Comments 0
You need to be logged in to leave comments. Login now