##// END OF EJS Templates
ui.prompt: Show prompt and selection in non-interactive mode...
Mads Kiilerich -
r8940:01ada7b1 default
parent child Browse files
Show More
@@ -1,346 +1,346 b''
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005-2007 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, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, socket, sys, tempfile, traceback
10 10 import config, util, error
11 11
12 12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
13 13 '0': False, 'no': False, 'false': False, 'off': False}
14 14
15 15 class ui(object):
16 16 def __init__(self, src=None):
17 17 self._buffers = []
18 18 self.quiet = self.verbose = self.debugflag = self._traceback = False
19 19 self._reportuntrusted = True
20 20 self._ocfg = config.config() # overlay
21 21 self._tcfg = config.config() # trusted
22 22 self._ucfg = config.config() # untrusted
23 23 self._trustusers = set()
24 24 self._trustgroups = set()
25 25
26 26 if src:
27 27 self._tcfg = src._tcfg.copy()
28 28 self._ucfg = src._ucfg.copy()
29 29 self._ocfg = src._ocfg.copy()
30 30 self._trustusers = src._trustusers.copy()
31 31 self._trustgroups = src._trustgroups.copy()
32 32 self.fixconfig()
33 33 else:
34 34 # we always trust global config files
35 35 for f in util.rcpath():
36 36 self.readconfig(f, trust=True)
37 37
38 38 def copy(self):
39 39 return self.__class__(self)
40 40
41 41 def _is_trusted(self, fp, f):
42 42 st = util.fstat(fp)
43 43 if util.isowner(st):
44 44 return True
45 45
46 46 tusers, tgroups = self._trustusers, self._trustgroups
47 47 if '*' in tusers or '*' in tgroups:
48 48 return True
49 49
50 50 user = util.username(st.st_uid)
51 51 group = util.groupname(st.st_gid)
52 52 if user in tusers or group in tgroups or user == util.username():
53 53 return True
54 54
55 55 if self._reportuntrusted:
56 56 self.warn(_('Not trusting file %s from untrusted '
57 57 'user %s, group %s\n') % (f, user, group))
58 58 return False
59 59
60 60 def readconfig(self, filename, root=None, trust=False,
61 61 sections=None, remap=None):
62 62 try:
63 63 fp = open(filename)
64 64 except IOError:
65 65 if not sections: # ignore unless we were looking for something
66 66 return
67 67 raise
68 68
69 69 cfg = config.config()
70 70 trusted = sections or trust or self._is_trusted(fp, filename)
71 71
72 72 try:
73 73 cfg.read(filename, fp, sections=sections, remap=remap)
74 74 except error.ConfigError, inst:
75 75 if trusted:
76 76 raise
77 77 self.warn(_("Ignored: %s\n") % str(inst))
78 78
79 79 if trusted:
80 80 self._tcfg.update(cfg)
81 81 self._tcfg.update(self._ocfg)
82 82 self._ucfg.update(cfg)
83 83 self._ucfg.update(self._ocfg)
84 84
85 85 if root is None:
86 86 root = os.path.expanduser('~')
87 87 self.fixconfig(root=root)
88 88
89 89 def fixconfig(self, root=None):
90 90 # translate paths relative to root (or home) into absolute paths
91 91 root = root or os.getcwd()
92 92 for c in self._tcfg, self._ucfg, self._ocfg:
93 93 for n, p in c.items('paths'):
94 94 if p and "://" not in p and not os.path.isabs(p):
95 95 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
96 96
97 97 # update ui options
98 98 self.debugflag = self.configbool('ui', 'debug')
99 99 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
100 100 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
101 101 if self.verbose and self.quiet:
102 102 self.quiet = self.verbose = False
103 103 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
104 104 self._traceback = self.configbool('ui', 'traceback', False)
105 105
106 106 # update trust information
107 107 self._trustusers.update(self.configlist('trusted', 'users'))
108 108 self._trustgroups.update(self.configlist('trusted', 'groups'))
109 109
110 110 def setconfig(self, section, name, value):
111 111 for cfg in (self._ocfg, self._tcfg, self._ucfg):
112 112 cfg.set(section, name, value)
113 113 self.fixconfig()
114 114
115 115 def _data(self, untrusted):
116 116 return untrusted and self._ucfg or self._tcfg
117 117
118 118 def configsource(self, section, name, untrusted=False):
119 119 return self._data(untrusted).source(section, name) or 'none'
120 120
121 121 def config(self, section, name, default=None, untrusted=False):
122 122 value = self._data(untrusted).get(section, name, default)
123 123 if self.debugflag and not untrusted and self._reportuntrusted:
124 124 uvalue = self._ucfg.get(section, name)
125 125 if uvalue is not None and uvalue != value:
126 126 self.debug(_("ignoring untrusted configuration option "
127 127 "%s.%s = %s\n") % (section, name, uvalue))
128 128 return value
129 129
130 130 def configbool(self, section, name, default=False, untrusted=False):
131 131 v = self.config(section, name, None, untrusted)
132 132 if v is None:
133 133 return default
134 134 if v.lower() not in _booleans:
135 135 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
136 136 % (section, name, v))
137 137 return _booleans[v.lower()]
138 138
139 139 def configlist(self, section, name, default=None, untrusted=False):
140 140 """Return a list of comma/space separated strings"""
141 141 result = self.config(section, name, untrusted=untrusted)
142 142 if result is None:
143 143 result = default or []
144 144 if isinstance(result, basestring):
145 145 result = result.replace(",", " ").split()
146 146 return result
147 147
148 148 def has_section(self, section, untrusted=False):
149 149 '''tell whether section exists in config.'''
150 150 return section in self._data(untrusted)
151 151
152 152 def configitems(self, section, untrusted=False):
153 153 items = self._data(untrusted).items(section)
154 154 if self.debugflag and not untrusted and self._reportuntrusted:
155 155 for k, v in self._ucfg.items(section):
156 156 if self._tcfg.get(section, k) != v:
157 157 self.debug(_("ignoring untrusted configuration option "
158 158 "%s.%s = %s\n") % (section, k, v))
159 159 return items
160 160
161 161 def walkconfig(self, untrusted=False):
162 162 cfg = self._data(untrusted)
163 163 for section in cfg.sections():
164 164 for name, value in self.configitems(section, untrusted):
165 165 yield section, name, str(value).replace('\n', '\\n')
166 166
167 167 def username(self):
168 168 """Return default username to be used in commits.
169 169
170 170 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
171 171 and stop searching if one of these is set.
172 172 If not found and ui.askusername is True, ask the user, else use
173 173 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
174 174 """
175 175 user = os.environ.get("HGUSER")
176 176 if user is None:
177 177 user = self.config("ui", "username")
178 178 if user is None:
179 179 user = os.environ.get("EMAIL")
180 180 if user is None and self.configbool("ui", "askusername"):
181 181 user = self.prompt(_("enter a commit username:"), default=None)
182 182 if user is None:
183 183 try:
184 184 user = '%s@%s' % (util.getuser(), socket.getfqdn())
185 185 self.warn(_("No username found, using '%s' instead\n") % user)
186 186 except KeyError:
187 187 pass
188 188 if not user:
189 189 raise util.Abort(_("Please specify a username."))
190 190 if "\n" in user:
191 191 raise util.Abort(_("username %s contains a newline\n") % repr(user))
192 192 return user
193 193
194 194 def shortuser(self, user):
195 195 """Return a short representation of a user name or email address."""
196 196 if not self.verbose: user = util.shortuser(user)
197 197 return user
198 198
199 199 def _path(self, loc):
200 200 p = self.config('paths', loc)
201 201 if p and '%%' in p:
202 202 self.warn('(deprecated \'%%\' in path %s=%s from %s)\n' %
203 203 (loc, p, self.configsource('paths', loc)))
204 204 p = p.replace('%%', '%')
205 205 return p
206 206
207 207 def expandpath(self, loc, default=None):
208 208 """Return repository location relative to cwd or from [paths]"""
209 209 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
210 210 return loc
211 211
212 212 path = self._path(loc)
213 213 if not path and default is not None:
214 214 path = self._path(default)
215 215 return path or loc
216 216
217 217 def pushbuffer(self):
218 218 self._buffers.append([])
219 219
220 220 def popbuffer(self):
221 221 return "".join(self._buffers.pop())
222 222
223 223 def write(self, *args):
224 224 if self._buffers:
225 225 self._buffers[-1].extend([str(a) for a in args])
226 226 else:
227 227 for a in args:
228 228 sys.stdout.write(str(a))
229 229
230 230 def write_err(self, *args):
231 231 try:
232 232 if not sys.stdout.closed: sys.stdout.flush()
233 233 for a in args:
234 234 sys.stderr.write(str(a))
235 235 # stderr may be buffered under win32 when redirected to files,
236 236 # including stdout.
237 237 if not sys.stderr.closed: sys.stderr.flush()
238 238 except IOError, inst:
239 239 if inst.errno != errno.EPIPE:
240 240 raise
241 241
242 242 def flush(self):
243 243 try: sys.stdout.flush()
244 244 except: pass
245 245 try: sys.stderr.flush()
246 246 except: pass
247 247
248 248 def interactive(self):
249 249 i = self.configbool("ui", "interactive", None)
250 250 if i is None:
251 251 return sys.stdin.isatty()
252 252 return i
253 253
254 254 def _readline(self, prompt=''):
255 255 if sys.stdin.isatty():
256 256 try:
257 257 # magically add command line editing support, where
258 258 # available
259 259 import readline
260 260 # force demandimport to really load the module
261 261 readline.read_history_file
262 262 # windows sometimes raises something other than ImportError
263 263 except Exception:
264 264 pass
265 265 line = raw_input(prompt)
266 266 # When stdin is in binary mode on Windows, it can cause
267 267 # raw_input() to emit an extra trailing carriage return
268 268 if os.linesep == '\r\n' and line and line[-1] == '\r':
269 269 line = line[:-1]
270 270 return line
271 271
272 272 def prompt(self, msg, choices=None, default="y"):
273 273 """Prompt user with msg, read response, and ensure it matches
274 274 one of the provided choices. choices is a sequence of acceptable
275 275 responses with the format: ('&None', 'E&xec', 'Sym&link')
276 276 No sequence implies no response checking. Responses are case
277 277 insensitive. If ui is not interactive, the default is returned.
278 278 """
279 279 if not self.interactive():
280 self.note(msg, ' ', default, "\n")
280 self.write(msg, ' ', default, "\n")
281 281 return default
282 282 while True:
283 283 try:
284 284 r = self._readline(msg + ' ')
285 285 if not r:
286 286 return default
287 287 if not choices:
288 288 return r
289 289 resps = [s[s.index('&')+1].lower() for s in choices]
290 290 if r.lower() in resps:
291 291 return r.lower()
292 292 else:
293 293 self.write(_("unrecognized response\n"))
294 294 except EOFError:
295 295 raise util.Abort(_('response expected'))
296 296
297 297 def getpass(self, prompt=None, default=None):
298 298 if not self.interactive(): return default
299 299 try:
300 300 return getpass.getpass(prompt or _('password: '))
301 301 except EOFError:
302 302 raise util.Abort(_('response expected'))
303 303 def status(self, *msg):
304 304 if not self.quiet: self.write(*msg)
305 305 def warn(self, *msg):
306 306 self.write_err(*msg)
307 307 def note(self, *msg):
308 308 if self.verbose: self.write(*msg)
309 309 def debug(self, *msg):
310 310 if self.debugflag: self.write(*msg)
311 311 def edit(self, text, user):
312 312 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
313 313 text=True)
314 314 try:
315 315 f = os.fdopen(fd, "w")
316 316 f.write(text)
317 317 f.close()
318 318
319 319 editor = self.geteditor()
320 320
321 321 util.system("%s \"%s\"" % (editor, name),
322 322 environ={'HGUSER': user},
323 323 onerr=util.Abort, errprefix=_("edit failed"))
324 324
325 325 f = open(name)
326 326 t = f.read()
327 327 f.close()
328 328 finally:
329 329 os.unlink(name)
330 330
331 331 return t
332 332
333 333 def traceback(self):
334 334 '''print exception traceback if traceback printing enabled.
335 335 only to call in exception handler. returns true if traceback
336 336 printed.'''
337 337 if self._traceback:
338 338 traceback.print_exc()
339 339 return self._traceback
340 340
341 341 def geteditor(self):
342 342 '''return editor to use'''
343 343 return (os.environ.get("HGEDITOR") or
344 344 self.config("ui", "editor") or
345 345 os.environ.get("VISUAL") or
346 346 os.environ.get("EDITOR", "vi"))
@@ -1,65 +1,69 b''
1 1 adding file1
2 2 adding file2
3 3 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 4 created new head
5 5
6 6 # non-interactive merge
7 local changed file1 which remote deleted
8 use (c)hanged version or (d)elete? c
9 remote changed file2 which local deleted
10 use (c)hanged version or leave (d)eleted? c
7 11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 12 (branch merge, don't forget to commit)
9 13 status:
10 14 M file2
11 15 C file1
12 16 file1:
13 17 1
14 18 changed
15 19 file2:
16 20 2
17 21 changed
18 22
19 23 # interactive merge
20 24 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
21 25 local changed file1 which remote deleted
22 26 use (c)hanged version or (d)elete? remote changed file2 which local deleted
23 27 use (c)hanged version or leave (d)eleted? 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 28 (branch merge, don't forget to commit)
25 29 status:
26 30 file2: No such file or directory
27 31 C file1
28 32 file1:
29 33 1
30 34 changed
31 35 file2 does not exist
32 36
33 37 # interactive merge with bad input
34 38 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
35 39 local changed file1 which remote deleted
36 40 use (c)hanged version or (d)elete? unrecognized response
37 41 local changed file1 which remote deleted
38 42 use (c)hanged version or (d)elete? unrecognized response
39 43 local changed file1 which remote deleted
40 44 use (c)hanged version or (d)elete? remote changed file2 which local deleted
41 45 use (c)hanged version or leave (d)eleted? unrecognized response
42 46 remote changed file2 which local deleted
43 47 use (c)hanged version or leave (d)eleted? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 48 (branch merge, don't forget to commit)
45 49 status:
46 50 M file2
47 51 R file1
48 52 file1 does not exist
49 53 file2:
50 54 2
51 55 changed
52 56
53 57 # interactive merge with not enough input
54 58 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
55 59 local changed file1 which remote deleted
56 60 use (c)hanged version or (d)elete? remote changed file2 which local deleted
57 61 use (c)hanged version or leave (d)eleted? abort: response expected
58 62 failed
59 63 status:
60 64 file2: No such file or directory
61 65 C file1
62 66 file1:
63 67 1
64 68 changed
65 69 file2 does not exist
@@ -1,524 +1,528 b''
1 1 # revision 0
2 2 adding f
3 3 # revision 1
4 4 # revision 2
5 5 created new head
6 6 # revision 3 - simple to merge
7 7 created new head
8 8
9 9
10 10 Tool selection
11 11
12 12 # default is internal merge:
13 13 [merge-tools]
14 14 # hg update -C 1
15 15 # hg merge -r 2
16 16 merging f
17 17 warning: conflicts during merge.
18 18 merging f failed!
19 19 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
20 20 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
21 21 # cat f
22 22 <<<<<<< local
23 23 revision 1
24 24 =======
25 25 revision 2
26 26 >>>>>>> other
27 27 space
28 28 # hg stat
29 29 M f
30 30 ? f.orig
31 31
32 32 # simplest hgrc using false for merge:
33 33 [merge-tools]
34 34 false.whatever=
35 35 # hg update -C 1
36 36 # hg merge -r 2
37 37 merging f
38 38 merging f failed!
39 39 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
40 40 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
41 41 # cat f
42 42 revision 1
43 43 space
44 44 # hg stat
45 45 M f
46 46 ? f.orig
47 47
48 48 # true with higher .priority gets precedence:
49 49 [merge-tools]
50 50 false.whatever=
51 51 true.priority=1
52 52 # hg update -C 1
53 53 # hg merge -r 2
54 54 merging f
55 55 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
56 56 (branch merge, don't forget to commit)
57 57 # cat f
58 58 revision 1
59 59 space
60 60 # hg stat
61 61 M f
62 62
63 63 # unless lowered on command line:
64 64 [merge-tools]
65 65 false.whatever=
66 66 true.priority=1
67 67 # hg update -C 1
68 68 # hg merge -r 2 --config merge-tools.true.priority=-7
69 69 merging f
70 70 merging f failed!
71 71 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
72 72 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
73 73 # cat f
74 74 revision 1
75 75 space
76 76 # hg stat
77 77 M f
78 78 ? f.orig
79 79
80 80 # or false set higher on command line:
81 81 [merge-tools]
82 82 false.whatever=
83 83 true.priority=1
84 84 # hg update -C 1
85 85 # hg merge -r 2 --config merge-tools.false.priority=117
86 86 merging f
87 87 merging f failed!
88 88 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
89 89 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
90 90 # cat f
91 91 revision 1
92 92 space
93 93 # hg stat
94 94 M f
95 95 ? f.orig
96 96
97 97 # or true.executable not found in PATH:
98 98 [merge-tools]
99 99 false.whatever=
100 100 true.priority=1
101 101 # hg update -C 1
102 102 # hg merge -r 2 --config merge-tools.true.executable=nonexistingmergetool
103 103 merging f
104 104 merging f failed!
105 105 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
106 106 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
107 107 # cat f
108 108 revision 1
109 109 space
110 110 # hg stat
111 111 M f
112 112 ? f.orig
113 113
114 114 # or true.executable with bogus path:
115 115 [merge-tools]
116 116 false.whatever=
117 117 true.priority=1
118 118 # hg update -C 1
119 119 # hg merge -r 2 --config merge-tools.true.executable=/bin/nonexistingmergetool
120 120 merging f
121 121 merging f failed!
122 122 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
123 123 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
124 124 # cat f
125 125 revision 1
126 126 space
127 127 # hg stat
128 128 M f
129 129 ? f.orig
130 130
131 131 # but true.executable set to cat found in PATH works:
132 132 [merge-tools]
133 133 false.whatever=
134 134 true.priority=1
135 135 true.executable=cat
136 136 # hg update -C 1
137 137 # hg merge -r 2
138 138 revision 1
139 139 space
140 140 revision 0
141 141 space
142 142 revision 2
143 143 space
144 144 merging f
145 145 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
146 146 (branch merge, don't forget to commit)
147 147 # cat f
148 148 revision 1
149 149 space
150 150 # hg stat
151 151 M f
152 152
153 153 # and true.executable set to cat with path works:
154 154 [merge-tools]
155 155 false.whatever=
156 156 true.priority=1
157 157 true.executable=cat
158 158 # hg update -C 1
159 159 # hg merge -r 2 --config merge-tools.true.executable=cat
160 160 revision 1
161 161 space
162 162 revision 0
163 163 space
164 164 revision 2
165 165 space
166 166 merging f
167 167 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
168 168 (branch merge, don't forget to commit)
169 169 # cat f
170 170 revision 1
171 171 space
172 172 # hg stat
173 173 M f
174 174
175 175
176 176 Tool selection and merge-patterns
177 177
178 178 # merge-patterns specifies new tool false:
179 179 [merge-tools]
180 180 false.whatever=
181 181 true.priority=1
182 182 true.executable=cat
183 183 # hg update -C 1
184 184 # hg merge -r 2 --config merge-patterns.f=false
185 185 merging f
186 186 merging f failed!
187 187 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
188 188 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
189 189 # cat f
190 190 revision 1
191 191 space
192 192 # hg stat
193 193 M f
194 194 ? f.orig
195 195
196 196 # merge-patterns specifies executable not found in PATH and gets warning:
197 197 [merge-tools]
198 198 false.whatever=
199 199 true.priority=1
200 200 true.executable=cat
201 201 # hg update -C 1
202 202 # hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=nonexistingmergetool
203 203 couldn't find merge tool true specified for f
204 204 merging f
205 205 merging f failed!
206 206 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
207 207 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
208 208 # cat f
209 209 revision 1
210 210 space
211 211 # hg stat
212 212 M f
213 213 ? f.orig
214 214
215 215 # merge-patterns specifies executable with bogus path and gets warning:
216 216 [merge-tools]
217 217 false.whatever=
218 218 true.priority=1
219 219 true.executable=cat
220 220 # hg update -C 1
221 221 # hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=/bin/nonexistingmergetool
222 222 couldn't find merge tool true specified for f
223 223 merging f
224 224 merging f failed!
225 225 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
226 226 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
227 227 # cat f
228 228 revision 1
229 229 space
230 230 # hg stat
231 231 M f
232 232 ? f.orig
233 233
234 234
235 235 ui.merge overrules priority
236 236
237 237 # ui.merge specifies false:
238 238 [merge-tools]
239 239 false.whatever=
240 240 true.priority=1
241 241 true.executable=cat
242 242 # hg update -C 1
243 243 # hg merge -r 2 --config ui.merge=false
244 244 merging f
245 245 merging f failed!
246 246 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
247 247 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
248 248 # cat f
249 249 revision 1
250 250 space
251 251 # hg stat
252 252 M f
253 253 ? f.orig
254 254
255 255 # ui.merge specifies internal:fail:
256 256 [merge-tools]
257 257 false.whatever=
258 258 true.priority=1
259 259 true.executable=cat
260 260 # hg update -C 1
261 261 # hg merge -r 2 --config ui.merge=internal:fail
262 262 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
263 263 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
264 264 # cat f
265 265 revision 1
266 266 space
267 267 # hg stat
268 268 M f
269 269
270 270 # ui.merge specifies internal:local:
271 271 [merge-tools]
272 272 false.whatever=
273 273 true.priority=1
274 274 true.executable=cat
275 275 # hg update -C 1
276 276 # hg merge -r 2 --config ui.merge=internal:local
277 277 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
278 278 (branch merge, don't forget to commit)
279 279 # cat f
280 280 revision 1
281 281 space
282 282 # hg stat
283 283 M f
284 284
285 285 # ui.merge specifies internal:other:
286 286 [merge-tools]
287 287 false.whatever=
288 288 true.priority=1
289 289 true.executable=cat
290 290 # hg update -C 1
291 291 # hg merge -r 2 --config ui.merge=internal:other
292 292 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
293 293 (branch merge, don't forget to commit)
294 294 # cat f
295 295 revision 2
296 296 space
297 297 # hg stat
298 298 M f
299 299
300 300 # ui.merge specifies internal:prompt:
301 301 [merge-tools]
302 302 false.whatever=
303 303 true.priority=1
304 304 true.executable=cat
305 305 # hg update -C 1
306 306 # hg merge -r 2 --config ui.merge=internal:prompt
307 no tool found to merge f
308 keep (l)ocal or take (o)ther? l
307 309 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
308 310 (branch merge, don't forget to commit)
309 311 # cat f
310 312 revision 1
311 313 space
312 314 # hg stat
313 315 M f
314 316
315 317 # ui.merge specifies internal:dump:
316 318 [merge-tools]
317 319 false.whatever=
318 320 true.priority=1
319 321 true.executable=cat
320 322 # hg update -C 1
321 323 # hg merge -r 2 --config ui.merge=internal:dump
322 324 merging f
323 325 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
324 326 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
325 327 # cat f
326 328 revision 1
327 329 space
328 330 # hg stat
329 331 M f
330 332 ? f.base
331 333 ? f.local
332 334 ? f.orig
333 335 ? f.other
334 336
335 337 f.base:
336 338 revision 0
337 339 space
338 340 f.local:
339 341 revision 1
340 342 space
341 343 f.other:
342 344 revision 2
343 345 space
344 346
345 347 # ui.merge specifies internal:other but is overruled by pattern for false:
346 348 [merge-tools]
347 349 false.whatever=
348 350 true.priority=1
349 351 true.executable=cat
350 352 # hg update -C 1
351 353 # hg merge -r 2 --config ui.merge=internal:other --config merge-patterns.f=false
352 354 merging f
353 355 merging f failed!
354 356 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
355 357 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
356 358 # cat f
357 359 revision 1
358 360 space
359 361 # hg stat
360 362 M f
361 363 ? f.orig
362 364
363 365
364 366 Premerge
365 367
366 368 # Default is silent simplemerge:
367 369 [merge-tools]
368 370 false.whatever=
369 371 true.priority=1
370 372 true.executable=cat
371 373 # hg update -C 1
372 374 # hg merge -r 3
373 375 merging f
374 376 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
375 377 (branch merge, don't forget to commit)
376 378 # cat f
377 379 revision 1
378 380 space
379 381 revision 3
380 382 # hg stat
381 383 M f
382 384
383 385 # .premerge=True is same:
384 386 [merge-tools]
385 387 false.whatever=
386 388 true.priority=1
387 389 true.executable=cat
388 390 # hg update -C 1
389 391 # hg merge -r 3 --config merge-tools.true.premerge=True
390 392 merging f
391 393 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
392 394 (branch merge, don't forget to commit)
393 395 # cat f
394 396 revision 1
395 397 space
396 398 revision 3
397 399 # hg stat
398 400 M f
399 401
400 402 # .premerge=False executes merge-tool:
401 403 [merge-tools]
402 404 false.whatever=
403 405 true.priority=1
404 406 true.executable=cat
405 407 # hg update -C 1
406 408 # hg merge -r 3 --config merge-tools.true.premerge=False
407 409 revision 1
408 410 space
409 411 revision 0
410 412 space
411 413 revision 0
412 414 space
413 415 revision 3
414 416 merging f
415 417 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
416 418 (branch merge, don't forget to commit)
417 419 # cat f
418 420 revision 1
419 421 space
420 422 # hg stat
421 423 M f
422 424
423 425
424 426 Tool execution
425 427
426 428 # set tools.args explicit to include $base $local $other $output:
427 429 [merge-tools]
428 430 false.whatever=
429 431 true.priority=1
430 432 true.executable=cat
431 433 # hg update -C 1
432 434 ==> ... <==
433 435 revision 0
434 436 space
435 437
436 438 ==> ... <==
437 439 revision 1
438 440 space
439 441
440 442 ==> ... <==
441 443 revision 2
442 444 space
443 445
444 446 ==> ... <==
445 447 revision 1
446 448 space
447 449 merging f
448 450 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
449 451 (branch merge, don't forget to commit)
450 452 # cat f
451 453 revision 1
452 454 space
453 455 # hg stat
454 456 M f
455 457
456 458 # Merge with "echo mergeresult > $local":
457 459 [merge-tools]
458 460 false.whatever=
459 461 true.priority=1
460 462 true.executable=cat
461 463 # hg update -C 1
462 464 merging f
463 465 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
464 466 (branch merge, don't forget to commit)
465 467 # cat f
466 468 mergeresult
467 469 # hg stat
468 470 M f
469 471
470 472 # - and $local is the file f:
471 473 [merge-tools]
472 474 false.whatever=
473 475 true.priority=1
474 476 true.executable=cat
475 477 # hg update -C 1
476 478 merging f
477 479 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
478 480 (branch merge, don't forget to commit)
479 481 # cat f
480 482 mergeresult
481 483 # hg stat
482 484 M f
483 485
484 486 # Merge with "echo mergeresult > $output" - the variable is a bit magic:
485 487 [merge-tools]
486 488 false.whatever=
487 489 true.priority=1
488 490 true.executable=cat
489 491 # hg update -C 1
490 492 merging f
491 493 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
492 494 (branch merge, don't forget to commit)
493 495 # cat f
494 496 mergeresult
495 497 # hg stat
496 498 M f
497 499
498 500
499 501 Merge post-processing
500 502
501 503 # cat is a bad merge-tool and doesn't change:
502 504 [merge-tools]
503 505 false.whatever=
504 506 true.priority=1
505 507 true.executable=cat
506 508 # hg update -C 1
507 509 # hg merge -y -r 2 --config merge-tools.true.checkchanged=1
508 510 revision 1
509 511 space
510 512 revision 0
511 513 space
512 514 revision 2
513 515 space
514 516 merging f
517 output file f appears unchanged
518 was merge successful (yn)? n
515 519 merging f failed!
516 520 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
517 521 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
518 522 # cat f
519 523 revision 1
520 524 space
521 525 # hg stat
522 526 M f
523 527 ? f.orig
524 528
General Comments 0
You need to be logged in to leave comments. Login now