Show More
@@ -1181,6 +1181,9 b" coreconfigitem('ui', 'mergemarkertemplat" | |||||
1181 | '{ifeq(branch, "default", "", "{branch} ")}' |
|
1181 | '{ifeq(branch, "default", "", "{branch} ")}' | |
1182 | '- {author|user}: {desc|firstline}') |
|
1182 | '- {author|user}: {desc|firstline}') | |
1183 | ) |
|
1183 | ) | |
|
1184 | coreconfigitem('ui', 'message-output', | |||
|
1185 | default='stdio', | |||
|
1186 | ) | |||
1184 | coreconfigitem('ui', 'nontty', |
|
1187 | coreconfigitem('ui', 'nontty', | |
1185 | default=False, |
|
1188 | default=False, | |
1186 | ) |
|
1189 | ) |
@@ -2246,6 +2246,14 b' User interface controls.' | |||||
2246 |
|
2246 | |||
2247 | Can be overridden per-merge-tool, see the ``[merge-tools]`` section. |
|
2247 | Can be overridden per-merge-tool, see the ``[merge-tools]`` section. | |
2248 |
|
2248 | |||
|
2249 | ``message-output`` | |||
|
2250 | Where to write status and error messages. (default: ``stdio``) | |||
|
2251 | ||||
|
2252 | ``stderr`` | |||
|
2253 | Everything to stderr. | |||
|
2254 | ``stdio`` | |||
|
2255 | Status to stdout, and error to stderr. | |||
|
2256 | ||||
2249 | ``origbackuppath`` |
|
2257 | ``origbackuppath`` | |
2250 | The path to a directory used to store generated .orig files. If the path is |
|
2258 | The path to a directory used to store generated .orig files. If the path is | |
2251 | not a directory, one will be created. If set, files stored in this |
|
2259 | not a directory, one will be created. If set, files stored in this |
@@ -234,6 +234,8 b' class ui(object):' | |||||
234 | self._fout = src._fout |
|
234 | self._fout = src._fout | |
235 | self._ferr = src._ferr |
|
235 | self._ferr = src._ferr | |
236 | self._fin = src._fin |
|
236 | self._fin = src._fin | |
|
237 | self._fmsgout = src._fmsgout | |||
|
238 | self._fmsgerr = src._fmsgerr | |||
237 | self._finoutredirected = src._finoutredirected |
|
239 | self._finoutredirected = src._finoutredirected | |
238 | self.pageractive = src.pageractive |
|
240 | self.pageractive = src.pageractive | |
239 | self._disablepager = src._disablepager |
|
241 | self._disablepager = src._disablepager | |
@@ -259,6 +261,8 b' class ui(object):' | |||||
259 | self._fout = procutil.stdout |
|
261 | self._fout = procutil.stdout | |
260 | self._ferr = procutil.stderr |
|
262 | self._ferr = procutil.stderr | |
261 | self._fin = procutil.stdin |
|
263 | self._fin = procutil.stdin | |
|
264 | self._fmsgout = self.fout # configurable | |||
|
265 | self._fmsgerr = self.ferr # configurable | |||
262 | self._finoutredirected = False |
|
266 | self._finoutredirected = False | |
263 | self.pageractive = False |
|
267 | self.pageractive = False | |
264 | self._disablepager = False |
|
268 | self._disablepager = False | |
@@ -416,7 +420,7 b' class ui(object):' | |||||
416 |
|
420 | |||
417 | if self.plain(): |
|
421 | if self.plain(): | |
418 | for k in ('debug', 'fallbackencoding', 'quiet', 'slash', |
|
422 | for k in ('debug', 'fallbackencoding', 'quiet', 'slash', | |
419 | 'logtemplate', 'statuscopies', 'style', |
|
423 | 'logtemplate', 'message-output', 'statuscopies', 'style', | |
420 | 'traceback', 'verbose'): |
|
424 | 'traceback', 'verbose'): | |
421 | if k in cfg['ui']: |
|
425 | if k in cfg['ui']: | |
422 | del cfg['ui'][k] |
|
426 | del cfg['ui'][k] | |
@@ -469,6 +473,7 b' class ui(object):' | |||||
469 |
|
473 | |||
470 | if section in (None, 'ui'): |
|
474 | if section in (None, 'ui'): | |
471 | # update ui options |
|
475 | # update ui options | |
|
476 | self._fmsgout, self._fmsgerr = _selectmsgdests(self) | |||
472 | self.debugflag = self.configbool('ui', 'debug') |
|
477 | self.debugflag = self.configbool('ui', 'debug') | |
473 | self.verbose = self.debugflag or self.configbool('ui', 'verbose') |
|
478 | self.verbose = self.debugflag or self.configbool('ui', 'verbose') | |
474 | self.quiet = not self.debugflag and self.configbool('ui', 'quiet') |
|
479 | self.quiet = not self.debugflag and self.configbool('ui', 'quiet') | |
@@ -891,6 +896,7 b' class ui(object):' | |||||
891 | @fout.setter |
|
896 | @fout.setter | |
892 | def fout(self, f): |
|
897 | def fout(self, f): | |
893 | self._fout = f |
|
898 | self._fout = f | |
|
899 | self._fmsgout, self._fmsgerr = _selectmsgdests(self) | |||
894 |
|
900 | |||
895 | @property |
|
901 | @property | |
896 | def ferr(self): |
|
902 | def ferr(self): | |
@@ -899,6 +905,7 b' class ui(object):' | |||||
899 | @ferr.setter |
|
905 | @ferr.setter | |
900 | def ferr(self, f): |
|
906 | def ferr(self, f): | |
901 | self._ferr = f |
|
907 | self._ferr = f | |
|
908 | self._fmsgout, self._fmsgerr = _selectmsgdests(self) | |||
902 |
|
909 | |||
903 | @property |
|
910 | @property | |
904 | def fin(self): |
|
911 | def fin(self): | |
@@ -1364,17 +1371,18 b' class ui(object):' | |||||
1364 | If ui is not interactive, the default is returned. |
|
1371 | If ui is not interactive, the default is returned. | |
1365 | """ |
|
1372 | """ | |
1366 | if not self.interactive(): |
|
1373 | if not self.interactive(): | |
1367 | self.write(msg, ' ', label='ui.prompt') |
|
1374 | self._write(self._fmsgout, msg, ' ', label='ui.prompt') | |
1368 |
self.write(default or '', "\n", |
|
1375 | self._write(self._fmsgout, default or '', "\n", | |
|
1376 | label='ui.promptecho') | |||
1369 | return default |
|
1377 | return default | |
1370 | self._writenobuf(self._fout, msg, label='ui.prompt') |
|
1378 | self._writenobuf(self._fmsgout, msg, label='ui.prompt') | |
1371 | self.flush() |
|
1379 | self.flush() | |
1372 | try: |
|
1380 | try: | |
1373 | r = self._readline() |
|
1381 | r = self._readline() | |
1374 | if not r: |
|
1382 | if not r: | |
1375 | r = default |
|
1383 | r = default | |
1376 | if self.configbool('ui', 'promptecho'): |
|
1384 | if self.configbool('ui', 'promptecho'): | |
1377 | self.write(r, "\n", label='ui.promptecho') |
|
1385 | self._write(self._fmsgout, r, "\n", label='ui.promptecho') | |
1378 | return r |
|
1386 | return r | |
1379 | except EOFError: |
|
1387 | except EOFError: | |
1380 | raise error.ResponseExpected() |
|
1388 | raise error.ResponseExpected() | |
@@ -1424,13 +1432,15 b' class ui(object):' | |||||
1424 | r = self.prompt(msg, resps[default]) |
|
1432 | r = self.prompt(msg, resps[default]) | |
1425 | if r.lower() in resps: |
|
1433 | if r.lower() in resps: | |
1426 | return resps.index(r.lower()) |
|
1434 | return resps.index(r.lower()) | |
1427 | self.write(_("unrecognized response\n")) |
|
1435 | # TODO: shouldn't it be a warning? | |
|
1436 | self._write(self._fmsgout, _("unrecognized response\n")) | |||
1428 |
|
1437 | |||
1429 | def getpass(self, prompt=None, default=None): |
|
1438 | def getpass(self, prompt=None, default=None): | |
1430 | if not self.interactive(): |
|
1439 | if not self.interactive(): | |
1431 | return default |
|
1440 | return default | |
1432 | try: |
|
1441 | try: | |
1433 |
self.write |
|
1442 | self._write(self._fmsgerr, prompt or _('password: '), | |
|
1443 | label='ui.prompt') | |||
1434 | # disable getpass() only if explicitly specified. it's still valid |
|
1444 | # disable getpass() only if explicitly specified. it's still valid | |
1435 | # to interact with tty even if fin is not a tty. |
|
1445 | # to interact with tty even if fin is not a tty. | |
1436 | with self.timeblockedsection('stdio'): |
|
1446 | with self.timeblockedsection('stdio'): | |
@@ -1451,7 +1461,7 b' class ui(object):' | |||||
1451 | ''' |
|
1461 | ''' | |
1452 | if not self.quiet: |
|
1462 | if not self.quiet: | |
1453 | opts[r'label'] = opts.get(r'label', '') + ' ui.status' |
|
1463 | opts[r'label'] = opts.get(r'label', '') + ' ui.status' | |
1454 | self.write(*msg, **opts) |
|
1464 | self._write(self._fmsgout, *msg, **opts) | |
1455 |
|
1465 | |||
1456 | def warn(self, *msg, **opts): |
|
1466 | def warn(self, *msg, **opts): | |
1457 | '''write warning message to output (stderr) |
|
1467 | '''write warning message to output (stderr) | |
@@ -1459,7 +1469,7 b' class ui(object):' | |||||
1459 | This adds an output label of "ui.warning". |
|
1469 | This adds an output label of "ui.warning". | |
1460 | ''' |
|
1470 | ''' | |
1461 | opts[r'label'] = opts.get(r'label', '') + ' ui.warning' |
|
1471 | opts[r'label'] = opts.get(r'label', '') + ' ui.warning' | |
1462 |
self.write |
|
1472 | self._write(self._fmsgerr, *msg, **opts) | |
1463 |
|
1473 | |||
1464 | def error(self, *msg, **opts): |
|
1474 | def error(self, *msg, **opts): | |
1465 | '''write error message to output (stderr) |
|
1475 | '''write error message to output (stderr) | |
@@ -1467,7 +1477,7 b' class ui(object):' | |||||
1467 | This adds an output label of "ui.error". |
|
1477 | This adds an output label of "ui.error". | |
1468 | ''' |
|
1478 | ''' | |
1469 | opts[r'label'] = opts.get(r'label', '') + ' ui.error' |
|
1479 | opts[r'label'] = opts.get(r'label', '') + ' ui.error' | |
1470 |
self.write |
|
1480 | self._write(self._fmsgerr, *msg, **opts) | |
1471 |
|
1481 | |||
1472 | def note(self, *msg, **opts): |
|
1482 | def note(self, *msg, **opts): | |
1473 | '''write note to output (if ui.verbose is True) |
|
1483 | '''write note to output (if ui.verbose is True) | |
@@ -1476,7 +1486,7 b' class ui(object):' | |||||
1476 | ''' |
|
1486 | ''' | |
1477 | if self.verbose: |
|
1487 | if self.verbose: | |
1478 | opts[r'label'] = opts.get(r'label', '') + ' ui.note' |
|
1488 | opts[r'label'] = opts.get(r'label', '') + ' ui.note' | |
1479 | self.write(*msg, **opts) |
|
1489 | self._write(self._fmsgout, *msg, **opts) | |
1480 |
|
1490 | |||
1481 | def debug(self, *msg, **opts): |
|
1491 | def debug(self, *msg, **opts): | |
1482 | '''write debug message to output (if ui.debugflag is True) |
|
1492 | '''write debug message to output (if ui.debugflag is True) | |
@@ -1485,7 +1495,7 b' class ui(object):' | |||||
1485 | ''' |
|
1495 | ''' | |
1486 | if self.debugflag: |
|
1496 | if self.debugflag: | |
1487 | opts[r'label'] = opts.get(r'label', '') + ' ui.debug' |
|
1497 | opts[r'label'] = opts.get(r'label', '') + ' ui.debug' | |
1488 | self.write(*msg, **opts) |
|
1498 | self._write(self._fmsgout, *msg, **opts) | |
1489 |
|
1499 | |||
1490 | def edit(self, text, user, extra=None, editform=None, pending=None, |
|
1500 | def edit(self, text, user, extra=None, editform=None, pending=None, | |
1491 | repopath=None, action=None): |
|
1501 | repopath=None, action=None): | |
@@ -1939,3 +1949,11 b' def getprogbar(ui):' | |||||
1939 |
|
1949 | |||
1940 | def haveprogbar(): |
|
1950 | def haveprogbar(): | |
1941 | return _progresssingleton is not None |
|
1951 | return _progresssingleton is not None | |
|
1952 | ||||
|
1953 | def _selectmsgdests(ui): | |||
|
1954 | name = ui.config(b'ui', b'message-output') | |||
|
1955 | if name == b'stdio': | |||
|
1956 | return ui.fout, ui.ferr | |||
|
1957 | if name == b'stderr': | |||
|
1958 | return ui.ferr, ui.ferr | |||
|
1959 | raise error.Abort(b'invalid ui.message-output destination: %s' % name) |
@@ -102,3 +102,118 b' Repository root:' | |||||
102 | At the end... |
|
102 | At the end... | |
103 |
|
103 | |||
104 | $ cd .. |
|
104 | $ cd .. | |
|
105 | ||||
|
106 | Status message redirection: | |||
|
107 | ||||
|
108 | $ hg init empty | |||
|
109 | ||||
|
110 | status messages are sent to stdout by default: | |||
|
111 | ||||
|
112 | $ hg outgoing -R t empty -Tjson 2>/dev/null | |||
|
113 | comparing with empty | |||
|
114 | searching for changes | |||
|
115 | [ | |||
|
116 | { | |||
|
117 | "bookmarks": [], | |||
|
118 | "branch": "default", | |||
|
119 | "date": [0, 0], | |||
|
120 | "desc": "test", | |||
|
121 | "node": "acb14030fe0a21b60322c440ad2d20cf7685a376", | |||
|
122 | "parents": ["0000000000000000000000000000000000000000"], | |||
|
123 | "phase": "draft", | |||
|
124 | "rev": 0, | |||
|
125 | "tags": ["tip"], | |||
|
126 | "user": "test" | |||
|
127 | } | |||
|
128 | ] | |||
|
129 | ||||
|
130 | which can be configured to send to stderr, so the output wouldn't be | |||
|
131 | interleaved: | |||
|
132 | ||||
|
133 | $ cat <<'EOF' >> "$HGRCPATH" | |||
|
134 | > [ui] | |||
|
135 | > message-output = stderr | |||
|
136 | > EOF | |||
|
137 | $ hg outgoing -R t empty -Tjson 2>/dev/null | |||
|
138 | [ | |||
|
139 | { | |||
|
140 | "bookmarks": [], | |||
|
141 | "branch": "default", | |||
|
142 | "date": [0, 0], | |||
|
143 | "desc": "test", | |||
|
144 | "node": "acb14030fe0a21b60322c440ad2d20cf7685a376", | |||
|
145 | "parents": ["0000000000000000000000000000000000000000"], | |||
|
146 | "phase": "draft", | |||
|
147 | "rev": 0, | |||
|
148 | "tags": ["tip"], | |||
|
149 | "user": "test" | |||
|
150 | } | |||
|
151 | ] | |||
|
152 | $ hg outgoing -R t empty -Tjson >/dev/null | |||
|
153 | comparing with empty | |||
|
154 | searching for changes | |||
|
155 | ||||
|
156 | this option should be turned off by HGPLAIN= since it may break scripting use: | |||
|
157 | ||||
|
158 | $ HGPLAIN= hg outgoing -R t empty -Tjson 2>/dev/null | |||
|
159 | comparing with empty | |||
|
160 | searching for changes | |||
|
161 | [ | |||
|
162 | { | |||
|
163 | "bookmarks": [], | |||
|
164 | "branch": "default", | |||
|
165 | "date": [0, 0], | |||
|
166 | "desc": "test", | |||
|
167 | "node": "acb14030fe0a21b60322c440ad2d20cf7685a376", | |||
|
168 | "parents": ["0000000000000000000000000000000000000000"], | |||
|
169 | "phase": "draft", | |||
|
170 | "rev": 0, | |||
|
171 | "tags": ["tip"], | |||
|
172 | "user": "test" | |||
|
173 | } | |||
|
174 | ] | |||
|
175 | ||||
|
176 | but still overridden by --config: | |||
|
177 | ||||
|
178 | $ HGPLAIN= hg outgoing -R t empty -Tjson --config ui.message-output=stderr \ | |||
|
179 | > 2>/dev/null | |||
|
180 | [ | |||
|
181 | { | |||
|
182 | "bookmarks": [], | |||
|
183 | "branch": "default", | |||
|
184 | "date": [0, 0], | |||
|
185 | "desc": "test", | |||
|
186 | "node": "acb14030fe0a21b60322c440ad2d20cf7685a376", | |||
|
187 | "parents": ["0000000000000000000000000000000000000000"], | |||
|
188 | "phase": "draft", | |||
|
189 | "rev": 0, | |||
|
190 | "tags": ["tip"], | |||
|
191 | "user": "test" | |||
|
192 | } | |||
|
193 | ] | |||
|
194 | ||||
|
195 | Invalid ui.message-output option: | |||
|
196 | ||||
|
197 | $ hg log -R t --config ui.message-output=bad | |||
|
198 | abort: invalid ui.message-output destination: bad | |||
|
199 | [255] | |||
|
200 | ||||
|
201 | Underlying message streams should be updated when ui.fout/ferr are set: | |||
|
202 | ||||
|
203 | $ cat <<'EOF' > capui.py | |||
|
204 | > from mercurial import pycompat, registrar | |||
|
205 | > cmdtable = {} | |||
|
206 | > command = registrar.command(cmdtable) | |||
|
207 | > @command(b'capui', norepo=True) | |||
|
208 | > def capui(ui): | |||
|
209 | > out = ui.fout | |||
|
210 | > ui.fout = pycompat.bytesio() | |||
|
211 | > ui.status(b'status\n') | |||
|
212 | > ui.ferr = pycompat.bytesio() | |||
|
213 | > ui.warn(b'warn\n') | |||
|
214 | > out.write(b'stdout: %s' % ui.fout.getvalue()) | |||
|
215 | > out.write(b'stderr: %s' % ui.ferr.getvalue()) | |||
|
216 | > EOF | |||
|
217 | $ hg --config extensions.capui=capui.py --config ui.message-output=stdio capui | |||
|
218 | stdout: status | |||
|
219 | stderr: warn |
General Comments 0
You need to be logged in to leave comments.
Login now