##// END OF EJS Templates
commands: make --rev and --index compatible in debugobsolete
commands: make --rev and --index compatible in debugobsolete

File last commit:

r28635:87f92d6f default
r28845:5a398627 default
Show More
ui.py
1338 lines | 47.5 KiB | text/x-python | PythonLexer
mpm@selenic.com
Move ui class to its own module...
r207 # ui.py - user interface bits for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Move ui class to its own module...
r207 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Move ui class to its own module...
r207
Gregory Szorc
ui: use absolute_import...
r25989 from __future__ import absolute_import
import errno
import getpass
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629 import inspect
Gregory Szorc
ui: use absolute_import...
r25989 import os
Matt Mackall
ui: try to handle $$ more robustly in prompts (issue4970)
r27392 import re
Gregory Szorc
ui: use absolute_import...
r25989 import socket
import sys
import tempfile
import traceback
from .i18n import _
from .node import hex
from . import (
config,
error,
formatter,
progress,
scmutil,
util,
)
mpm@selenic.com
Move ui class to its own module...
r207
Matt Mackall
ui: move samplehgrcs from config...
r22419 samplehgrcs = {
'user':
"""# example user config (see "hg help config" for more info)
[ui]
# name and email, e.g.
# username = Jane Doe <jdoe@example.com>
username =
[extensions]
# uncomment these lines to enable some popular extensions
# (see "hg help extensions" for more info)
#
# pager =
# color =""",
Jordi GutiƩrrez Hermoso
config: use the same hgrc for a cloned repo as for an uninitted repo...
r22837 'cloned':
"""# example repository config (see "hg help config" for more info)
[paths]
default = %s
# path aliases to other clones of this repo in URLs or filesystem paths
# (see "hg help config.paths" for more info)
#
# default-push = ssh://jdoe@example.net/hg/jdoes-fork
# my-fork = ssh://jdoe@example.net/hg/jdoes-fork
# my-clone = /home/jdoe/jdoes-clone
[ui]
# name and email (local to this repository, optional), e.g.
# username = Jane Doe <jdoe@example.com>
""",
Matt Mackall
ui: move samplehgrcs from config...
r22419 'local':
"""# example repository config (see "hg help config" for more info)
Jordi GutiƩrrez Hermoso
config: give a more detailed sample repo config...
r22836 [paths]
# path aliases to other clones of this repo in URLs or filesystem paths
# (see "hg help config.paths" for more info)
#
# default = http://example.com/hg/example-repo
# default-push = ssh://jdoe@example.net/hg/jdoes-fork
# my-fork = ssh://jdoe@example.net/hg/jdoes-fork
# my-clone = /home/jdoe/jdoes-clone
[ui]
# name and email (local to this repository, optional), e.g.
# username = Jane Doe <jdoe@example.com>
Matt Mackall
ui: move samplehgrcs from config...
r22419 """,
'global':
"""# example system-wide hg config (see "hg help config" for more info)
[extensions]
# uncomment these lines to enable some popular extensions
# (see "hg help extensions" for more info)
#
# blackbox =
# color =
# pager =""",
}
Eric Hopper
Convert all classes to new-style classes by deriving them from object.
r1559 class ui(object):
Matt Mackall
ui: kill most users of parentui name and arg, replace with .copy()
r8190 def __init__(self, src=None):
Pierre-Yves David
ui: pushbuffer can now also capture stderr...
r21132 # _buffers: used for temporary capture of output
Matt Mackall
ui: buffers -> _buffers
r8202 self._buffers = []
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 # 3-tuple describing how each buffer in the stack behaves.
# Values are (capture stderr, capture subprocesses, apply labels).
Pierre-Yves David
ui: pushbuffer can now also capture stderr...
r21132 self._bufferstates = []
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 # When a buffer is active, defines whether we are expanding labels.
# This exists to prevent an extra list lookup.
self._bufferapplylabels = None
Bryan O'Sullivan
Make it possible to debug failed hook imports via use of --traceback...
r9851 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
Matt Mackall
ui: make interactive a method
r8208 self._reportuntrusted = True
Matt Mackall
ui: privatize cdata vars
r8203 self._ocfg = config.config() # overlay
self._tcfg = config.config() # trusted
self._ucfg = config.config() # untrusted
Martin Geisler
ui: use set instead of dict
r8478 self._trustusers = set()
self._trustgroups = set()
Idan Kamara
ui: add a variable to control whether hooks should be called...
r17048 self.callhooks = True
Matt Mackall
ui: refactor option setting...
r8136
Matt Mackall
ui: kill most users of parentui name and arg, replace with .copy()
r8190 if src:
Idan Kamara
ui: add I/O descriptors
r14612 self.fout = src.fout
self.ferr = src.ferr
self.fin = src.fin
Matt Mackall
ui: privatize cdata vars
r8203 self._tcfg = src._tcfg.copy()
self._ucfg = src._ucfg.copy()
self._ocfg = src._ocfg.copy()
Matt Mackall
ui: trusted_users -> _trustusers, trusted_groups -> _trustgroups
r8201 self._trustusers = src._trustusers.copy()
self._trustgroups = src._trustgroups.copy()
Sune Foldager
ui: add environ property to access os.environ or wsgirequest.environ...
r9887 self.environ = src.environ
Idan Kamara
ui: add a variable to control whether hooks should be called...
r17048 self.callhooks = src.callhooks
Matt Mackall
ui: simplify init, kill dupconfig
r8143 self.fixconfig()
else:
Idan Kamara
ui: add I/O descriptors
r14612 self.fout = sys.stdout
self.ferr = sys.stderr
self.fin = sys.stdin
Sune Foldager
ui: add environ property to access os.environ or wsgirequest.environ...
r9887 # shared read-only environment
self.environ = os.environ
Alexis S. L. Carvalho
Use a variable to explicitly trust global config files
r3676 # we always trust global config files
Adrian Buehlmann
move rcpath from util to scmutil
r13984 for f in scmutil.rcpath():
Matt Mackall
ui: assumetrusted -> trust
r8200 self.readconfig(f, trust=True)
Dirkjan Ochtman
more whitespace cleanup and some other style nits
r8222
Matt Mackall
ui: replace parentui mechanism with repo.baseui
r8189 def copy(self):
Ronny Pfannschmidt
ui: ui.copy() now takes the ui class into account...
r8220 return self.__class__(self)
Thomas Arendsen Hein
Create local ui object per repository, so .hg/hgrc don't get mixed....
r1839
Matt Mackall
ui: add formatter method
r16135 def formatter(self, topic, opts):
return formatter.formatter(self, topic, opts)
Matt Mackall
ui: rename _is_trusted to _trusted...
r14859 def _trusted(self, fp, f):
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677 st = util.fstat(fp)
Martin Geisler
posix: do not use fstat in isowner...
r8657 if util.isowner(st):
Alexis S. L. Carvalho
Avoid looking up usernames if the current user owns the .hgrc file...
r3677 return True
Matt Mackall
ui: cleanup _is_trusted a bit
r8141
Matt Mackall
ui: trusted_users -> _trustusers, trusted_groups -> _trustgroups
r8201 tusers, tgroups = self._trustusers, self._trustgroups
Matt Mackall
ui: cleanup _is_trusted a bit
r8141 if '*' in tusers or '*' in tgroups:
return True
user = util.username(st.st_uid)
group = util.groupname(st.st_gid)
if user in tusers or group in tgroups or user == util.username():
return True
Matt Mackall
ui: report_untrusted fixes...
r8204 if self._reportuntrusted:
Martin Geisler
ui: lowercase "not trusting file" warning message
r16939 self.warn(_('not trusting file %s from untrusted '
Matt Mackall
ui: cleanup _is_trusted a bit
r8141 'user %s, group %s\n') % (f, user, group))
return False
Alexis S. L. Carvalho
Only read .hg/hgrc files from trusted users/groups...
r3551
Matt Mackall
ui: assumetrusted -> trust
r8200 def readconfig(self, filename, root=None, trust=False,
Alexander Solovyov
hgwebdir: read --webdir-conf as actual configuration to ui (issue1586)...
r8345 sections=None, remap=None):
Matt Mackall
ui: fold readsections into readconfig...
r8142 try:
fp = open(filename)
except IOError:
if not sections: # ignore unless we were looking for something
return
raise
Matt Mackall
ui: always have ucdata...
r8139
Matt Mackall
ui: privatize cdata vars
r8203 cfg = config.config()
Matt Mackall
ui: rename _is_trusted to _trusted...
r14859 trusted = sections or trust or self._trusted(fp, filename)
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552
Matt Mackall
ui: fold readsections into readconfig...
r8142 try:
Alexander Solovyov
hgwebdir: read --webdir-conf as actual configuration to ui (issue1586)...
r8345 cfg.read(filename, fp, sections=sections, remap=remap)
Matt Mackall
misc: adding missing file close() calls...
r15407 fp.close()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.ConfigError as inst:
Matt Mackall
ui: fold readsections into readconfig...
r8142 if trusted:
Matt Mackall
ui: introduce new config parser
r8144 raise
Martin Geisler
ui: lowercase ConfigError warning message
r16938 self.warn(_("ignored: %s\n") % str(inst))
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552
Brodie Rao
ui: add HGPLAIN environment variable for easier scripting...
r10455 if self.plain():
Brodie Rao
ui: unset ui.slash when HGPLAIN is set
r10507 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
Mathias De MarƩ
commands: add ui.statuscopies config knob...
r24663 'logtemplate', 'statuscopies', 'style',
Brodie Rao
ui: unset ui.slash when HGPLAIN is set
r10507 'traceback', 'verbose'):
Brodie Rao
ui: add HGPLAIN environment variable for easier scripting...
r10455 if k in cfg['ui']:
del cfg['ui'][k]
"Yann E. MORIN"
ui: enable alias exception when reading config in plain mode...
r14373 for k, v in cfg.items('defaults'):
del cfg['defaults'][k]
# Don't remove aliases from the configuration if in the exceptionlist
if self.plain('alias'):
Brodie Rao
ui: suppress aliases when HGPLAIN is set
r10506 for k, v in cfg.items('alias'):
del cfg['alias'][k]
Siddharth Agarwal
ui: disable revsetaliases in plain mode (BC)...
r24883 if self.plain('revsetalias'):
for k, v in cfg.items('revsetalias'):
del cfg['revsetalias'][k]
Brodie Rao
ui: add HGPLAIN environment variable for easier scripting...
r10455
Matt Mackall
ui: fold readsections into readconfig...
r8142 if trusted:
Matt Mackall
ui: privatize cdata vars
r8203 self._tcfg.update(cfg)
self._tcfg.update(self._ocfg)
self._ucfg.update(cfg)
self._ucfg.update(self._ocfg)
Matt Mackall
ui: always have ucdata...
r8139
Alexis S. L. Carvalho
ui.py: normalize settings every time the configuration changes...
r3347 if root is None:
root = os.path.expanduser('~')
self.fixconfig(root=root)
Alexis S. L. Carvalho
load extensions only after the ui object has been completely initialized...
r3014
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 def fixconfig(self, root=None, section=None):
if section in (None, 'paths'):
# expand vars and ~
# translate paths relative to root (or home) into absolute paths
root = root or os.getcwd()
for c in self._tcfg, self._ucfg, self._ocfg:
for n, p in c.items('paths'):
if not p:
continue
if '%%' in p:
self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
% (n, p, self.configsource('paths', n)))
p = p.replace('%%', '%')
p = util.expandpath(p)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if not util.hasscheme(p) and not os.path.isabs(p):
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 p = os.path.normpath(os.path.join(root, p))
c.set("paths", n, p)
Alexis S. L. Carvalho
ui.py: normalize settings every time the configuration changes...
r3347
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 if section in (None, 'ui'):
# update ui options
self.debugflag = self.configbool('ui', 'debug')
self.verbose = self.debugflag or self.configbool('ui', 'verbose')
self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
if self.verbose and self.quiet:
self.quiet = self.verbose = False
Ry4an Brase
ui: always report untrusted hgrc files when debug enabled...
r13493 self._reportuntrusted = self.debugflag or self.configbool("ui",
"report_untrusted", True)
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 self.tracebackflag = self.configbool('ui', 'traceback', False)
Alexis S. L. Carvalho
update ui.quiet/verbose/debug/interactive every time the config changes...
r3350
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 if section in (None, 'trusted'):
# update trust information
self._trustusers.update(self.configlist('trusted', 'users'))
self._trustgroups.update(self.configlist('trusted', 'groups'))
Alexis S. L. Carvalho
Only read .hg/hgrc files from trusted users/groups...
r3551
Pierre-Yves David
config: have a way to backup and restore value in config...
r15919 def backupconfig(self, section, item):
return (self._ocfg.backup(section, item),
self._tcfg.backup(section, item),
self._ucfg.backup(section, item),)
def restoreconfig(self, data):
self._ocfg.restore(data[0])
self._tcfg.restore(data[1])
self._ucfg.restore(data[2])
Mads Kiilerich
config: give a useful hint of source for the most common command line settings...
r20788 def setconfig(self, section, name, value, source=''):
Mads Kiilerich
config: backout 77f1f206e135 - 743daa601445 removed the only use of overlay
r20787 for cfg in (self._ocfg, self._tcfg, self._ucfg):
Mads Kiilerich
config: give a useful hint of source for the most common command line settings...
r20788 cfg.set(section, name, value, source)
Nicolas Dumazet
ui: only fix config if the relevant section has changed...
r12764 self.fixconfig(section=section)
mpm@selenic.com
Add ui.setconfig overlay...
r960
Matt Mackall
ui: _get_cdata -> _data
r8199 def _data(self, untrusted):
Matt Mackall
ui: privatize cdata vars
r8203 return untrusted and self._ucfg or self._tcfg
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552
Matt Mackall
showconfig: show source file and line with --debug
r8182 def configsource(self, section, name, untrusted=False):
Matt Mackall
ui: _get_cdata -> _data
r8199 return self._data(untrusted).source(section, name) or 'none'
Matt Mackall
showconfig: show source file and line with --debug
r8182
Matt Mackall
ui: introduce new config parser
r8144 def config(self, section, name, default=None, untrusted=False):
Matt Mackall
ui: allow alternatives for config options
r15035 if isinstance(name, list):
alternates = name
else:
alternates = [name]
for n in alternates:
Augie Fackler
ui.config: fix bug in config alternatives from cc669e4fec95
r19536 value = self._data(untrusted).get(section, n, None)
Matt Mackall
ui: allow alternatives for config options
r15035 if value is not None:
name = n
break
else:
value = default
Matt Mackall
ui: report_untrusted fixes...
r8204 if self.debugflag and not untrusted and self._reportuntrusted:
Augie Fackler
ui.config: fix bug in config alternatives from cc669e4fec95
r19536 for n in alternates:
uvalue = self._ucfg.get(section, n)
if uvalue is not None and uvalue != value:
self.debug("ignoring untrusted configuration option "
"%s.%s = %s\n" % (section, n, uvalue))
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 return value
Alexis S. L. Carvalho
ui.py: move common code out of config and configbool
r3341
Gregory Szorc
ui: add method to return option and all sub-options...
r27252 def configsuboptions(self, section, name, default=None, untrusted=False):
"""Get a config option and all sub-options.
Some config options have sub-options that are declared with the
format "key:opt = value". This method is used to return the main
option and all its declared sub-options.
Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
is a dict of defined sub-options where keys and values are strings.
"""
data = self._data(untrusted)
main = data.get(section, name, default)
if self.debugflag and not untrusted and self._reportuntrusted:
uvalue = self._ucfg.get(section, name)
if uvalue is not None and uvalue != main:
self.debug('ignoring untrusted configuration option '
'%s.%s = %s\n' % (section, name, uvalue))
sub = {}
prefix = '%s:' % name
for k, v in data.items(section):
if k.startswith(prefix):
sub[k[len(prefix):]] = v
if self.debugflag and not untrusted and self._reportuntrusted:
for k, v in sub.items():
uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
if uvalue is not None and uvalue != v:
self.debug('ignoring untrusted configuration option '
'%s:%s.%s = %s\n' % (section, name, k, uvalue))
return main, sub
Matt Mackall
ui: add configpath helper
r13238 def configpath(self, section, name, default=None, untrusted=False):
Simon Heimberg
ui: config path relative to repo root
r14924 'get a path config item, expanded relative to repo root or config file'
Matt Mackall
ui: add configpath helper
r13238 v = self.config(section, name, default, untrusted)
Simon Heimberg
ui: providing no default value to configpath should not raise an Error
r14923 if v is None:
return None
Matt Mackall
ui: add configpath helper
r13238 if not os.path.isabs(v) or "://" not in v:
src = self.configsource(section, name, untrusted)
if ':' in src:
Simon Heimberg
ui: fix error, base can not be a list
r14922 base = os.path.dirname(src.rsplit(':')[0])
Matt Mackall
ui: add configpath helper
r13238 v = os.path.join(base, os.path.expanduser(v))
return v
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 def configbool(self, section, name, default=False, untrusted=False):
Sune Foldager
ui: add configint function and tests
r14171 """parse a configuration element as a boolean
>>> u = ui(); s = 'foo'
>>> u.setconfig(s, 'true', 'yes')
>>> u.configbool(s, 'true')
True
>>> u.setconfig(s, 'false', 'no')
>>> u.configbool(s, 'false')
False
>>> u.configbool(s, 'unknown')
False
>>> u.configbool(s, 'unknown', True)
True
>>> u.setconfig(s, 'invalid', 'somevalue')
>>> u.configbool(s, 'invalid')
Traceback (most recent call last):
...
ConfigError: foo.invalid is not a boolean ('somevalue')
"""
Matt Mackall
ui: introduce new config parser
r8144 v = self.config(section, name, None, untrusted)
Martin Geisler
use 'x is None' instead of 'x == None'...
r8527 if v is None:
Matt Mackall
ui: introduce new config parser
r8144 return default
Dirkjan Ochtman
ui: just return it if it's already a bool
r10243 if isinstance(v, bool):
return v
Augie Fackler
parsebool: create new function and use it for config parsing
r12087 b = util.parsebool(v)
if b is None:
Sune Foldager
ui: add configint function and tests
r14171 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
Matt Mackall
ui: introduce new config parser
r8144 % (section, name, v))
Augie Fackler
parsebool: create new function and use it for config parsing
r12087 return b
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552
Sune Foldager
ui: add configint function and tests
r14171 def configint(self, section, name, default=None, untrusted=False):
"""parse a configuration element as an integer
>>> u = ui(); s = 'foo'
>>> u.setconfig(s, 'int1', '42')
>>> u.configint(s, 'int1')
42
>>> u.setconfig(s, 'int2', '-42')
>>> u.configint(s, 'int2')
-42
>>> u.configint(s, 'unknown', 7)
7
>>> u.setconfig(s, 'invalid', 'somevalue')
>>> u.configint(s, 'invalid')
Traceback (most recent call last):
...
ConfigError: foo.invalid is not an integer ('somevalue')
"""
v = self.config(section, name, None, untrusted)
if v is None:
return default
try:
return int(v)
except ValueError:
raise error.ConfigError(_("%s.%s is not an integer ('%s')")
% (section, name, v))
Bryan O'Sullivan
ui: add a configbytes method, for space configuration...
r19065 def configbytes(self, section, name, default=0, untrusted=False):
"""parse a configuration element as a quantity in bytes
Units can be specified as b (bytes), k or kb (kilobytes), m or
mb (megabytes), g or gb (gigabytes).
>>> u = ui(); s = 'foo'
>>> u.setconfig(s, 'val1', '42')
>>> u.configbytes(s, 'val1')
42
>>> u.setconfig(s, 'val2', '42.5 kb')
>>> u.configbytes(s, 'val2')
43520
>>> u.configbytes(s, 'unknown', '7 MB')
7340032
>>> u.setconfig(s, 'invalid', 'somevalue')
>>> u.configbytes(s, 'invalid')
Traceback (most recent call last):
...
ConfigError: foo.invalid is not a byte quantity ('somevalue')
"""
Bryan O'Sullivan
ui: use util.sizetoint in configbytes
r19195 value = self.config(section, name)
if value is None:
Bryan O'Sullivan
ui: add a configbytes method, for space configuration...
r19065 if not isinstance(default, str):
return default
Bryan O'Sullivan
ui: use util.sizetoint in configbytes
r19195 value = default
Bryan O'Sullivan
ui: add a configbytes method, for space configuration...
r19065 try:
Bryan O'Sullivan
ui: use util.sizetoint in configbytes
r19195 return util.sizetoint(value)
except error.ParseError:
Bryan O'Sullivan
ui: add a configbytes method, for space configuration...
r19065 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
Bryan O'Sullivan
ui: use util.sizetoint in configbytes
r19195 % (section, name, value))
Bryan O'Sullivan
ui: add a configbytes method, for space configuration...
r19065
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 def configlist(self, section, name, default=None, untrusted=False):
Sune Foldager
ui: add configint function and tests
r14171 """parse a configuration element as a list of comma/space separated
strings
>>> u = ui(); s = 'foo'
>>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
>>> u.configlist(s, 'list1')
['this', 'is', 'a small', 'test']
"""
Henrik Stuart
ui: support quotes in configlist (issue2147)...
r10982
def _parse_plain(parts, s, offset):
whitespace = False
while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
whitespace = True
offset += 1
if offset >= len(s):
return None, parts, offset
if whitespace:
parts.append('')
if s[offset] == '"' and not parts[-1]:
return _parse_quote, parts, offset + 1
elif s[offset] == '"' and parts[-1][-1] == '\\':
parts[-1] = parts[-1][:-1] + s[offset]
return _parse_plain, parts, offset + 1
parts[-1] += s[offset]
return _parse_plain, parts, offset + 1
def _parse_quote(parts, s, offset):
if offset < len(s) and s[offset] == '"': # ""
parts.append('')
offset += 1
while offset < len(s) and (s[offset].isspace() or
s[offset] == ','):
offset += 1
return _parse_plain, parts, offset
while offset < len(s) and s[offset] != '"':
Henrik Stuart
ui: fix check-code error
r11036 if (s[offset] == '\\' and offset + 1 < len(s)
and s[offset + 1] == '"'):
Henrik Stuart
ui: support quotes in configlist (issue2147)...
r10982 offset += 1
parts[-1] += '"'
else:
parts[-1] += s[offset]
offset += 1
if offset >= len(s):
real_parts = _configlist(parts[-1])
if not real_parts:
parts[-1] = '"'
else:
real_parts[0] = '"' + real_parts[0]
parts = parts[:-1]
parts.extend(real_parts)
return None, parts, offset
offset += 1
while offset < len(s) and s[offset] in [' ', ',']:
offset += 1
if offset < len(s):
if offset + 1 == len(s) and s[offset] == '"':
parts[-1] += '"'
offset += 1
else:
parts.append('')
else:
return None, parts, offset
return _parse_plain, parts, offset
def _configlist(s):
s = s.rstrip(' ,')
if not s:
Alecs King
ui: differentiate empty configlist from None
r11945 return []
Henrik Stuart
ui: support quotes in configlist (issue2147)...
r10982 parser, parts, offset = _parse_plain, [''], 0
while parser:
parser, parts, offset = parser(parts, s, offset)
return parts
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 result = self.config(section, name, untrusted=untrusted)
Thomas Arendsen Hein
Added ui.configlist method to get comma/space separated lists of strings....
r2499 if result is None:
Thomas Arendsen Hein
Allow using default values with ui.configlist, too, and add a test for this.
r2502 result = default or []
if isinstance(result, basestring):
Thomas Arendsen Hein
ui: handle leading newlines/spaces/commas in configlist...
r11309 result = _configlist(result.lstrip(' ,\n'))
Henrik Stuart
ui: support quotes in configlist (issue2147)...
r10982 if result is None:
result = default or []
Thomas Arendsen Hein
Allow using default values with ui.configlist, too, and add a test for this.
r2502 return result
Thomas Arendsen Hein
Added ui.configlist method to get comma/space separated lists of strings....
r2499
Bryan O'Sullivan
config: add hasconfig method and supporting plumbing...
r27696 def hasconfig(self, section, name, untrusted=False):
return self._data(untrusted).hasitem(section, name)
Bryan O'Sullivan
ui: Rename has_config to has_section.
r4487 def has_section(self, section, untrusted=False):
Vadim Gelfer
add ui.has_config method.
r2343 '''tell whether section exists in config.'''
Matt Mackall
ui: _get_cdata -> _data
r8199 return section in self._data(untrusted)
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552
Gregory Szorc
ui: optionally ignore sub-options from configitems()...
r27253 def configitems(self, section, untrusted=False, ignoresub=False):
Matt Mackall
ui: _get_cdata -> _data
r8199 items = self._data(untrusted).items(section)
Gregory Szorc
ui: optionally ignore sub-options from configitems()...
r27253 if ignoresub:
newitems = {}
for k, v in items:
if ':' not in k:
newitems[k] = v
items = newitems.items()
Matt Mackall
ui: report_untrusted fixes...
r8204 if self.debugflag and not untrusted and self._reportuntrusted:
Dirkjan Ochtman
more whitespace cleanup and some other style nits
r8222 for k, v in self._ucfg.items(section):
Matt Mackall
ui: privatize cdata vars
r8203 if self._tcfg.get(section, k) != v:
David Soria Parra
i18n: remove translation of debug messages
r14708 self.debug("ignoring untrusted configuration option "
"%s.%s = %s\n" % (section, k, v))
Matt Mackall
ui: introduce new config parser
r8144 return items
mpm@selenic.com
ui: add configuration file support...
r285
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 def walkconfig(self, untrusted=False):
Matt Mackall
ui: privatize cdata vars
r8203 cfg = self._data(untrusted)
for section in cfg.sections():
Alexis S. L. Carvalho
save settings from untrusted config files in a separate configparser...
r3552 for name, value in self.configitems(section, untrusted):
Martin Geisler
ui: yield unchanged values in walkconfig...
r13576 yield section, name, value
Bryan O'Sullivan
Add commands.debugconfig....
r1028
"Yann E. MORIN"
ui: test plain mode against exceptions...
r14372 def plain(self, feature=None):
Dan Villiom Podlaski Christiansen
ui: document the formatted(), interactive() & plain() functions.
r11325 '''is plain mode active?
Brodie Rao
HGPLAIN: allow exceptions to plain mode, like i18n, via HGPLAINEXCEPT...
r13849 Plain mode means that all configuration variables which affect
the behavior and output of Mercurial should be
ignored. Additionally, the output should be stable,
reproducible and suitable for use in scripts or applications.
The only way to trigger plain mode is by setting either the
`HGPLAIN' or `HGPLAINEXCEPT' environment variables.
Dan Villiom Podlaski Christiansen
ui: document the formatted(), interactive() & plain() functions.
r11325
"Yann E. MORIN"
ui: test plain mode against exceptions...
r14372 The return value can either be
- False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
- True otherwise
Dan Villiom Podlaski Christiansen
ui: document the formatted(), interactive() & plain() functions.
r11325 '''
Brodie Rao
HGPLAIN: allow exceptions to plain mode, like i18n, via HGPLAINEXCEPT...
r13849 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
return False
exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
"Yann E. MORIN"
ui: test plain mode against exceptions...
r14372 if feature and exceptions:
return feature not in exceptions
return True
Brodie Rao
ui: add HGPLAIN environment variable for easier scripting...
r10455
Matt Mackall
Add username/merge/editor to .hgrc...
r608 def username(self):
Thomas Arendsen Hein
Adapted behaviour of ui.username() to documentation and mention it explicitly:...
r1985 """Return default username to be used in commits.
Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
and stop searching if one of these is set.
Benoit Boissinot
ui: add an option to prompt for the username when it isn't provided...
r6862 If not found and ui.askusername is True, ask the user, else use
($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
Thomas Arendsen Hein
Adapted behaviour of ui.username() to documentation and mention it explicitly:...
r1985 """
user = os.environ.get("HGUSER")
if user is None:
anatoly techtonik
config: allow 'user' in .hgrc ui section (issue3169)
r21955 user = self.config("ui", ["username", "user"])
Chad Dombrova
ui.username(): expand environment variables in username configuration value....
r11225 if user is not None:
user = os.path.expandvars(user)
Thomas Arendsen Hein
Adapted behaviour of ui.username() to documentation and mention it explicitly:...
r1985 if user is None:
user = os.environ.get("EMAIL")
Benoit Boissinot
ui: add an option to prompt for the username when it isn't provided...
r6862 if user is None and self.configbool("ui", "askusername"):
Martin Geisler
lowercase prompts...
r7600 user = self.prompt(_("enter a commit username:"), default=None)
Martin Geisler
ui: only use "user@host" as username in noninteractive mode...
r9613 if user is None and not self.interactive():
Benoit Boissinot
only print a warning when no username is specified...
r3721 try:
user = '%s@%s' % (util.getuser(), socket.getfqdn())
Martin Geisler
ui: lowercase "no username" warning
r16940 self.warn(_("no username found, using '%s' instead\n") % user)
Benoit Boissinot
only print a warning when no username is specified...
r3721 except KeyError:
Thomas Arendsen Hein
Abort on empty username so specifying a username can be forced....
r4044 pass
if not user:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('no username supplied'),
Matt Mackall
ui: suggest config --edit when no username is set
r20574 hint=_('use "hg config --edit" '
Matt Mackall
ui: fix extra space in username abort
r20580 'to set your username'))
Matt Mackall
ui: disallow newlines in usernames (issue1034)
r6351 if "\n" in user:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("username %s contains a newline\n")
% repr(user))
Thomas Arendsen Hein
Adapted behaviour of ui.username() to documentation and mention it explicitly:...
r1985 return user
Matt Mackall
Add username/merge/editor to .hgrc...
r608
Thomas Arendsen Hein
Move generating short username to display in hg/hgweb annotate to ui module.
r1129 def shortuser(self, user):
"""Return a short representation of a user name or email address."""
Matt Mackall
many, many trivial check-code fixups
r10282 if not self.verbose:
user = util.shortuser(user)
Thomas Arendsen Hein
Move generating short username to display in hg/hgweb annotate to ui module.
r1129 return user
Vadim Gelfer
push, outgoing, bundle: fall back to "default" if "default-push" not defined
r2494 def expandpath(self, loc, default=None):
Thomas Arendsen Hein
Directory names take precedence over symbolic names consistently....
r1892 """Return repository location relative to cwd or from [paths]"""
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 try:
p = self.paths.getpath(loc)
if p:
return p.rawloc
except error.RepoError:
pass
if default:
try:
p = self.paths.getpath(default)
if p:
return p.rawloc
except error.RepoError:
pass
Gregory Szorc
ui: represent paths as classes...
r24250 return loc
@util.propertycache
def paths(self):
return paths(self)
mpm@selenic.com
[PATCH] Add ui.expandpath command...
r506
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 def pushbuffer(self, error=False, subproc=False, labeled=False):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 """install a buffer to capture standard output of the ui object
Pierre-Yves David
ui: pushbuffer can now also capture stderr...
r21132
Pierre-Yves David
ui: allow capture of subprocess output...
r24848 If error is True, the error output will be captured too.
If subproc is True, output from subprocesses (typically hooks) will be
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 captured too.
Brodie Rao
ui: add ui.write() output labeling API...
r10815
If labeled is True, any labels associated with buffered
output will be handled. By default, this has no effect
on the output returned, but extensions and GUI tools may
handle this argument and returned styled output. If output
is being buffered so it can be captured and parsed or
processed, labeled should not be set to True.
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 """
Matt Mackall
ui: buffers -> _buffers
r8202 self._buffers.append([])
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 self._bufferstates.append((error, subproc, labeled))
self._bufferapplylabels = labeled
Matt Mackall
add a simple nested buffering scheme to ui
r3737
Gregory Szorc
ui: remove labeled argument from popbuffer...
r27109 def popbuffer(self):
'''pop the last buffer and return the buffered output'''
Pierre-Yves David
ui: pushbuffer can now also capture stderr...
r21132 self._bufferstates.pop()
Gregory Szorc
ui: track label expansion when creating buffers...
r27106 if self._bufferstates:
self._bufferapplylabels = self._bufferstates[-1][2]
else:
self._bufferapplylabels = None
Matt Mackall
ui: buffers -> _buffers
r8202 return "".join(self._buffers.pop())
Matt Mackall
add a simple nested buffering scheme to ui
r3737
Brodie Rao
ui: add ui.write() output labeling API...
r10815 def write(self, *args, **opts):
'''write args to output
By default, this method simply writes to the buffer or stdout,
but extensions or GUI tools may override this method,
write_err(), popbuffer(), and label() to style output from
various parts of hg.
An optional keyword argument, "label", can be passed in.
This should be a string containing label names separated by
space. Label names take the form of "topic.type". For example,
ui.debug() issues a label of "ui.debug".
When labeling output for a specific command, a label of
"cmdname.type" is recommended. For example, status issues
a label of "status.modified" for modified files.
'''
timeless
ui: add prompt argument to write (issue5154) (API)...
r28633 if self._buffers and not opts.get('prompt', False):
Gregory Szorc
ui: avoid needless casting to a str...
r27110 self._buffers[-1].extend(a for a in args)
Matt Mackall
add a simple nested buffering scheme to ui
r3737 else:
Gregory Szorc
ui.write: don't clear progress bar when writing to a buffer...
r27068 self._progclear()
Matt Mackall
add a simple nested buffering scheme to ui
r3737 for a in args:
Gregory Szorc
ui: avoid needless casting to a str...
r27110 self.fout.write(a)
mpm@selenic.com
[PATCH] Make ui.warn write to stderr...
r565
Brodie Rao
ui: add ui.write() output labeling API...
r10815 def write_err(self, *args, **opts):
Pierre-Yves David
progress: move all logic altering the ui object logic in mercurial.ui...
r25499 self._progclear()
Benoit Boissinot
ignore EPIPE in ui.err_write...
r1989 try:
Pierre-Yves David
ui: allow capture of subprocess output...
r24848 if self._bufferstates and self._bufferstates[-1][0]:
Pierre-Yves David
ui: pushbuffer can now also capture stderr...
r21132 return self.write(*args, **opts)
Idan Kamara
ui: use I/O descriptors internally...
r14614 if not getattr(self.fout, 'closed', False):
self.fout.flush()
Benoit Boissinot
ignore EPIPE in ui.err_write...
r1989 for a in args:
Gregory Szorc
ui: avoid needless casting to a str...
r27110 self.ferr.write(a)
Patrick Mezard
Flush stderr after write....
r4023 # stderr may be buffered under win32 when redirected to files,
# including stdout.
Idan Kamara
ui: use I/O descriptors internally...
r14614 if not getattr(self.ferr, 'closed', False):
self.ferr.flush()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Kevin Bullock
ui: swallow EBADF on stderr...
r16367 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
Benoit Boissinot
ignore EPIPE in ui.err_write...
r1989 raise
mpm@selenic.com
[PATCH] Make ui.warn write to stderr...
r565
Vadim Gelfer
make ui flush output. this makes error happen if printing to /dev/full....
r1837 def flush(self):
Idan Kamara
ui: use I/O descriptors internally...
r14614 try: self.fout.flush()
Brodie Rao
cleanup: replace more naked excepts with more specific ones
r16703 except (IOError, ValueError): pass
Idan Kamara
ui: use I/O descriptors internally...
r14614 try: self.ferr.flush()
Brodie Rao
cleanup: replace more naked excepts with more specific ones
r16703 except (IOError, ValueError): pass
Vadim Gelfer
make ui flush output. this makes error happen if printing to /dev/full....
r1837
Matt Mackall
ui: add _isatty method to easily disable cooked I/O
r16751 def _isatty(self, fh):
if self.configbool('ui', 'nontty', False):
return False
return util.isatty(fh)
Vadim Gelfer
make ui flush output. this makes error happen if printing to /dev/full....
r1837
Simon Farnsworth
ui: add new config flag for interface selection...
r28542 def interface(self, feature):
"""what interface to use for interactive console features?
The interface is controlled by the value of `ui.interface` but also by
the value of feature-specific configuration. For example:
ui.interface.histedit = text
ui.interface.chunkselector = curses
Here the features are "histedit" and "chunkselector".
The configuration above means that the default interfaces for commands
is curses, the interface for histedit is text and the interface for
selecting chunk is crecord (the best curses interface available).
Consider the following exemple:
ui.interface = curses
ui.interface.histedit = text
Then histedit will use the text interface and chunkselector will use
the default curses interface (crecord at the moment).
"""
alldefaults = frozenset(["text", "curses"])
featureinterfaces = {
"chunkselector": [
"text",
"curses",
]
}
# Feature-specific interface
if feature not in featureinterfaces.keys():
# Programming error, not user error
raise ValueError("Unknown feature requested %s" % feature)
availableinterfaces = frozenset(featureinterfaces[feature])
if alldefaults > availableinterfaces:
# Programming error, not user error. We need a use case to
# define the right thing to do here.
raise ValueError(
"Feature %s does not handle all default interfaces" %
feature)
if self.plain():
return "text"
# Default interface for all the features
defaultinterface = "text"
i = self.config("ui", "interface", None)
if i in alldefaults:
defaultinterface = i
choseninterface = defaultinterface
f = self.config("ui", "interface.%s" % feature, None)
if f in availableinterfaces:
choseninterface = f
if i is not None and defaultinterface != i:
if f is not None:
self.warn(_("invalid value for ui.interface: %s\n") %
(i,))
else:
self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
(i, choseninterface))
if f is not None and choseninterface != f:
self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
(feature, f, choseninterface))
return choseninterface
Matt Mackall
ui: make interactive a method
r8208 def interactive(self):
Dan Villiom Podlaski Christiansen
ui: document the formatted(), interactive() & plain() functions.
r11325 '''is interactive input allowed?
An interactive session is a session where input can be reasonably read
from `sys.stdin'. If this function returns false, any attempt to read
from stdin should fail with an error, unless a sensible default has been
specified.
Interactiveness is triggered by the value of the `ui.interactive'
configuration variable or - if it is unset - when `sys.stdin' points
to a terminal device.
This function refers to input only; for output, see `ui.formatted()'.
'''
Patrick Mezard
ui: honor interactive=off even if isatty()
r8538 i = self.configbool("ui", "interactive", None)
if i is None:
Idan Kamara
util: add helper function isatty(fd) to check for tty-ness
r14515 # some environments replace stdin without implementing isatty
# usually those are non-interactive
Matt Mackall
ui: add _isatty method to easily disable cooked I/O
r16751 return self._isatty(self.fin)
Ronny Pfannschmidt
make ui.interactive() return false in case stdin lacks isatty
r10077
Patrick Mezard
ui: honor interactive=off even if isatty()
r8538 return i
Matt Mackall
ui: make interactive a method
r8208
Augie Fackler
termwidth: move to ui.ui from util
r12689 def termwidth(self):
'''how wide is the terminal in columns?
'''
if 'COLUMNS' in os.environ:
try:
return int(os.environ['COLUMNS'])
except ValueError:
pass
return util.termwidth()
Dan Villiom Podlaski Christiansen
ui: add ui.formatted configuration variable and accessor function....
r11324 def formatted(self):
Dan Villiom Podlaski Christiansen
ui: document the formatted(), interactive() & plain() functions.
r11325 '''should formatted output be used?
It is often desirable to format the output to suite the output medium.
Examples of this are truncating long lines or colorizing messages.
However, this is not often not desirable when piping output into other
utilities, e.g. `grep'.
Formatted output is triggered by the value of the `ui.formatted'
configuration variable or - if it is unset - when `sys.stdout' points
to a terminal device. Please note that `ui.formatted' should be
considered an implementation detail; it is not intended for use outside
Mercurial or its extensions.
This function refers to output only; for input, see `ui.interactive()'.
This function always returns false when in plain mode, see `ui.plain()'.
'''
Dan Villiom Podlaski Christiansen
ui: add ui.formatted configuration variable and accessor function....
r11324 if self.plain():
return False
i = self.configbool("ui", "formatted", None)
if i is None:
Idan Kamara
util: add helper function isatty(fd) to check for tty-ness
r14515 # some environments replace stdout without implementing isatty
# usually those are non-interactive
Matt Mackall
ui: add _isatty method to easily disable cooked I/O
r16751 return self._isatty(self.fout)
Dan Villiom Podlaski Christiansen
ui: add ui.formatted configuration variable and accessor function....
r11324
return i
Dirkjan Ochtman
Don't try to determine interactivity if ui() called with interactive=False....
r5337 def _readline(self, prompt=''):
Matt Mackall
ui: add _isatty method to easily disable cooked I/O
r16751 if self._isatty(self.fin):
Bryan O'Sullivan
ui: get readline and prompt to behave better depending on interactivity
r5036 try:
# magically add command line editing support, where
# available
import readline
# force demandimport to really load the module
readline.read_history_file
Brendan Cully
issue1419: catch strange readline import error on windows
r7496 # windows sometimes raises something other than ImportError
except Exception:
Bryan O'Sullivan
ui: get readline and prompt to behave better depending on interactivity
r5036 pass
Idan Kamara
ui: use I/O descriptors internally...
r14614
Idan Kamara
ui: call write() so the prompt string goes through subclassed implementation
r15000 # call write() so output goes through subclassed implementation
# e.g. color extension on Windows
timeless
ui: add prompt argument to write (issue5154) (API)...
r28633 self.write(prompt, prompt=True)
Idan Kamara
ui: call write() so the prompt string goes through subclassed implementation
r15000
Martin Geisler
ui: also swap sys.stdout with self.fout in _readline...
r15062 # instead of trying to emulate raw_input, swap (self.fin,
# self.fout) with (sys.stdin, sys.stdout)
oldin = sys.stdin
oldout = sys.stdout
Idan Kamara
ui: call write() so the prompt string goes through subclassed implementation
r15000 sys.stdin = self.fin
Martin Geisler
ui: also swap sys.stdout with self.fout in _readline...
r15062 sys.stdout = self.fout
Yuya Nishihara
ui: add brief comment why raw_input() needs dummy ' ' prompt string...
r22291 # prompt ' ' must exist; otherwise readline may delete entire line
# - http://bugs.python.org/issue12833
Idan Kamara
ui: pass ' ' to raw_input when prompting...
r15053 line = raw_input(' ')
Martin Geisler
ui: also swap sys.stdout with self.fout in _readline...
r15062 sys.stdin = oldin
sys.stdout = oldout
Idan Kamara
ui: use I/O descriptors internally...
r14614
Steve Borho
workaround for raw_input() on Windows...
r5613 # When stdin is in binary mode on Windows, it can cause
# raw_input() to emit an extra trailing carriage return
if os.linesep == '\r\n' and line and line[-1] == '\r':
line = line[:-1]
return line
Bryan O'Sullivan
ui: get readline and prompt to behave better depending on interactivity
r5036
Simon Heimberg
ui: extract choice from prompt...
r9048 def prompt(self, msg, default="y"):
"""Prompt user with msg, read response.
If ui is not interactive, the default is returned.
Kirill Smelkov
prompt: kill matchflags...
r5751 """
Matt Mackall
ui: make interactive a method
r8208 if not self.interactive():
Yuya Nishihara
ui: fix crash by non-interactive prompt echo for user name...
r28039 self.write(msg, ' ', default or '', "\n")
Peter Arrenbrecht
ui: log non-interactive default response to stdout when verbose...
r7320 return default
Simon Heimberg
ui: extract choice from prompt...
r9048 try:
Idan Kamara
ui: pass ' ' to raw_input when prompting...
r15053 r = self._readline(self.label(msg, 'ui.prompt'))
Simon Heimberg
ui: extract choice from prompt...
r9048 if not r:
Mads Kiilerich
ui: show prompt choice if input is not a tty but is forced to be interactive...
r22589 r = default
Yuya Nishihara
ui: separate option to show prompt echo, enabled only in tests (issue4417)...
r23053 if self.configbool('ui', 'promptecho'):
Mads Kiilerich
ui: show prompt choice if input is not a tty but is forced to be interactive...
r22589 self.write(r, "\n")
Simon Heimberg
ui: extract choice from prompt...
r9048 return r
except EOFError:
Siddharth Agarwal
error: add structured exception for EOF at prompt...
r26896 raise error.ResponseExpected()
Simon Heimberg
ui: extract choice from prompt...
r9048
FUJIWARA Katsunori
ui: add "extractchoices()" to share the logic to extract choices from prompt
r20265 @staticmethod
def extractchoices(prompt):
"""Extract prompt message and list of choices from specified prompt.
This returns tuple "(message, choices)", and "choices" is the
list of tuple "(response character, text without &)".
Matt Mackall
ui: try to handle $$ more robustly in prompts (issue4970)
r27392
>>> ui.extractchoices("awake? $$ &Yes $$ &No")
('awake? ', [('y', 'Yes'), ('n', 'No')])
>>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
>>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
FUJIWARA Katsunori
ui: add "extractchoices()" to share the logic to extract choices from prompt
r20265 """
Matt Mackall
ui: try to handle $$ more robustly in prompts (issue4970)
r27392
# Sadly, the prompt string may have been built with a filename
# containing "$$" so let's try to find the first valid-looking
# prompt to start parsing. Sadly, we also can't rely on
# choices containing spaces, ASCII, or basically anything
# except an ampersand followed by a character.
m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
msg = m.group(1)
choices = [p.strip(' ') for p in m.group(2).split('$$')]
FUJIWARA Katsunori
ui: add "extractchoices()" to share the logic to extract choices from prompt
r20265 return (msg,
[(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
for s in choices])
Matt Mackall
ui: merge prompt text components into a singe string...
r19226 def promptchoice(self, prompt, default=0):
"""Prompt user with a message, read response, and ensure it matches
one of the provided choices. The prompt is formatted as follows:
"would you like fries with that (Yn)? $$ &Yes $$ &No"
The index of the choice is returned. Responses are case
insensitive. If ui is not interactive, the default is
returned.
Simon Heimberg
ui: extract choice from prompt...
r9048 """
Matt Mackall
ui: merge prompt text components into a singe string...
r19226
FUJIWARA Katsunori
ui: add "extractchoices()" to share the logic to extract choices from prompt
r20265 msg, choices = self.extractchoices(prompt)
resps = [r for r, t in choices]
Thomas Arendsen Hein
Make ui.prompt repeat on "unrecognized response" again (issue897)...
r5671 while True:
Simon Heimberg
ui: extract choice from prompt...
r9048 r = self.prompt(msg, resps[default])
if r.lower() in resps:
return resps.index(r.lower())
self.write(_("unrecognized response\n"))
Vadim Gelfer
prompt user for http authentication info...
r2281 def getpass(self, prompt=None, default=None):
Matt Mackall
many, many trivial check-code fixups
r10282 if not self.interactive():
return default
Steve Borho
catch CTRL-D at password prompt...
r7798 try:
Matt Mackall
ui: send password prompts to stderr again (issue4056)
r19880 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
Yuya Nishihara
cmdserver: forcibly use L channel to read password input (issue3161)...
r21195 # disable getpass() only if explicitly specified. it's still valid
# to interact with tty even if fin is not a tty.
if self.configbool('ui', 'nontty'):
return self.fin.readline().rstrip('\n')
else:
return getpass.getpass('')
Steve Borho
catch CTRL-D at password prompt...
r7798 except EOFError:
Siddharth Agarwal
error: add structured exception for EOF at prompt...
r26896 raise error.ResponseExpected()
Brodie Rao
ui: add ui.write() output labeling API...
r10815 def status(self, *msg, **opts):
'''write status message to output (if ui.quiet is False)
This adds an output label of "ui.status".
'''
Matt Mackall
many, many trivial check-code fixups
r10282 if not self.quiet:
Brodie Rao
ui: add ui.write() output labeling API...
r10815 opts['label'] = opts.get('label', '') + ' ui.status'
self.write(*msg, **opts)
def warn(self, *msg, **opts):
'''write warning message to output (stderr)
This adds an output label of "ui.warning".
'''
opts['label'] = opts.get('label', '') + ' ui.warning'
self.write_err(*msg, **opts)
def note(self, *msg, **opts):
'''write note to output (if ui.verbose is True)
This adds an output label of "ui.note".
'''
Matt Mackall
many, many trivial check-code fixups
r10282 if self.verbose:
Brodie Rao
ui: add ui.write() output labeling API...
r10815 opts['label'] = opts.get('label', '') + ' ui.note'
self.write(*msg, **opts)
def debug(self, *msg, **opts):
'''write debug message to output (if ui.debugflag is True)
This adds an output label of "ui.debug".
'''
Matt Mackall
many, many trivial check-code fixups
r10282 if self.debugflag:
Brodie Rao
ui: add ui.write() output labeling API...
r10815 opts['label'] = opts.get('label', '') + ' ui.debug'
self.write(*msg, **opts)
FUJIWARA Katsunori
cmdutil: make in-memory changes visible to external editor (issue4378)...
r26750
def edit(self, text, user, extra=None, editform=None, pending=None):
Jordi GutiƩrrez Hermoso
edit: allow to configure the suffix of the temporary filename...
r28635 extra_defaults = {
'prefix': 'editor',
'suffix': '.txt',
}
Mykola Nikishov
ui: allow open editor with custom filename...
r27153 if extra is not None:
extra_defaults.update(extra)
extra = extra_defaults
(fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
Jordi GutiƩrrez Hermoso
edit: allow to configure the suffix of the temporary filename...
r28635 suffix=extra['suffix'], text=True)
Thomas Arendsen Hein
Improved ui.edit():...
r1984 try:
f = os.fdopen(fd, "w")
f.write(text)
f.close()
Alexander Drozdov
ui: edit(): rebase, graft: set HGREVISION environment variable for an editor...
r20605 environ = {'HGUSER': user}
Alexander Drozdov
ui: edit(): transplant: set HGREVISION environment variable for an editor...
r20606 if 'transplant_source' in extra:
environ.update({'HGREVISION': hex(extra['transplant_source'])})
Alexander Drozdov
editor: prefer 'intermediate-source' extra to use for HGREVISION environment variable...
r24687 for label in ('intermediate-source', 'source', 'rebase_source'):
Alexander Drozdov
ui: edit(): rebase, graft: set HGREVISION environment variable for an editor...
r20605 if label in extra:
environ.update({'HGREVISION': extra[label]})
break
FUJIWARA Katsunori
ui: invoke editor for committing with HGEDITFORM environment variable...
r22205 if editform:
environ.update({'HGEDITFORM': editform})
FUJIWARA Katsunori
cmdutil: make in-memory changes visible to external editor (issue4378)...
r26750 if pending:
environ.update({'HG_PENDING': pending})
Alexander Drozdov
ui: edit(): rebase, graft: set HGREVISION environment variable for an editor...
r20605
Osku Salerma
Use VISUAL in addition to EDITOR when choosing the editor to use.
r5660 editor = self.geteditor()
mpm@selenic.com
Move ui class to its own module...
r207
Yuya Nishihara
ui: introduce util.system() wrapper to make sure ui.fout is used...
r23269 self.system("%s \"%s\"" % (editor, name),
Alexander Drozdov
ui: edit(): rebase, graft: set HGREVISION environment variable for an editor...
r20605 environ=environ,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 onerr=error.Abort, errprefix=_("edit failed"))
Matt Mackall
Add username/merge/editor to .hgrc...
r608
Thomas Arendsen Hein
Improved ui.edit():...
r1984 f = open(name)
t = f.read()
f.close()
finally:
os.unlink(name)
Radoslaw "AstralStorm" Szkodzinski
Pass username to hgeditor, remove temporary file...
r662
mpm@selenic.com
Move ui class to its own module...
r207 return t
Vadim Gelfer
move mail sending code into core, so extensions can share it....
r2200
Siddharth Agarwal
ui: avoid mutable default arguments...
r26312 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None):
Yuya Nishihara
ui: introduce util.system() wrapper to make sure ui.fout is used...
r23269 '''execute shell command with appropriate output stream. command
output will be redirected if fout is not stdout.
'''
Pierre-Yves David
ui: allow capture of subprocess output...
r24848 out = self.fout
Augie Fackler
cleanup: use __builtins__.any instead of util.any...
r25149 if any(s[1] for s in self._bufferstates):
Pierre-Yves David
ui: allow capture of subprocess output...
r24848 out = self
Yuya Nishihara
ui: introduce util.system() wrapper to make sure ui.fout is used...
r23269 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
Pierre-Yves David
ui: allow capture of subprocess output...
r24848 errprefix=errprefix, out=out)
Yuya Nishihara
ui: introduce util.system() wrapper to make sure ui.fout is used...
r23269
Matt Harbison
ui: add 'force' parameter to traceback() to override the current print setting...
r18966 def traceback(self, exc=None, force=False):
'''print exception traceback if traceback printing enabled or forced.
Vadim Gelfer
add ui.print_exc(), make all traceback printing central.
r2335 only to call in exception handler. returns true if traceback
printed.'''
Matt Harbison
ui: add 'force' parameter to traceback() to override the current print setting...
r18966 if self.tracebackflag or force:
Matt Harbison
ui: add support for fully printing chained exception stacks in ui.traceback()...
r18965 if exc is None:
exc = sys.exc_info()
cause = getattr(exc[1], 'cause', None)
if cause is not None:
causetb = traceback.format_tb(cause[2])
exctb = traceback.format_tb(exc[2])
exconly = traceback.format_exception_only(cause[0], cause[1])
# exclude frame where 'exc' was chained and rethrown from exctb
self.write_err('Traceback (most recent call last):\n',
''.join(exctb[:-1]),
''.join(causetb),
''.join(exconly))
else:
Matt Harbison
ui: flush stderr after printing a non-chained exception for Windows...
r25568 output = traceback.format_exception(exc[0], exc[1], exc[2])
self.write_err(''.join(output))
Matt Harbison
ui: add 'force' parameter to traceback() to override the current print setting...
r18966 return self.tracebackflag or force
Osku Salerma
Use VISUAL in addition to EDITOR when choosing the editor to use.
r5660
def geteditor(self):
'''return editor to use'''
Steven Stallion
plan9: initial support for plan 9 from bell labs...
r16383 if sys.platform == 'plan9':
# vi is the MIPS instruction simulator on Plan 9. We
# instead default to E to plumb commit messages to
# avoid confusion.
editor = 'E'
else:
editor = 'vi'
Osku Salerma
Use VISUAL in addition to EDITOR when choosing the editor to use.
r5660 return (os.environ.get("HGEDITOR") or
self.config("ui", "editor") or
os.environ.get("VISUAL") or
Steven Stallion
plan9: initial support for plan 9 from bell labs...
r16383 os.environ.get("EDITOR", editor))
Matt Mackall
Add ui.progress API
r9153
Pierre-Yves David
progress: move all logic altering the ui object logic in mercurial.ui...
r25499 @util.propertycache
def _progbar(self):
"""setup the progbar singleton to the ui object"""
if (self.quiet or self.debugflag
Pierre-Yves David
progress: display progress bars by default with core Mercurial...
r25519 or self.configbool('progress', 'disable', False)
Pierre-Yves David
progress: move all logic altering the ui object logic in mercurial.ui...
r25499 or not progress.shouldprint(self)):
return None
return getprogbar(self)
def _progclear(self):
"""clear progress bar output if any. use it before any output"""
Mads Kiilerich
spelling: trivial spell checking
r26781 if '_progbar' not in vars(self): # nothing loaded yet
Pierre-Yves David
progress: move all logic altering the ui object logic in mercurial.ui...
r25499 return
if self._progbar is not None and self._progbar.printed:
self._progbar.clear()
Matt Mackall
Add ui.progress API
r9153 def progress(self, topic, pos, item="", unit="", total=None):
'''show a progress message
timeless
progress: update comment to reflect implementation...
r28598 By default a textual progress bar will be displayed if an operation
takes too long. 'topic' is the current operation, 'item' is a
Mads Kiilerich
fix trivial spelling errors
r17424 non-numeric marker of the current position (i.e. the currently
in-process file), 'pos' is the current numeric position (i.e.
Brodie Rao
ui: fix NameError in ui.progress due to unit/units typo
r9398 revision, bytes, etc.), unit is a corresponding unit label,
Matt Mackall
Add ui.progress API
r9153 and total is the highest expected pos.
Augie Fackler
ui.progress: clarify termination requirement
r10425 Multiple nested topics may be active at a time.
All topics should be marked closed by setting pos to None at
termination.
Matt Mackall
Add ui.progress API
r9153 '''
Pierre-Yves David
progress: move all logic altering the ui object logic in mercurial.ui...
r25499 if self._progbar is not None:
self._progbar.progress(topic, pos, item=item, unit=unit,
total=total)
Pierre-Yves David
progress: get the extremely verbose output out of default debug...
r25125 if pos is None or not self.configbool('progress', 'debug'):
Matt Mackall
Add ui.progress API
r9153 return
Brodie Rao
ui: fix NameError in ui.progress due to unit/units typo
r9398 if unit:
unit = ' ' + unit
Matt Mackall
Add ui.progress API
r9153 if item:
item = ' ' + item
if total:
pct = 100.0 * pos / total
Patrick Mezard
ui: display progress with decimal notation
r10220 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
Brodie Rao
ui: fix NameError in ui.progress due to unit/units typo
r9398 % (topic, item, pos, total, unit, pct))
Matt Mackall
Add ui.progress API
r9153 else:
Jesse Glick
Related to Issue919: ui.progress, apparently unused before now, is busted.
r9749 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
Brodie Rao
ui: add ui.write() output labeling API...
r10815
Durham Goode
blackbox: adds a blackbox extension...
r18669 def log(self, service, *msg, **opts):
Matt Mackall
ui: add logging hook
r11984 '''hook for logging facility extensions
service should be a readily-identifiable subsystem, which will
allow filtering.
Augie Fackler
ui: improve docs on ui.log...
r26235
*msg should be a newline-terminated format string to log, and
then any values to %-format into that format string.
**opts currently has no defined meanings.
Matt Mackall
ui: add logging hook
r11984 '''
Brodie Rao
ui: add ui.write() output labeling API...
r10815 def label(self, msg, label):
'''style msg based on supplied label
Like ui.write(), this just returns msg unchanged, but extensions
and GUI tools can override it to allow styling output without
writing it.
ui.write(s, 'label') is equivalent to
ui.write(ui.label(s, 'label')).
'''
return msg
Gregory Szorc
ui: represent paths as classes...
r24250
Pierre-Yves David
ui: add a 'stacklevel' argument to 'develwarn'...
r27274 def develwarn(self, msg, stacklevel=1):
"""issue a developer warning message
Use 'stacklevel' to report the offender some layers further up in the
stack.
"""
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629 msg = 'devel-warn: ' + msg
Pierre-Yves David
ui: add a 'stacklevel' argument to 'develwarn'...
r27274 stacklevel += 1 # get in develwarn
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629 if self.tracebackflag:
Pierre-Yves David
ui: add a 'stacklevel' argument to 'develwarn'...
r27274 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
timeless
ui: log devel warnings
r28498 self.log('develwarn', '%s at:\n%s' %
(msg, ''.join(util.getstackframes(stacklevel))))
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629 else:
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 2)
Pierre-Yves David
ui: add a 'stacklevel' argument to 'develwarn'...
r27274 self.write_err('%s at: %s:%s (%s)\n'
% ((msg,) + calframe[stacklevel][1:4]))
timeless
ui: log devel warnings
r28498 self.log('develwarn', '%s at: %s:%s (%s)\n',
msg, *calframe[stacklevel][1:4])
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629
Pierre-Yves David
ui: add a 'deprecwarn' helper to issue deprecation warnings...
r27275 def deprecwarn(self, msg, version):
"""issue a deprecation warning
- msg: message explaining what is deprecated and how to upgrade,
- version: last version where the API will be supported,
"""
msg += ("\n(compatibility will be dropped after Mercurial-%s,"
" update your code.)") % version
self.develwarn(msg, stacklevel=2)
Pierre-Yves David
devel-warn: move the develwarn function as a method of the ui object...
r25629
Gregory Szorc
ui: represent paths as classes...
r24250 class paths(dict):
"""Represents a collection of paths and their configs.
Data is initially derived from ui instances and the config files they have
loaded.
"""
def __init__(self, ui):
dict.__init__(self)
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 for name, loc in ui.configitems('paths', ignoresub=True):
Gregory Szorc
ui: represent paths as classes...
r24250 # No location is the same as not existing.
if not loc:
continue
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 loc, sub = ui.configsuboptions('paths', name)
self[name] = path(ui, name, rawloc=loc, suboptions=sub)
Gregory Szorc
ui: represent paths as classes...
r24250
def getpath(self, name, default=None):
Yuya Nishihara
paths: make getpath() accept multiple defaults...
r27561 """Return a ``path`` from a string, falling back to default.
Gregory Szorc
ui: move URL and path detection into path API...
r26056
``name`` can be a named path or locations. Locations are filesystem
paths or URIs.
Gregory Szorc
ui: represent paths as classes...
r24250
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 Returns None if ``name`` is not a registered path, a URI, or a local
path to a repo.
Gregory Szorc
ui: represent paths as classes...
r24250 """
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 # Only fall back to default if no path was requested.
if name is None:
Yuya Nishihara
paths: make getpath() accept multiple defaults...
r27561 if not default:
default = ()
elif not isinstance(default, (tuple, list)):
default = (default,)
for k in default:
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 try:
Yuya Nishihara
paths: make getpath() accept multiple defaults...
r27561 return self[k]
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 except KeyError:
Yuya Nishihara
paths: make getpath() accept multiple defaults...
r27561 continue
return None
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189
# Most likely empty string.
# This may need to raise in the future.
if not name:
return None
Gregory Szorc
ui: represent paths as classes...
r24250 try:
return self[name]
except KeyError:
Gregory Szorc
ui: move URL and path detection into path API...
r26056 # Try to resolve as a local path or URI.
try:
Gregory Szorc
ui: pass ui instance to path.__init__...
r27265 # We don't pass sub-options in, so no need to pass ui instance.
return path(None, None, rawloc=name)
Gregory Szorc
ui: move URL and path detection into path API...
r26056 except ValueError:
Gregory Szorc
ui: change default path fallback mechanism (issue4796)...
r26189 raise error.RepoError(_('repository %s does not exist') %
name)
Gregory Szorc
ui: move URL and path detection into path API...
r26056
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 _pathsuboptions = {}
def pathsuboption(option, attr):
"""Decorator used to declare a path sub-option.
Arguments are the sub-option name and the attribute it should set on
``path`` instances.
The decorated function will receive as arguments a ``ui`` instance,
``path`` instance, and the string value of this option from the config.
The function should return the value that will be set on the ``path``
instance.
This decorator can be used to perform additional verification of
sub-options and to change the type of sub-options.
"""
def register(func):
_pathsuboptions[option] = (attr, func)
return func
return register
@pathsuboption('pushurl', 'pushloc')
def pushurlpathoption(ui, path, value):
u = util.url(value)
# Actually require a URL.
if not u.scheme:
ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
return None
# Don't support the #foo syntax in the push URL to declare branch to
# push.
if u.fragment:
ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
'ignoring)\n') % path.name)
u.fragment = None
return str(u)
Gregory Szorc
ui: represent paths as classes...
r24250 class path(object):
"""Represents an individual path and its configuration."""
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 def __init__(self, ui, name, rawloc=None, suboptions=None):
Gregory Szorc
ui: represent paths as classes...
r24250 """Construct a path from its config options.
Gregory Szorc
ui: pass ui instance to path.__init__...
r27265 ``ui`` is the ``ui`` instance the path is coming from.
Gregory Szorc
ui: represent paths as classes...
r24250 ``name`` is the symbolic name of the path.
``rawloc`` is the raw location, as defined in the config.
Gregory Szorc
ui: capture push location on path instances...
r26064 ``pushloc`` is the raw locations pushes should be made to.
Gregory Szorc
ui: move URL and path detection into path API...
r26056
If ``name`` is not defined, we require that the location be a) a local
filesystem path with a .hg directory or b) a URL. If not,
``ValueError`` is raised.
Gregory Szorc
ui: represent paths as classes...
r24250 """
Gregory Szorc
ui: move URL and path detection into path API...
r26056 if not rawloc:
raise ValueError('rawloc must be defined')
# Locations may define branches via syntax <base>#<branch>.
u = util.url(rawloc)
branch = None
if u.fragment:
branch = u.fragment
u.fragment = None
self.url = u
self.branch = branch
Gregory Szorc
ui: represent paths as classes...
r24250 self.name = name
Gregory Szorc
ui: move URL and path detection into path API...
r26056 self.rawloc = rawloc
self.loc = str(u)
# When given a raw location but not a symbolic name, validate the
# location is valid.
Durham Goode
paths: move path validation logic to its own function...
r26076 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
Gregory Szorc
ui: move URL and path detection into path API...
r26056 raise ValueError('location is not a URL or path to a local '
'repo: %s' % rawloc)
Pierre-Yves David
progress: move the singleton logic to the ui module...
r25498
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 suboptions = suboptions or {}
# Now process the sub-options. If a sub-option is registered, its
# attribute will always be present. The value will be None if there
# was no valid sub-option.
for suboption, (attr, func) in _pathsuboptions.iteritems():
if suboption not in suboptions:
setattr(self, attr, None)
continue
value = func(ui, self, suboptions[suboption])
setattr(self, attr, value)
Durham Goode
paths: move path validation logic to its own function...
r26076 def _isvalidlocalpath(self, path):
"""Returns True if the given path is a potentially valid repository.
This is its own function so that extensions can change the definition of
'valid' in this case (like when pulling from a git repo into a hg
one)."""
return os.path.isdir(os.path.join(path, '.hg'))
Gregory Szorc
ui: capture push location on path instances...
r26064 @property
Gregory Szorc
ui: support declaring path push urls as sub-options...
r27266 def suboptions(self):
"""Return sub-options and their values for this path.
This is intended to be used for presentation purposes.
"""
d = {}
for subopt, (attr, _func) in _pathsuboptions.iteritems():
value = getattr(self, attr)
if value is not None:
d[subopt] = value
return d
Gregory Szorc
ui: capture push location on path instances...
r26064
Pierre-Yves David
progress: move the singleton logic to the ui module...
r25498 # we instantiate one globally shared progress bar to avoid
# competing progress bars when multiple UI objects get created
_progresssingleton = None
def getprogbar(ui):
global _progresssingleton
if _progresssingleton is None:
# passing 'ui' object to the singleton is fishy,
# this is how the extension used to work but feel free to rework it.
_progresssingleton = progress.progbar(ui)
return _progresssingleton