##// END OF EJS Templates
HGPLAIN: allow exceptions to plain mode, like i18n, via HGPLAINEXCEPT...
Brodie Rao -
r13849:9f97de15 default
parent child Browse files
Show More
@@ -1,93 +1,101 b''
1 HG
1 HG
2 Path to the 'hg' executable, automatically passed when running
2 Path to the 'hg' executable, automatically passed when running
3 hooks, extensions or external tools. If unset or empty, this is
3 hooks, extensions or external tools. If unset or empty, this is
4 the hg executable's name if it's frozen, or an executable named
4 the hg executable's name if it's frozen, or an executable named
5 'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
5 'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
6 Windows) is searched.
6 Windows) is searched.
7
7
8 HGEDITOR
8 HGEDITOR
9 This is the name of the editor to run when committing. See EDITOR.
9 This is the name of the editor to run when committing. See EDITOR.
10
10
11 (deprecated, use configuration file)
11 (deprecated, use configuration file)
12
12
13 HGENCODING
13 HGENCODING
14 This overrides the default locale setting detected by Mercurial.
14 This overrides the default locale setting detected by Mercurial.
15 This setting is used to convert data including usernames,
15 This setting is used to convert data including usernames,
16 changeset descriptions, tag names, and branches. This setting can
16 changeset descriptions, tag names, and branches. This setting can
17 be overridden with the --encoding command-line option.
17 be overridden with the --encoding command-line option.
18
18
19 HGENCODINGMODE
19 HGENCODINGMODE
20 This sets Mercurial's behavior for handling unknown characters
20 This sets Mercurial's behavior for handling unknown characters
21 while transcoding user input. The default is "strict", which
21 while transcoding user input. The default is "strict", which
22 causes Mercurial to abort if it can't map a character. Other
22 causes Mercurial to abort if it can't map a character. Other
23 settings include "replace", which replaces unknown characters, and
23 settings include "replace", which replaces unknown characters, and
24 "ignore", which drops them. This setting can be overridden with
24 "ignore", which drops them. This setting can be overridden with
25 the --encodingmode command-line option.
25 the --encodingmode command-line option.
26
26
27 HGENCODINGAMBIGUOUS
27 HGENCODINGAMBIGUOUS
28 This sets Mercurial's behavior for handling characters with
28 This sets Mercurial's behavior for handling characters with
29 "ambiguous" widths like accented Latin characters with East Asian
29 "ambiguous" widths like accented Latin characters with East Asian
30 fonts. By default, Mercurial assumes ambiguous characters are
30 fonts. By default, Mercurial assumes ambiguous characters are
31 narrow, set this variable to "wide" if such characters cause
31 narrow, set this variable to "wide" if such characters cause
32 formatting problems.
32 formatting problems.
33
33
34 HGMERGE
34 HGMERGE
35 An executable to use for resolving merge conflicts. The program
35 An executable to use for resolving merge conflicts. The program
36 will be executed with three arguments: local file, remote file,
36 will be executed with three arguments: local file, remote file,
37 ancestor file.
37 ancestor file.
38
38
39 (deprecated, use configuration file)
39 (deprecated, use configuration file)
40
40
41 HGRCPATH
41 HGRCPATH
42 A list of files or directories to search for configuration
42 A list of files or directories to search for configuration
43 files. Item separator is ":" on Unix, ";" on Windows. If HGRCPATH
43 files. Item separator is ":" on Unix, ";" on Windows. If HGRCPATH
44 is not set, platform default search path is used. If empty, only
44 is not set, platform default search path is used. If empty, only
45 the .hg/hgrc from the current repository is read.
45 the .hg/hgrc from the current repository is read.
46
46
47 For each element in HGRCPATH:
47 For each element in HGRCPATH:
48
48
49 - if it's a directory, all files ending with .rc are added
49 - if it's a directory, all files ending with .rc are added
50 - otherwise, the file itself will be added
50 - otherwise, the file itself will be added
51
51
52 HGPLAIN
52 HGPLAIN
53 When set, this disables any configuration settings that might
53 When set, this disables any configuration settings that might
54 change Mercurial's default output. This includes encoding,
54 change Mercurial's default output. This includes encoding,
55 defaults, verbose mode, debug mode, quiet mode, tracebacks, and
55 defaults, verbose mode, debug mode, quiet mode, tracebacks, and
56 localization. This can be useful when scripting against Mercurial
56 localization. This can be useful when scripting against Mercurial
57 in the face of existing user configuration.
57 in the face of existing user configuration.
58
58
59 Equivalent options set via command line flags or environment
59 Equivalent options set via command line flags or environment
60 variables are not overridden.
60 variables are not overridden.
61
61
62 HGPLAINEXCEPT
63 This is a comma-separated list of features to preserve when
64 HGPLAIN is enabled. Currently the only value supported is "i18n",
65 which preserves internationalization in plain mode.
66
67 Setting HGPLAINEXCEPT to anything (even an empty string) will
68 enable plain mode.
69
62 HGUSER
70 HGUSER
63 This is the string used as the author of a commit. If not set,
71 This is the string used as the author of a commit. If not set,
64 available values will be considered in this order:
72 available values will be considered in this order:
65
73
66 - HGUSER (deprecated)
74 - HGUSER (deprecated)
67 - configuration files from the HGRCPATH
75 - configuration files from the HGRCPATH
68 - EMAIL
76 - EMAIL
69 - interactive prompt
77 - interactive prompt
70 - LOGNAME (with ``@hostname`` appended)
78 - LOGNAME (with ``@hostname`` appended)
71
79
72 (deprecated, use configuration file)
80 (deprecated, use configuration file)
73
81
74 EMAIL
82 EMAIL
75 May be used as the author of a commit; see HGUSER.
83 May be used as the author of a commit; see HGUSER.
76
84
77 LOGNAME
85 LOGNAME
78 May be used as the author of a commit; see HGUSER.
86 May be used as the author of a commit; see HGUSER.
79
87
80 VISUAL
88 VISUAL
81 This is the name of the editor to use when committing. See EDITOR.
89 This is the name of the editor to use when committing. See EDITOR.
82
90
83 EDITOR
91 EDITOR
84 Sometimes Mercurial needs to open a text file in an editor for a
92 Sometimes Mercurial needs to open a text file in an editor for a
85 user to modify, for example when writing commit messages. The
93 user to modify, for example when writing commit messages. The
86 editor it uses is determined by looking at the environment
94 editor it uses is determined by looking at the environment
87 variables HGEDITOR, VISUAL and EDITOR, in that order. The first
95 variables HGEDITOR, VISUAL and EDITOR, in that order. The first
88 non-empty one is chosen. If all of them are empty, the editor
96 non-empty one is chosen. If all of them are empty, the editor
89 defaults to 'vi'.
97 defaults to 'vi'.
90
98
91 PYTHONPATH
99 PYTHONPATH
92 This is used by Python to find imported modules and may need to be
100 This is used by Python to find imported modules and may need to be
93 set appropriately if this Mercurial is not installed system-wide.
101 set appropriately if this Mercurial is not installed system-wide.
@@ -1,58 +1,64 b''
1 # i18n.py - internationalization support for mercurial
1 # i18n.py - internationalization support for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import encoding
8 import encoding
9 import gettext, sys, os
9 import gettext, sys, os
10
10
11 # modelled after templater.templatepath:
11 # modelled after templater.templatepath:
12 if hasattr(sys, 'frozen'):
12 if hasattr(sys, 'frozen'):
13 module = sys.executable
13 module = sys.executable
14 else:
14 else:
15 module = __file__
15 module = __file__
16
16
17 base = os.path.dirname(module)
17 base = os.path.dirname(module)
18 for dir in ('.', '..'):
18 for dir in ('.', '..'):
19 localedir = os.path.join(base, dir, 'locale')
19 localedir = os.path.join(base, dir, 'locale')
20 if os.path.isdir(localedir):
20 if os.path.isdir(localedir):
21 break
21 break
22
22
23 t = gettext.translation('hg', localedir, fallback=True)
23 t = gettext.translation('hg', localedir, fallback=True)
24
24
25 def gettext(message):
25 def gettext(message):
26 """Translate message.
26 """Translate message.
27
27
28 The message is looked up in the catalog to get a Unicode string,
28 The message is looked up in the catalog to get a Unicode string,
29 which is encoded in the local encoding before being returned.
29 which is encoded in the local encoding before being returned.
30
30
31 Important: message is restricted to characters in the encoding
31 Important: message is restricted to characters in the encoding
32 given by sys.getdefaultencoding() which is most likely 'ascii'.
32 given by sys.getdefaultencoding() which is most likely 'ascii'.
33 """
33 """
34 # If message is None, t.ugettext will return u'None' as the
34 # If message is None, t.ugettext will return u'None' as the
35 # translation whereas our callers expect us to return None.
35 # translation whereas our callers expect us to return None.
36 if message is None:
36 if message is None:
37 return message
37 return message
38
38
39 paragraphs = message.split('\n\n')
39 paragraphs = message.split('\n\n')
40 # Be careful not to translate the empty string -- it holds the
40 # Be careful not to translate the empty string -- it holds the
41 # meta data of the .po file.
41 # meta data of the .po file.
42 u = u'\n\n'.join([p and t.ugettext(p) or '' for p in paragraphs])
42 u = u'\n\n'.join([p and t.ugettext(p) or '' for p in paragraphs])
43 try:
43 try:
44 # encoding.tolocal cannot be used since it will first try to
44 # encoding.tolocal cannot be used since it will first try to
45 # decode the Unicode string. Calling u.decode(enc) really
45 # decode the Unicode string. Calling u.decode(enc) really
46 # means u.encode(sys.getdefaultencoding()).decode(enc). Since
46 # means u.encode(sys.getdefaultencoding()).decode(enc). Since
47 # the Python encoding defaults to 'ascii', this fails if the
47 # the Python encoding defaults to 'ascii', this fails if the
48 # translated string use non-ASCII characters.
48 # translated string use non-ASCII characters.
49 return u.encode(encoding.encoding, "replace")
49 return u.encode(encoding.encoding, "replace")
50 except LookupError:
50 except LookupError:
51 # An unknown encoding results in a LookupError.
51 # An unknown encoding results in a LookupError.
52 return message
52 return message
53
53
54 if 'HGPLAIN' in os.environ:
54 def _plain():
55 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
56 return False
57 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
58 return 'i18n' not in exceptions
59
60 if _plain():
55 _ = lambda message: message
61 _ = lambda message: message
56 else:
62 else:
57 _ = gettext
63 _ = gettext
58
64
@@ -1,636 +1,643 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, util, error, url
10 import config, util, error, url
11
11
12 class ui(object):
12 class ui(object):
13 def __init__(self, src=None):
13 def __init__(self, src=None):
14 self._buffers = []
14 self._buffers = []
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 self._reportuntrusted = True
16 self._reportuntrusted = True
17 self._ocfg = config.config() # overlay
17 self._ocfg = config.config() # overlay
18 self._tcfg = config.config() # trusted
18 self._tcfg = config.config() # trusted
19 self._ucfg = config.config() # untrusted
19 self._ucfg = config.config() # untrusted
20 self._trustusers = set()
20 self._trustusers = set()
21 self._trustgroups = set()
21 self._trustgroups = set()
22
22
23 if src:
23 if src:
24 self._tcfg = src._tcfg.copy()
24 self._tcfg = src._tcfg.copy()
25 self._ucfg = src._ucfg.copy()
25 self._ucfg = src._ucfg.copy()
26 self._ocfg = src._ocfg.copy()
26 self._ocfg = src._ocfg.copy()
27 self._trustusers = src._trustusers.copy()
27 self._trustusers = src._trustusers.copy()
28 self._trustgroups = src._trustgroups.copy()
28 self._trustgroups = src._trustgroups.copy()
29 self.environ = src.environ
29 self.environ = src.environ
30 self.fixconfig()
30 self.fixconfig()
31 else:
31 else:
32 # shared read-only environment
32 # shared read-only environment
33 self.environ = os.environ
33 self.environ = os.environ
34 # we always trust global config files
34 # we always trust global config files
35 for f in util.rcpath():
35 for f in util.rcpath():
36 self.readconfig(f, trust=True)
36 self.readconfig(f, trust=True)
37
37
38 def copy(self):
38 def copy(self):
39 return self.__class__(self)
39 return self.__class__(self)
40
40
41 def _is_trusted(self, fp, f):
41 def _is_trusted(self, fp, f):
42 st = util.fstat(fp)
42 st = util.fstat(fp)
43 if util.isowner(st):
43 if util.isowner(st):
44 return True
44 return True
45
45
46 tusers, tgroups = self._trustusers, self._trustgroups
46 tusers, tgroups = self._trustusers, self._trustgroups
47 if '*' in tusers or '*' in tgroups:
47 if '*' in tusers or '*' in tgroups:
48 return True
48 return True
49
49
50 user = util.username(st.st_uid)
50 user = util.username(st.st_uid)
51 group = util.groupname(st.st_gid)
51 group = util.groupname(st.st_gid)
52 if user in tusers or group in tgroups or user == util.username():
52 if user in tusers or group in tgroups or user == util.username():
53 return True
53 return True
54
54
55 if self._reportuntrusted:
55 if self._reportuntrusted:
56 self.warn(_('Not trusting file %s from untrusted '
56 self.warn(_('Not trusting file %s from untrusted '
57 'user %s, group %s\n') % (f, user, group))
57 'user %s, group %s\n') % (f, user, group))
58 return False
58 return False
59
59
60 def readconfig(self, filename, root=None, trust=False,
60 def readconfig(self, filename, root=None, trust=False,
61 sections=None, remap=None):
61 sections=None, remap=None):
62 try:
62 try:
63 fp = open(filename)
63 fp = open(filename)
64 except IOError:
64 except IOError:
65 if not sections: # ignore unless we were looking for something
65 if not sections: # ignore unless we were looking for something
66 return
66 return
67 raise
67 raise
68
68
69 cfg = config.config()
69 cfg = config.config()
70 trusted = sections or trust or self._is_trusted(fp, filename)
70 trusted = sections or trust or self._is_trusted(fp, filename)
71
71
72 try:
72 try:
73 cfg.read(filename, fp, sections=sections, remap=remap)
73 cfg.read(filename, fp, sections=sections, remap=remap)
74 except error.ConfigError, inst:
74 except error.ConfigError, inst:
75 if trusted:
75 if trusted:
76 raise
76 raise
77 self.warn(_("Ignored: %s\n") % str(inst))
77 self.warn(_("Ignored: %s\n") % str(inst))
78
78
79 if self.plain():
79 if self.plain():
80 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
80 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
81 'logtemplate', 'style',
81 'logtemplate', 'style',
82 'traceback', 'verbose'):
82 'traceback', 'verbose'):
83 if k in cfg['ui']:
83 if k in cfg['ui']:
84 del cfg['ui'][k]
84 del cfg['ui'][k]
85 for k, v in cfg.items('alias'):
85 for k, v in cfg.items('alias'):
86 del cfg['alias'][k]
86 del cfg['alias'][k]
87 for k, v in cfg.items('defaults'):
87 for k, v in cfg.items('defaults'):
88 del cfg['defaults'][k]
88 del cfg['defaults'][k]
89
89
90 if trusted:
90 if trusted:
91 self._tcfg.update(cfg)
91 self._tcfg.update(cfg)
92 self._tcfg.update(self._ocfg)
92 self._tcfg.update(self._ocfg)
93 self._ucfg.update(cfg)
93 self._ucfg.update(cfg)
94 self._ucfg.update(self._ocfg)
94 self._ucfg.update(self._ocfg)
95
95
96 if root is None:
96 if root is None:
97 root = os.path.expanduser('~')
97 root = os.path.expanduser('~')
98 self.fixconfig(root=root)
98 self.fixconfig(root=root)
99
99
100 def fixconfig(self, root=None, section=None):
100 def fixconfig(self, root=None, section=None):
101 if section in (None, 'paths'):
101 if section in (None, 'paths'):
102 # expand vars and ~
102 # expand vars and ~
103 # translate paths relative to root (or home) into absolute paths
103 # translate paths relative to root (or home) into absolute paths
104 root = root or os.getcwd()
104 root = root or os.getcwd()
105 for c in self._tcfg, self._ucfg, self._ocfg:
105 for c in self._tcfg, self._ucfg, self._ocfg:
106 for n, p in c.items('paths'):
106 for n, p in c.items('paths'):
107 if not p:
107 if not p:
108 continue
108 continue
109 if '%%' in p:
109 if '%%' in p:
110 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
110 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
111 % (n, p, self.configsource('paths', n)))
111 % (n, p, self.configsource('paths', n)))
112 p = p.replace('%%', '%')
112 p = p.replace('%%', '%')
113 p = util.expandpath(p)
113 p = util.expandpath(p)
114 if not url.hasscheme(p) and not os.path.isabs(p):
114 if not url.hasscheme(p) and not os.path.isabs(p):
115 p = os.path.normpath(os.path.join(root, p))
115 p = os.path.normpath(os.path.join(root, p))
116 c.set("paths", n, p)
116 c.set("paths", n, p)
117
117
118 if section in (None, 'ui'):
118 if section in (None, 'ui'):
119 # update ui options
119 # update ui options
120 self.debugflag = self.configbool('ui', 'debug')
120 self.debugflag = self.configbool('ui', 'debug')
121 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
121 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
122 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
122 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
123 if self.verbose and self.quiet:
123 if self.verbose and self.quiet:
124 self.quiet = self.verbose = False
124 self.quiet = self.verbose = False
125 self._reportuntrusted = self.debugflag or self.configbool("ui",
125 self._reportuntrusted = self.debugflag or self.configbool("ui",
126 "report_untrusted", True)
126 "report_untrusted", True)
127 self.tracebackflag = self.configbool('ui', 'traceback', False)
127 self.tracebackflag = self.configbool('ui', 'traceback', False)
128
128
129 if section in (None, 'trusted'):
129 if section in (None, 'trusted'):
130 # update trust information
130 # update trust information
131 self._trustusers.update(self.configlist('trusted', 'users'))
131 self._trustusers.update(self.configlist('trusted', 'users'))
132 self._trustgroups.update(self.configlist('trusted', 'groups'))
132 self._trustgroups.update(self.configlist('trusted', 'groups'))
133
133
134 def setconfig(self, section, name, value, overlay=True):
134 def setconfig(self, section, name, value, overlay=True):
135 if overlay:
135 if overlay:
136 self._ocfg.set(section, name, value)
136 self._ocfg.set(section, name, value)
137 self._tcfg.set(section, name, value)
137 self._tcfg.set(section, name, value)
138 self._ucfg.set(section, name, value)
138 self._ucfg.set(section, name, value)
139 self.fixconfig(section=section)
139 self.fixconfig(section=section)
140
140
141 def _data(self, untrusted):
141 def _data(self, untrusted):
142 return untrusted and self._ucfg or self._tcfg
142 return untrusted and self._ucfg or self._tcfg
143
143
144 def configsource(self, section, name, untrusted=False):
144 def configsource(self, section, name, untrusted=False):
145 return self._data(untrusted).source(section, name) or 'none'
145 return self._data(untrusted).source(section, name) or 'none'
146
146
147 def config(self, section, name, default=None, untrusted=False):
147 def config(self, section, name, default=None, untrusted=False):
148 value = self._data(untrusted).get(section, name, default)
148 value = self._data(untrusted).get(section, name, default)
149 if self.debugflag and not untrusted and self._reportuntrusted:
149 if self.debugflag and not untrusted and self._reportuntrusted:
150 uvalue = self._ucfg.get(section, name)
150 uvalue = self._ucfg.get(section, name)
151 if uvalue is not None and uvalue != value:
151 if uvalue is not None and uvalue != value:
152 self.debug(_("ignoring untrusted configuration option "
152 self.debug(_("ignoring untrusted configuration option "
153 "%s.%s = %s\n") % (section, name, uvalue))
153 "%s.%s = %s\n") % (section, name, uvalue))
154 return value
154 return value
155
155
156 def configpath(self, section, name, default=None, untrusted=False):
156 def configpath(self, section, name, default=None, untrusted=False):
157 'get a path config item, expanded relative to config file'
157 'get a path config item, expanded relative to config file'
158 v = self.config(section, name, default, untrusted)
158 v = self.config(section, name, default, untrusted)
159 if not os.path.isabs(v) or "://" not in v:
159 if not os.path.isabs(v) or "://" not in v:
160 src = self.configsource(section, name, untrusted)
160 src = self.configsource(section, name, untrusted)
161 if ':' in src:
161 if ':' in src:
162 base = os.path.dirname(src.rsplit(':'))
162 base = os.path.dirname(src.rsplit(':'))
163 v = os.path.join(base, os.path.expanduser(v))
163 v = os.path.join(base, os.path.expanduser(v))
164 return v
164 return v
165
165
166 def configbool(self, section, name, default=False, untrusted=False):
166 def configbool(self, section, name, default=False, untrusted=False):
167 v = self.config(section, name, None, untrusted)
167 v = self.config(section, name, None, untrusted)
168 if v is None:
168 if v is None:
169 return default
169 return default
170 if isinstance(v, bool):
170 if isinstance(v, bool):
171 return v
171 return v
172 b = util.parsebool(v)
172 b = util.parsebool(v)
173 if b is None:
173 if b is None:
174 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
174 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
175 % (section, name, v))
175 % (section, name, v))
176 return b
176 return b
177
177
178 def configlist(self, section, name, default=None, untrusted=False):
178 def configlist(self, section, name, default=None, untrusted=False):
179 """Return a list of comma/space separated strings"""
179 """Return a list of comma/space separated strings"""
180
180
181 def _parse_plain(parts, s, offset):
181 def _parse_plain(parts, s, offset):
182 whitespace = False
182 whitespace = False
183 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
183 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
184 whitespace = True
184 whitespace = True
185 offset += 1
185 offset += 1
186 if offset >= len(s):
186 if offset >= len(s):
187 return None, parts, offset
187 return None, parts, offset
188 if whitespace:
188 if whitespace:
189 parts.append('')
189 parts.append('')
190 if s[offset] == '"' and not parts[-1]:
190 if s[offset] == '"' and not parts[-1]:
191 return _parse_quote, parts, offset + 1
191 return _parse_quote, parts, offset + 1
192 elif s[offset] == '"' and parts[-1][-1] == '\\':
192 elif s[offset] == '"' and parts[-1][-1] == '\\':
193 parts[-1] = parts[-1][:-1] + s[offset]
193 parts[-1] = parts[-1][:-1] + s[offset]
194 return _parse_plain, parts, offset + 1
194 return _parse_plain, parts, offset + 1
195 parts[-1] += s[offset]
195 parts[-1] += s[offset]
196 return _parse_plain, parts, offset + 1
196 return _parse_plain, parts, offset + 1
197
197
198 def _parse_quote(parts, s, offset):
198 def _parse_quote(parts, s, offset):
199 if offset < len(s) and s[offset] == '"': # ""
199 if offset < len(s) and s[offset] == '"': # ""
200 parts.append('')
200 parts.append('')
201 offset += 1
201 offset += 1
202 while offset < len(s) and (s[offset].isspace() or
202 while offset < len(s) and (s[offset].isspace() or
203 s[offset] == ','):
203 s[offset] == ','):
204 offset += 1
204 offset += 1
205 return _parse_plain, parts, offset
205 return _parse_plain, parts, offset
206
206
207 while offset < len(s) and s[offset] != '"':
207 while offset < len(s) and s[offset] != '"':
208 if (s[offset] == '\\' and offset + 1 < len(s)
208 if (s[offset] == '\\' and offset + 1 < len(s)
209 and s[offset + 1] == '"'):
209 and s[offset + 1] == '"'):
210 offset += 1
210 offset += 1
211 parts[-1] += '"'
211 parts[-1] += '"'
212 else:
212 else:
213 parts[-1] += s[offset]
213 parts[-1] += s[offset]
214 offset += 1
214 offset += 1
215
215
216 if offset >= len(s):
216 if offset >= len(s):
217 real_parts = _configlist(parts[-1])
217 real_parts = _configlist(parts[-1])
218 if not real_parts:
218 if not real_parts:
219 parts[-1] = '"'
219 parts[-1] = '"'
220 else:
220 else:
221 real_parts[0] = '"' + real_parts[0]
221 real_parts[0] = '"' + real_parts[0]
222 parts = parts[:-1]
222 parts = parts[:-1]
223 parts.extend(real_parts)
223 parts.extend(real_parts)
224 return None, parts, offset
224 return None, parts, offset
225
225
226 offset += 1
226 offset += 1
227 while offset < len(s) and s[offset] in [' ', ',']:
227 while offset < len(s) and s[offset] in [' ', ',']:
228 offset += 1
228 offset += 1
229
229
230 if offset < len(s):
230 if offset < len(s):
231 if offset + 1 == len(s) and s[offset] == '"':
231 if offset + 1 == len(s) and s[offset] == '"':
232 parts[-1] += '"'
232 parts[-1] += '"'
233 offset += 1
233 offset += 1
234 else:
234 else:
235 parts.append('')
235 parts.append('')
236 else:
236 else:
237 return None, parts, offset
237 return None, parts, offset
238
238
239 return _parse_plain, parts, offset
239 return _parse_plain, parts, offset
240
240
241 def _configlist(s):
241 def _configlist(s):
242 s = s.rstrip(' ,')
242 s = s.rstrip(' ,')
243 if not s:
243 if not s:
244 return []
244 return []
245 parser, parts, offset = _parse_plain, [''], 0
245 parser, parts, offset = _parse_plain, [''], 0
246 while parser:
246 while parser:
247 parser, parts, offset = parser(parts, s, offset)
247 parser, parts, offset = parser(parts, s, offset)
248 return parts
248 return parts
249
249
250 result = self.config(section, name, untrusted=untrusted)
250 result = self.config(section, name, untrusted=untrusted)
251 if result is None:
251 if result is None:
252 result = default or []
252 result = default or []
253 if isinstance(result, basestring):
253 if isinstance(result, basestring):
254 result = _configlist(result.lstrip(' ,\n'))
254 result = _configlist(result.lstrip(' ,\n'))
255 if result is None:
255 if result is None:
256 result = default or []
256 result = default or []
257 return result
257 return result
258
258
259 def has_section(self, section, untrusted=False):
259 def has_section(self, section, untrusted=False):
260 '''tell whether section exists in config.'''
260 '''tell whether section exists in config.'''
261 return section in self._data(untrusted)
261 return section in self._data(untrusted)
262
262
263 def configitems(self, section, untrusted=False):
263 def configitems(self, section, untrusted=False):
264 items = self._data(untrusted).items(section)
264 items = self._data(untrusted).items(section)
265 if self.debugflag and not untrusted and self._reportuntrusted:
265 if self.debugflag and not untrusted and self._reportuntrusted:
266 for k, v in self._ucfg.items(section):
266 for k, v in self._ucfg.items(section):
267 if self._tcfg.get(section, k) != v:
267 if self._tcfg.get(section, k) != v:
268 self.debug(_("ignoring untrusted configuration option "
268 self.debug(_("ignoring untrusted configuration option "
269 "%s.%s = %s\n") % (section, k, v))
269 "%s.%s = %s\n") % (section, k, v))
270 return items
270 return items
271
271
272 def walkconfig(self, untrusted=False):
272 def walkconfig(self, untrusted=False):
273 cfg = self._data(untrusted)
273 cfg = self._data(untrusted)
274 for section in cfg.sections():
274 for section in cfg.sections():
275 for name, value in self.configitems(section, untrusted):
275 for name, value in self.configitems(section, untrusted):
276 yield section, name, value
276 yield section, name, value
277
277
278 def plain(self):
278 def plain(self):
279 '''is plain mode active?
279 '''is plain mode active?
280
280
281 Plain mode means that all configuration variables which affect the
281 Plain mode means that all configuration variables which affect
282 behavior and output of Mercurial should be ignored. Additionally, the
282 the behavior and output of Mercurial should be
283 output should be stable, reproducible and suitable for use in scripts or
283 ignored. Additionally, the output should be stable,
284 applications.
284 reproducible and suitable for use in scripts or applications.
285
286 The only way to trigger plain mode is by setting either the
287 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
285
288
286 The only way to trigger plain mode is by setting the `HGPLAIN'
289 The return value can either be False, True, or a list of
287 environment variable.
290 features that plain mode should not apply to (e.g., i18n,
291 progress, etc).
288 '''
292 '''
289 return 'HGPLAIN' in os.environ
293 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
294 return False
295 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
296 return exceptions or True
290
297
291 def username(self):
298 def username(self):
292 """Return default username to be used in commits.
299 """Return default username to be used in commits.
293
300
294 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
301 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
295 and stop searching if one of these is set.
302 and stop searching if one of these is set.
296 If not found and ui.askusername is True, ask the user, else use
303 If not found and ui.askusername is True, ask the user, else use
297 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
304 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
298 """
305 """
299 user = os.environ.get("HGUSER")
306 user = os.environ.get("HGUSER")
300 if user is None:
307 if user is None:
301 user = self.config("ui", "username")
308 user = self.config("ui", "username")
302 if user is not None:
309 if user is not None:
303 user = os.path.expandvars(user)
310 user = os.path.expandvars(user)
304 if user is None:
311 if user is None:
305 user = os.environ.get("EMAIL")
312 user = os.environ.get("EMAIL")
306 if user is None and self.configbool("ui", "askusername"):
313 if user is None and self.configbool("ui", "askusername"):
307 user = self.prompt(_("enter a commit username:"), default=None)
314 user = self.prompt(_("enter a commit username:"), default=None)
308 if user is None and not self.interactive():
315 if user is None and not self.interactive():
309 try:
316 try:
310 user = '%s@%s' % (util.getuser(), socket.getfqdn())
317 user = '%s@%s' % (util.getuser(), socket.getfqdn())
311 self.warn(_("No username found, using '%s' instead\n") % user)
318 self.warn(_("No username found, using '%s' instead\n") % user)
312 except KeyError:
319 except KeyError:
313 pass
320 pass
314 if not user:
321 if not user:
315 raise util.Abort(_('no username supplied (see "hg help config")'))
322 raise util.Abort(_('no username supplied (see "hg help config")'))
316 if "\n" in user:
323 if "\n" in user:
317 raise util.Abort(_("username %s contains a newline\n") % repr(user))
324 raise util.Abort(_("username %s contains a newline\n") % repr(user))
318 return user
325 return user
319
326
320 def shortuser(self, user):
327 def shortuser(self, user):
321 """Return a short representation of a user name or email address."""
328 """Return a short representation of a user name or email address."""
322 if not self.verbose:
329 if not self.verbose:
323 user = util.shortuser(user)
330 user = util.shortuser(user)
324 return user
331 return user
325
332
326 def expandpath(self, loc, default=None):
333 def expandpath(self, loc, default=None):
327 """Return repository location relative to cwd or from [paths]"""
334 """Return repository location relative to cwd or from [paths]"""
328 if url.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
335 if url.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
329 return loc
336 return loc
330
337
331 path = self.config('paths', loc)
338 path = self.config('paths', loc)
332 if not path and default is not None:
339 if not path and default is not None:
333 path = self.config('paths', default)
340 path = self.config('paths', default)
334 return path or loc
341 return path or loc
335
342
336 def pushbuffer(self):
343 def pushbuffer(self):
337 self._buffers.append([])
344 self._buffers.append([])
338
345
339 def popbuffer(self, labeled=False):
346 def popbuffer(self, labeled=False):
340 '''pop the last buffer and return the buffered output
347 '''pop the last buffer and return the buffered output
341
348
342 If labeled is True, any labels associated with buffered
349 If labeled is True, any labels associated with buffered
343 output will be handled. By default, this has no effect
350 output will be handled. By default, this has no effect
344 on the output returned, but extensions and GUI tools may
351 on the output returned, but extensions and GUI tools may
345 handle this argument and returned styled output. If output
352 handle this argument and returned styled output. If output
346 is being buffered so it can be captured and parsed or
353 is being buffered so it can be captured and parsed or
347 processed, labeled should not be set to True.
354 processed, labeled should not be set to True.
348 '''
355 '''
349 return "".join(self._buffers.pop())
356 return "".join(self._buffers.pop())
350
357
351 def write(self, *args, **opts):
358 def write(self, *args, **opts):
352 '''write args to output
359 '''write args to output
353
360
354 By default, this method simply writes to the buffer or stdout,
361 By default, this method simply writes to the buffer or stdout,
355 but extensions or GUI tools may override this method,
362 but extensions or GUI tools may override this method,
356 write_err(), popbuffer(), and label() to style output from
363 write_err(), popbuffer(), and label() to style output from
357 various parts of hg.
364 various parts of hg.
358
365
359 An optional keyword argument, "label", can be passed in.
366 An optional keyword argument, "label", can be passed in.
360 This should be a string containing label names separated by
367 This should be a string containing label names separated by
361 space. Label names take the form of "topic.type". For example,
368 space. Label names take the form of "topic.type". For example,
362 ui.debug() issues a label of "ui.debug".
369 ui.debug() issues a label of "ui.debug".
363
370
364 When labeling output for a specific command, a label of
371 When labeling output for a specific command, a label of
365 "cmdname.type" is recommended. For example, status issues
372 "cmdname.type" is recommended. For example, status issues
366 a label of "status.modified" for modified files.
373 a label of "status.modified" for modified files.
367 '''
374 '''
368 if self._buffers:
375 if self._buffers:
369 self._buffers[-1].extend([str(a) for a in args])
376 self._buffers[-1].extend([str(a) for a in args])
370 else:
377 else:
371 for a in args:
378 for a in args:
372 sys.stdout.write(str(a))
379 sys.stdout.write(str(a))
373
380
374 def write_err(self, *args, **opts):
381 def write_err(self, *args, **opts):
375 try:
382 try:
376 if not getattr(sys.stdout, 'closed', False):
383 if not getattr(sys.stdout, 'closed', False):
377 sys.stdout.flush()
384 sys.stdout.flush()
378 for a in args:
385 for a in args:
379 sys.stderr.write(str(a))
386 sys.stderr.write(str(a))
380 # stderr may be buffered under win32 when redirected to files,
387 # stderr may be buffered under win32 when redirected to files,
381 # including stdout.
388 # including stdout.
382 if not getattr(sys.stderr, 'closed', False):
389 if not getattr(sys.stderr, 'closed', False):
383 sys.stderr.flush()
390 sys.stderr.flush()
384 except IOError, inst:
391 except IOError, inst:
385 if inst.errno not in (errno.EPIPE, errno.EIO):
392 if inst.errno not in (errno.EPIPE, errno.EIO):
386 raise
393 raise
387
394
388 def flush(self):
395 def flush(self):
389 try: sys.stdout.flush()
396 try: sys.stdout.flush()
390 except: pass
397 except: pass
391 try: sys.stderr.flush()
398 try: sys.stderr.flush()
392 except: pass
399 except: pass
393
400
394 def interactive(self):
401 def interactive(self):
395 '''is interactive input allowed?
402 '''is interactive input allowed?
396
403
397 An interactive session is a session where input can be reasonably read
404 An interactive session is a session where input can be reasonably read
398 from `sys.stdin'. If this function returns false, any attempt to read
405 from `sys.stdin'. If this function returns false, any attempt to read
399 from stdin should fail with an error, unless a sensible default has been
406 from stdin should fail with an error, unless a sensible default has been
400 specified.
407 specified.
401
408
402 Interactiveness is triggered by the value of the `ui.interactive'
409 Interactiveness is triggered by the value of the `ui.interactive'
403 configuration variable or - if it is unset - when `sys.stdin' points
410 configuration variable or - if it is unset - when `sys.stdin' points
404 to a terminal device.
411 to a terminal device.
405
412
406 This function refers to input only; for output, see `ui.formatted()'.
413 This function refers to input only; for output, see `ui.formatted()'.
407 '''
414 '''
408 i = self.configbool("ui", "interactive", None)
415 i = self.configbool("ui", "interactive", None)
409 if i is None:
416 if i is None:
410 try:
417 try:
411 return sys.stdin.isatty()
418 return sys.stdin.isatty()
412 except AttributeError:
419 except AttributeError:
413 # some environments replace stdin without implementing isatty
420 # some environments replace stdin without implementing isatty
414 # usually those are non-interactive
421 # usually those are non-interactive
415 return False
422 return False
416
423
417 return i
424 return i
418
425
419 def termwidth(self):
426 def termwidth(self):
420 '''how wide is the terminal in columns?
427 '''how wide is the terminal in columns?
421 '''
428 '''
422 if 'COLUMNS' in os.environ:
429 if 'COLUMNS' in os.environ:
423 try:
430 try:
424 return int(os.environ['COLUMNS'])
431 return int(os.environ['COLUMNS'])
425 except ValueError:
432 except ValueError:
426 pass
433 pass
427 return util.termwidth()
434 return util.termwidth()
428
435
429 def formatted(self):
436 def formatted(self):
430 '''should formatted output be used?
437 '''should formatted output be used?
431
438
432 It is often desirable to format the output to suite the output medium.
439 It is often desirable to format the output to suite the output medium.
433 Examples of this are truncating long lines or colorizing messages.
440 Examples of this are truncating long lines or colorizing messages.
434 However, this is not often not desirable when piping output into other
441 However, this is not often not desirable when piping output into other
435 utilities, e.g. `grep'.
442 utilities, e.g. `grep'.
436
443
437 Formatted output is triggered by the value of the `ui.formatted'
444 Formatted output is triggered by the value of the `ui.formatted'
438 configuration variable or - if it is unset - when `sys.stdout' points
445 configuration variable or - if it is unset - when `sys.stdout' points
439 to a terminal device. Please note that `ui.formatted' should be
446 to a terminal device. Please note that `ui.formatted' should be
440 considered an implementation detail; it is not intended for use outside
447 considered an implementation detail; it is not intended for use outside
441 Mercurial or its extensions.
448 Mercurial or its extensions.
442
449
443 This function refers to output only; for input, see `ui.interactive()'.
450 This function refers to output only; for input, see `ui.interactive()'.
444 This function always returns false when in plain mode, see `ui.plain()'.
451 This function always returns false when in plain mode, see `ui.plain()'.
445 '''
452 '''
446 if self.plain():
453 if self.plain():
447 return False
454 return False
448
455
449 i = self.configbool("ui", "formatted", None)
456 i = self.configbool("ui", "formatted", None)
450 if i is None:
457 if i is None:
451 try:
458 try:
452 return sys.stdout.isatty()
459 return sys.stdout.isatty()
453 except AttributeError:
460 except AttributeError:
454 # some environments replace stdout without implementing isatty
461 # some environments replace stdout without implementing isatty
455 # usually those are non-interactive
462 # usually those are non-interactive
456 return False
463 return False
457
464
458 return i
465 return i
459
466
460 def _readline(self, prompt=''):
467 def _readline(self, prompt=''):
461 if sys.stdin.isatty():
468 if sys.stdin.isatty():
462 try:
469 try:
463 # magically add command line editing support, where
470 # magically add command line editing support, where
464 # available
471 # available
465 import readline
472 import readline
466 # force demandimport to really load the module
473 # force demandimport to really load the module
467 readline.read_history_file
474 readline.read_history_file
468 # windows sometimes raises something other than ImportError
475 # windows sometimes raises something other than ImportError
469 except Exception:
476 except Exception:
470 pass
477 pass
471 line = raw_input(prompt)
478 line = raw_input(prompt)
472 # When stdin is in binary mode on Windows, it can cause
479 # When stdin is in binary mode on Windows, it can cause
473 # raw_input() to emit an extra trailing carriage return
480 # raw_input() to emit an extra trailing carriage return
474 if os.linesep == '\r\n' and line and line[-1] == '\r':
481 if os.linesep == '\r\n' and line and line[-1] == '\r':
475 line = line[:-1]
482 line = line[:-1]
476 return line
483 return line
477
484
478 def prompt(self, msg, default="y"):
485 def prompt(self, msg, default="y"):
479 """Prompt user with msg, read response.
486 """Prompt user with msg, read response.
480 If ui is not interactive, the default is returned.
487 If ui is not interactive, the default is returned.
481 """
488 """
482 if not self.interactive():
489 if not self.interactive():
483 self.write(msg, ' ', default, "\n")
490 self.write(msg, ' ', default, "\n")
484 return default
491 return default
485 try:
492 try:
486 r = self._readline(self.label(msg, 'ui.prompt') + ' ')
493 r = self._readline(self.label(msg, 'ui.prompt') + ' ')
487 if not r:
494 if not r:
488 return default
495 return default
489 return r
496 return r
490 except EOFError:
497 except EOFError:
491 raise util.Abort(_('response expected'))
498 raise util.Abort(_('response expected'))
492
499
493 def promptchoice(self, msg, choices, default=0):
500 def promptchoice(self, msg, choices, default=0):
494 """Prompt user with msg, read response, and ensure it matches
501 """Prompt user with msg, read response, and ensure it matches
495 one of the provided choices. The index of the choice is returned.
502 one of the provided choices. The index of the choice is returned.
496 choices is a sequence of acceptable responses with the format:
503 choices is a sequence of acceptable responses with the format:
497 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
504 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
498 If ui is not interactive, the default is returned.
505 If ui is not interactive, the default is returned.
499 """
506 """
500 resps = [s[s.index('&')+1].lower() for s in choices]
507 resps = [s[s.index('&')+1].lower() for s in choices]
501 while True:
508 while True:
502 r = self.prompt(msg, resps[default])
509 r = self.prompt(msg, resps[default])
503 if r.lower() in resps:
510 if r.lower() in resps:
504 return resps.index(r.lower())
511 return resps.index(r.lower())
505 self.write(_("unrecognized response\n"))
512 self.write(_("unrecognized response\n"))
506
513
507 def getpass(self, prompt=None, default=None):
514 def getpass(self, prompt=None, default=None):
508 if not self.interactive():
515 if not self.interactive():
509 return default
516 return default
510 try:
517 try:
511 return getpass.getpass(prompt or _('password: '))
518 return getpass.getpass(prompt or _('password: '))
512 except EOFError:
519 except EOFError:
513 raise util.Abort(_('response expected'))
520 raise util.Abort(_('response expected'))
514 def status(self, *msg, **opts):
521 def status(self, *msg, **opts):
515 '''write status message to output (if ui.quiet is False)
522 '''write status message to output (if ui.quiet is False)
516
523
517 This adds an output label of "ui.status".
524 This adds an output label of "ui.status".
518 '''
525 '''
519 if not self.quiet:
526 if not self.quiet:
520 opts['label'] = opts.get('label', '') + ' ui.status'
527 opts['label'] = opts.get('label', '') + ' ui.status'
521 self.write(*msg, **opts)
528 self.write(*msg, **opts)
522 def warn(self, *msg, **opts):
529 def warn(self, *msg, **opts):
523 '''write warning message to output (stderr)
530 '''write warning message to output (stderr)
524
531
525 This adds an output label of "ui.warning".
532 This adds an output label of "ui.warning".
526 '''
533 '''
527 opts['label'] = opts.get('label', '') + ' ui.warning'
534 opts['label'] = opts.get('label', '') + ' ui.warning'
528 self.write_err(*msg, **opts)
535 self.write_err(*msg, **opts)
529 def note(self, *msg, **opts):
536 def note(self, *msg, **opts):
530 '''write note to output (if ui.verbose is True)
537 '''write note to output (if ui.verbose is True)
531
538
532 This adds an output label of "ui.note".
539 This adds an output label of "ui.note".
533 '''
540 '''
534 if self.verbose:
541 if self.verbose:
535 opts['label'] = opts.get('label', '') + ' ui.note'
542 opts['label'] = opts.get('label', '') + ' ui.note'
536 self.write(*msg, **opts)
543 self.write(*msg, **opts)
537 def debug(self, *msg, **opts):
544 def debug(self, *msg, **opts):
538 '''write debug message to output (if ui.debugflag is True)
545 '''write debug message to output (if ui.debugflag is True)
539
546
540 This adds an output label of "ui.debug".
547 This adds an output label of "ui.debug".
541 '''
548 '''
542 if self.debugflag:
549 if self.debugflag:
543 opts['label'] = opts.get('label', '') + ' ui.debug'
550 opts['label'] = opts.get('label', '') + ' ui.debug'
544 self.write(*msg, **opts)
551 self.write(*msg, **opts)
545 def edit(self, text, user):
552 def edit(self, text, user):
546 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
553 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
547 text=True)
554 text=True)
548 try:
555 try:
549 f = os.fdopen(fd, "w")
556 f = os.fdopen(fd, "w")
550 f.write(text)
557 f.write(text)
551 f.close()
558 f.close()
552
559
553 editor = self.geteditor()
560 editor = self.geteditor()
554
561
555 util.system("%s \"%s\"" % (editor, name),
562 util.system("%s \"%s\"" % (editor, name),
556 environ={'HGUSER': user},
563 environ={'HGUSER': user},
557 onerr=util.Abort, errprefix=_("edit failed"))
564 onerr=util.Abort, errprefix=_("edit failed"))
558
565
559 f = open(name)
566 f = open(name)
560 t = f.read()
567 t = f.read()
561 f.close()
568 f.close()
562 finally:
569 finally:
563 os.unlink(name)
570 os.unlink(name)
564
571
565 return t
572 return t
566
573
567 def traceback(self, exc=None):
574 def traceback(self, exc=None):
568 '''print exception traceback if traceback printing enabled.
575 '''print exception traceback if traceback printing enabled.
569 only to call in exception handler. returns true if traceback
576 only to call in exception handler. returns true if traceback
570 printed.'''
577 printed.'''
571 if self.tracebackflag:
578 if self.tracebackflag:
572 if exc:
579 if exc:
573 traceback.print_exception(exc[0], exc[1], exc[2])
580 traceback.print_exception(exc[0], exc[1], exc[2])
574 else:
581 else:
575 traceback.print_exc()
582 traceback.print_exc()
576 return self.tracebackflag
583 return self.tracebackflag
577
584
578 def geteditor(self):
585 def geteditor(self):
579 '''return editor to use'''
586 '''return editor to use'''
580 return (os.environ.get("HGEDITOR") or
587 return (os.environ.get("HGEDITOR") or
581 self.config("ui", "editor") or
588 self.config("ui", "editor") or
582 os.environ.get("VISUAL") or
589 os.environ.get("VISUAL") or
583 os.environ.get("EDITOR", "vi"))
590 os.environ.get("EDITOR", "vi"))
584
591
585 def progress(self, topic, pos, item="", unit="", total=None):
592 def progress(self, topic, pos, item="", unit="", total=None):
586 '''show a progress message
593 '''show a progress message
587
594
588 With stock hg, this is simply a debug message that is hidden
595 With stock hg, this is simply a debug message that is hidden
589 by default, but with extensions or GUI tools it may be
596 by default, but with extensions or GUI tools it may be
590 visible. 'topic' is the current operation, 'item' is a
597 visible. 'topic' is the current operation, 'item' is a
591 non-numeric marker of the current position (ie the currently
598 non-numeric marker of the current position (ie the currently
592 in-process file), 'pos' is the current numeric position (ie
599 in-process file), 'pos' is the current numeric position (ie
593 revision, bytes, etc.), unit is a corresponding unit label,
600 revision, bytes, etc.), unit is a corresponding unit label,
594 and total is the highest expected pos.
601 and total is the highest expected pos.
595
602
596 Multiple nested topics may be active at a time.
603 Multiple nested topics may be active at a time.
597
604
598 All topics should be marked closed by setting pos to None at
605 All topics should be marked closed by setting pos to None at
599 termination.
606 termination.
600 '''
607 '''
601
608
602 if pos is None or not self.debugflag:
609 if pos is None or not self.debugflag:
603 return
610 return
604
611
605 if unit:
612 if unit:
606 unit = ' ' + unit
613 unit = ' ' + unit
607 if item:
614 if item:
608 item = ' ' + item
615 item = ' ' + item
609
616
610 if total:
617 if total:
611 pct = 100.0 * pos / total
618 pct = 100.0 * pos / total
612 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
619 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
613 % (topic, item, pos, total, unit, pct))
620 % (topic, item, pos, total, unit, pct))
614 else:
621 else:
615 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
622 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
616
623
617 def log(self, service, message):
624 def log(self, service, message):
618 '''hook for logging facility extensions
625 '''hook for logging facility extensions
619
626
620 service should be a readily-identifiable subsystem, which will
627 service should be a readily-identifiable subsystem, which will
621 allow filtering.
628 allow filtering.
622 message should be a newline-terminated string to log.
629 message should be a newline-terminated string to log.
623 '''
630 '''
624 pass
631 pass
625
632
626 def label(self, msg, label):
633 def label(self, msg, label):
627 '''style msg based on supplied label
634 '''style msg based on supplied label
628
635
629 Like ui.write(), this just returns msg unchanged, but extensions
636 Like ui.write(), this just returns msg unchanged, but extensions
630 and GUI tools can override it to allow styling output without
637 and GUI tools can override it to allow styling output without
631 writing it.
638 writing it.
632
639
633 ui.write(s, 'label') is equivalent to
640 ui.write(s, 'label') is equivalent to
634 ui.write(ui.label(s, 'label')).
641 ui.write(ui.label(s, 'label')).
635 '''
642 '''
636 return msg
643 return msg
@@ -1,135 +1,171 b''
1 Use hgrc within $TESTTMP
1 Use hgrc within $TESTTMP
2
2
3 $ HGRCPATH=`pwd`/hgrc
3 $ HGRCPATH=`pwd`/hgrc
4 $ export HGRCPATH
4 $ export HGRCPATH
5
5
6 Basic syntax error
6 Basic syntax error
7
7
8 $ echo "invalid" > $HGRCPATH
8 $ echo "invalid" > $HGRCPATH
9 $ hg version
9 $ hg version
10 hg: parse error at $TESTTMP/hgrc:1: invalid
10 hg: parse error at $TESTTMP/hgrc:1: invalid
11 [255]
11 [255]
12 $ echo "" > $HGRCPATH
12 $ echo "" > $HGRCPATH
13
13
14 Issue1199: Can't use '%' in hgrc (eg url encoded username)
14 Issue1199: Can't use '%' in hgrc (eg url encoded username)
15
15
16 $ hg init "foo%bar"
16 $ hg init "foo%bar"
17 $ hg clone "foo%bar" foobar
17 $ hg clone "foo%bar" foobar
18 updating to branch default
18 updating to branch default
19 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 $ cd foobar
20 $ cd foobar
21 $ cat .hg/hgrc
21 $ cat .hg/hgrc
22 [paths]
22 [paths]
23 default = $TESTTMP/foo%bar
23 default = $TESTTMP/foo%bar
24 $ hg paths
24 $ hg paths
25 default = $TESTTMP/foo%bar
25 default = $TESTTMP/foo%bar
26 $ hg showconfig
26 $ hg showconfig
27 bundle.mainreporoot=$TESTTMP/foobar
27 bundle.mainreporoot=$TESTTMP/foobar
28 paths.default=$TESTTMP/foo%bar
28 paths.default=$TESTTMP/foo%bar
29 $ cd ..
29 $ cd ..
30
30
31 issue1829: wrong indentation
31 issue1829: wrong indentation
32
32
33 $ echo '[foo]' > $HGRCPATH
33 $ echo '[foo]' > $HGRCPATH
34 $ echo ' x = y' >> $HGRCPATH
34 $ echo ' x = y' >> $HGRCPATH
35 $ hg version
35 $ hg version
36 hg: parse error at $TESTTMP/hgrc:2: x = y
36 hg: parse error at $TESTTMP/hgrc:2: x = y
37 [255]
37 [255]
38
38
39 $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
39 $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
40 > > $HGRCPATH
40 > > $HGRCPATH
41 $ hg showconfig foo
41 $ hg showconfig foo
42 foo.bar=a\nb\nc\nde\nfg
42 foo.bar=a\nb\nc\nde\nfg
43 foo.baz=bif cb
43 foo.baz=bif cb
44
44
45 $ FAKEPATH=/path/to/nowhere
45 $ FAKEPATH=/path/to/nowhere
46 $ export FAKEPATH
46 $ export FAKEPATH
47 $ echo '%include $FAKEPATH/no-such-file' > $HGRCPATH
47 $ echo '%include $FAKEPATH/no-such-file' > $HGRCPATH
48 $ hg version
48 $ hg version
49 hg: parse error at $TESTTMP/hgrc:1: cannot include /path/to/nowhere/no-such-file (No such file or directory)
49 hg: parse error at $TESTTMP/hgrc:1: cannot include /path/to/nowhere/no-such-file (No such file or directory)
50 [255]
50 [255]
51 $ unset FAKEPATH
51 $ unset FAKEPATH
52
52
53 username expansion
53 username expansion
54
54
55 $ olduser=$HGUSER
55 $ olduser=$HGUSER
56 $ unset HGUSER
56 $ unset HGUSER
57
57
58 $ FAKEUSER='John Doe'
58 $ FAKEUSER='John Doe'
59 $ export FAKEUSER
59 $ export FAKEUSER
60 $ echo '[ui]' > $HGRCPATH
60 $ echo '[ui]' > $HGRCPATH
61 $ echo 'username = $FAKEUSER' >> $HGRCPATH
61 $ echo 'username = $FAKEUSER' >> $HGRCPATH
62
62
63 $ hg init usertest
63 $ hg init usertest
64 $ cd usertest
64 $ cd usertest
65 $ touch bar
65 $ touch bar
66 $ hg commit --addremove --quiet -m "added bar"
66 $ hg commit --addremove --quiet -m "added bar"
67 $ hg log --template "{author}\n"
67 $ hg log --template "{author}\n"
68 John Doe
68 John Doe
69 $ cd ..
69 $ cd ..
70
70
71 $ hg showconfig
71 $ hg showconfig
72 ui.username=$FAKEUSER
72 ui.username=$FAKEUSER
73
73
74 $ unset FAKEUSER
74 $ unset FAKEUSER
75 $ HGUSER=$olduser
75 $ HGUSER=$olduser
76 $ export HGUSER
76 $ export HGUSER
77
77
78 showconfig with multiple arguments
78 showconfig with multiple arguments
79
79
80 $ echo "[alias]" > $HGRCPATH
80 $ echo "[alias]" > $HGRCPATH
81 $ echo "log = log -g" >> $HGRCPATH
81 $ echo "log = log -g" >> $HGRCPATH
82 $ echo "[defaults]" >> $HGRCPATH
82 $ echo "[defaults]" >> $HGRCPATH
83 $ echo "identify = -n" >> $HGRCPATH
83 $ echo "identify = -n" >> $HGRCPATH
84 $ hg showconfig alias defaults
84 $ hg showconfig alias defaults
85 alias.log=log -g
85 alias.log=log -g
86 defaults.identify=-n
86 defaults.identify=-n
87 $ hg showconfig alias defaults.identify
87 $ hg showconfig alias defaults.identify
88 abort: only one config item permitted
88 abort: only one config item permitted
89 [255]
89 [255]
90 $ hg showconfig alias.log defaults.identify
90 $ hg showconfig alias.log defaults.identify
91 abort: only one config item permitted
91 abort: only one config item permitted
92 [255]
92 [255]
93
93
94 HGPLAIN
94 HGPLAIN
95
95
96 $ cd ..
96 $ cd ..
97 $ p=`pwd`
97 $ p=`pwd`
98 $ echo "[ui]" > $HGRCPATH
98 $ echo "[ui]" > $HGRCPATH
99 $ echo "debug=true" >> $HGRCPATH
99 $ echo "debug=true" >> $HGRCPATH
100 $ echo "fallbackencoding=ASCII" >> $HGRCPATH
100 $ echo "fallbackencoding=ASCII" >> $HGRCPATH
101 $ echo "quiet=true" >> $HGRCPATH
101 $ echo "quiet=true" >> $HGRCPATH
102 $ echo "slash=true" >> $HGRCPATH
102 $ echo "slash=true" >> $HGRCPATH
103 $ echo "traceback=true" >> $HGRCPATH
103 $ echo "traceback=true" >> $HGRCPATH
104 $ echo "verbose=true" >> $HGRCPATH
104 $ echo "verbose=true" >> $HGRCPATH
105 $ echo "style=~/.hgstyle" >> $HGRCPATH
105 $ echo "style=~/.hgstyle" >> $HGRCPATH
106 $ echo "logtemplate={node}" >> $HGRCPATH
106 $ echo "logtemplate={node}" >> $HGRCPATH
107 $ echo "[defaults]" >> $HGRCPATH
107 $ echo "[defaults]" >> $HGRCPATH
108 $ echo "identify=-n" >> $HGRCPATH
108 $ echo "identify=-n" >> $HGRCPATH
109 $ echo "[alias]" >> $HGRCPATH
109 $ echo "[alias]" >> $HGRCPATH
110 $ echo "log=log -g" >> $HGRCPATH
110 $ echo "log=log -g" >> $HGRCPATH
111
111
112 customized hgrc
112 customized hgrc
113
113
114 $ hg showconfig
114 $ hg showconfig
115 read config from: $TESTTMP/hgrc
115 read config from: $TESTTMP/hgrc
116 $TESTTMP/hgrc:13: alias.log=log -g
116 $TESTTMP/hgrc:13: alias.log=log -g
117 $TESTTMP/hgrc:11: defaults.identify=-n
117 $TESTTMP/hgrc:11: defaults.identify=-n
118 $TESTTMP/hgrc:2: ui.debug=true
118 $TESTTMP/hgrc:2: ui.debug=true
119 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
119 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
120 $TESTTMP/hgrc:4: ui.quiet=true
120 $TESTTMP/hgrc:4: ui.quiet=true
121 $TESTTMP/hgrc:5: ui.slash=true
121 $TESTTMP/hgrc:5: ui.slash=true
122 $TESTTMP/hgrc:6: ui.traceback=true
122 $TESTTMP/hgrc:6: ui.traceback=true
123 $TESTTMP/hgrc:7: ui.verbose=true
123 $TESTTMP/hgrc:7: ui.verbose=true
124 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
124 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
125 $TESTTMP/hgrc:9: ui.logtemplate={node}
125 $TESTTMP/hgrc:9: ui.logtemplate={node}
126
126
127 plain hgrc
127 plain hgrc
128
128
129 $ HGPLAIN=; export HGPLAIN
129 $ HGPLAIN=; export HGPLAIN
130 $ hg showconfig --config ui.traceback=True --debug
130 $ hg showconfig --config ui.traceback=True --debug
131 read config from: $TESTTMP/hgrc
131 read config from: $TESTTMP/hgrc
132 none: ui.traceback=True
132 none: ui.traceback=True
133 none: ui.verbose=False
133 none: ui.verbose=False
134 none: ui.debug=True
134 none: ui.debug=True
135 none: ui.quiet=False
135 none: ui.quiet=False
136
137 plain mode with exceptions
138
139 $ cat > plain.py <<EOF
140 > def uisetup(ui):
141 > ui.write('plain: %r\n' % ui.plain())
142 > EOF
143 $ echo "[extensions]" >> $HGRCPATH
144 $ echo "plain=./plain.py" >> $HGRCPATH
145 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
146 $ hg showconfig --config ui.traceback=True --debug
147 plain: ['']
148 read config from: $TESTTMP/hgrc
149 $TESTTMP/hgrc:15: extensions.plain=./plain.py
150 none: ui.traceback=True
151 none: ui.verbose=False
152 none: ui.debug=True
153 none: ui.quiet=False
154 $ unset HGPLAIN
155 $ hg showconfig --config ui.traceback=True --debug
156 plain: ['']
157 read config from: $TESTTMP/hgrc
158 $TESTTMP/hgrc:15: extensions.plain=./plain.py
159 none: ui.traceback=True
160 none: ui.verbose=False
161 none: ui.debug=True
162 none: ui.quiet=False
163 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
164 $ hg showconfig --config ui.traceback=True --debug
165 plain: ['i18n']
166 read config from: $TESTTMP/hgrc
167 $TESTTMP/hgrc:15: extensions.plain=./plain.py
168 none: ui.traceback=True
169 none: ui.verbose=False
170 none: ui.debug=True
171 none: ui.quiet=False
General Comments 0
You need to be logged in to leave comments. Login now