##// END OF EJS Templates
config: getsource -> source
Matt Mackall -
r8198:cf9accff default
parent child Browse files
Show More
@@ -1,125 +1,125 b''
1 from i18n import _
1 from i18n import _
2 import re, error, os
2 import re, error, os
3
3
4 class sortdict(dict):
4 class sortdict(dict):
5 'a simple sorted dictionary'
5 'a simple sorted dictionary'
6 def __init__(self, data=None):
6 def __init__(self, data=None):
7 self._list = []
7 self._list = []
8 if data:
8 if data:
9 self.update(data)
9 self.update(data)
10 def copy(self):
10 def copy(self):
11 return sortdict(self)
11 return sortdict(self)
12 def __setitem__(self, key, val):
12 def __setitem__(self, key, val):
13 if key in self:
13 if key in self:
14 self._list.remove(key)
14 self._list.remove(key)
15 self._list.append(key)
15 self._list.append(key)
16 dict.__setitem__(self, key, val)
16 dict.__setitem__(self, key, val)
17 def __iter__(self):
17 def __iter__(self):
18 return self._list.__iter__()
18 return self._list.__iter__()
19 def update(self, src):
19 def update(self, src):
20 for k in src:
20 for k in src:
21 self[k] = src[k]
21 self[k] = src[k]
22 def items(self):
22 def items(self):
23 return [(k,self[k]) for k in self._list]
23 return [(k,self[k]) for k in self._list]
24 def __delitem__(self, key):
24 def __delitem__(self, key):
25 dict.__delitem__(self, key)
25 dict.__delitem__(self, key)
26 self._list.remove(key)
26 self._list.remove(key)
27
27
28 class config(object):
28 class config(object):
29 def __init__(self, data=None):
29 def __init__(self, data=None):
30 self._data = {}
30 self._data = {}
31 self._source = {}
31 self._source = {}
32 if data:
32 if data:
33 for k in data._data:
33 for k in data._data:
34 self._data[k] = data[k].copy()
34 self._data[k] = data[k].copy()
35 self._source = data._source.copy()
35 self._source = data._source.copy()
36 def copy(self):
36 def copy(self):
37 return config(self)
37 return config(self)
38 def __contains__(self, section):
38 def __contains__(self, section):
39 return section in self._data
39 return section in self._data
40 def __getitem__(self, section):
40 def __getitem__(self, section):
41 return self._data.get(section, {})
41 return self._data.get(section, {})
42 def __iter__(self):
42 def __iter__(self):
43 for d in self.sections():
43 for d in self.sections():
44 yield d
44 yield d
45 def update(self, src):
45 def update(self, src):
46 for s in src:
46 for s in src:
47 if s not in self:
47 if s not in self:
48 self._data[s] = sortdict()
48 self._data[s] = sortdict()
49 self._data[s].update(src._data[s])
49 self._data[s].update(src._data[s])
50 self._source.update(src._source)
50 self._source.update(src._source)
51 def get(self, section, item, default=None):
51 def get(self, section, item, default=None):
52 return self._data.get(section, {}).get(item, default)
52 return self._data.get(section, {}).get(item, default)
53 def getsource(self, section, item):
53 def source(self, section, item):
54 return self._source.get((section, item), "")
54 return self._source.get((section, item), "")
55 def sections(self):
55 def sections(self):
56 return sorted(self._data.keys())
56 return sorted(self._data.keys())
57 def items(self, section):
57 def items(self, section):
58 return self._data.get(section, {}).items()
58 return self._data.get(section, {}).items()
59 def set(self, section, item, value, source=""):
59 def set(self, section, item, value, source=""):
60 if section not in self:
60 if section not in self:
61 self._data[section] = sortdict()
61 self._data[section] = sortdict()
62 self._data[section][item] = value
62 self._data[section][item] = value
63 self._source[(section, item)] = source
63 self._source[(section, item)] = source
64
64
65 def read(self, path, fp=None, sections=None):
65 def read(self, path, fp=None, sections=None):
66 sectionre = re.compile(r'\[([^\[]+)\]')
66 sectionre = re.compile(r'\[([^\[]+)\]')
67 itemre = re.compile(r'([^=\s]+)\s*=\s*(.*\S|)')
67 itemre = re.compile(r'([^=\s]+)\s*=\s*(.*\S|)')
68 contre = re.compile(r'\s+(\S.*\S)')
68 contre = re.compile(r'\s+(\S.*\S)')
69 emptyre = re.compile(r'(;|#|\s*$)')
69 emptyre = re.compile(r'(;|#|\s*$)')
70 unsetre = re.compile(r'%unset\s+(\S+)')
70 unsetre = re.compile(r'%unset\s+(\S+)')
71 includere = re.compile(r'%include\s+(\S.*\S)')
71 includere = re.compile(r'%include\s+(\S.*\S)')
72 section = ""
72 section = ""
73 item = None
73 item = None
74 line = 0
74 line = 0
75 cont = 0
75 cont = 0
76
76
77 if not fp:
77 if not fp:
78 fp = open(path)
78 fp = open(path)
79
79
80 for l in fp:
80 for l in fp:
81 line += 1
81 line += 1
82 if cont:
82 if cont:
83 m = contre.match(l)
83 m = contre.match(l)
84 if m:
84 if m:
85 if sections and section not in sections:
85 if sections and section not in sections:
86 continue
86 continue
87 v = self.get(section, item) + "\n" + m.group(1)
87 v = self.get(section, item) + "\n" + m.group(1)
88 self.set(section, item, v, "%s:%d" % (path, line))
88 self.set(section, item, v, "%s:%d" % (path, line))
89 continue
89 continue
90 item = None
90 item = None
91 m = includere.match(l)
91 m = includere.match(l)
92 if m:
92 if m:
93 inc = m.group(1)
93 inc = m.group(1)
94 base = os.path.dirname(path)
94 base = os.path.dirname(path)
95 inc = os.path.normpath(os.path.join(base, inc))
95 inc = os.path.normpath(os.path.join(base, inc))
96 incfp = open(inc)
96 incfp = open(inc)
97 self.read(inc, incfp)
97 self.read(inc, incfp)
98 continue
98 continue
99 if emptyre.match(l):
99 if emptyre.match(l):
100 continue
100 continue
101 m = sectionre.match(l)
101 m = sectionre.match(l)
102 if m:
102 if m:
103 section = m.group(1)
103 section = m.group(1)
104 if section not in self:
104 if section not in self:
105 self._data[section] = sortdict()
105 self._data[section] = sortdict()
106 continue
106 continue
107 m = itemre.match(l)
107 m = itemre.match(l)
108 if m:
108 if m:
109 item = m.group(1)
109 item = m.group(1)
110 cont = 1
110 cont = 1
111 if sections and section not in sections:
111 if sections and section not in sections:
112 continue
112 continue
113 self.set(section, item, m.group(2), "%s:%d" % (path, line))
113 self.set(section, item, m.group(2), "%s:%d" % (path, line))
114 continue
114 continue
115 m = unsetre.match(l)
115 m = unsetre.match(l)
116 if m:
116 if m:
117 name = m.group(1)
117 name = m.group(1)
118 if sections and section not in sections:
118 if sections and section not in sections:
119 continue
119 continue
120 if self.get(section, name) != None:
120 if self.get(section, name) != None:
121 del self._data[section][name]
121 del self._data[section][name]
122 continue
122 continue
123
123
124 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
124 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
125 % (path, line, l.rstrip()))
125 % (path, line, l.rstrip()))
@@ -1,208 +1,208 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import re, sys, os
9 import re, sys, os
10 from mercurial import util, config
10 from mercurial import util, config
11
11
12 path = ['templates', '../templates']
12 path = ['templates', '../templates']
13
13
14 def parsestring(s, quoted=True):
14 def parsestring(s, quoted=True):
15 '''parse a string using simple c-like syntax.
15 '''parse a string using simple c-like syntax.
16 string must be in quotes if quoted is True.'''
16 string must be in quotes if quoted is True.'''
17 if quoted:
17 if quoted:
18 if len(s) < 2 or s[0] != s[-1]:
18 if len(s) < 2 or s[0] != s[-1]:
19 raise SyntaxError(_('unmatched quotes'))
19 raise SyntaxError(_('unmatched quotes'))
20 return s[1:-1].decode('string_escape')
20 return s[1:-1].decode('string_escape')
21
21
22 return s.decode('string_escape')
22 return s.decode('string_escape')
23
23
24 class templater(object):
24 class templater(object):
25 '''template expansion engine.
25 '''template expansion engine.
26
26
27 template expansion works like this. a map file contains key=value
27 template expansion works like this. a map file contains key=value
28 pairs. if value is quoted, it is treated as string. otherwise, it
28 pairs. if value is quoted, it is treated as string. otherwise, it
29 is treated as name of template file.
29 is treated as name of template file.
30
30
31 templater is asked to expand a key in map. it looks up key, and
31 templater is asked to expand a key in map. it looks up key, and
32 looks for strings like this: {foo}. it expands {foo} by looking up
32 looks for strings like this: {foo}. it expands {foo} by looking up
33 foo in map, and substituting it. expansion is recursive: it stops
33 foo in map, and substituting it. expansion is recursive: it stops
34 when there is no more {foo} to replace.
34 when there is no more {foo} to replace.
35
35
36 expansion also allows formatting and filtering.
36 expansion also allows formatting and filtering.
37
37
38 format uses key to expand each item in list. syntax is
38 format uses key to expand each item in list. syntax is
39 {key%format}.
39 {key%format}.
40
40
41 filter uses function to transform value. syntax is
41 filter uses function to transform value. syntax is
42 {key|filter1|filter2|...}.'''
42 {key|filter1|filter2|...}.'''
43
43
44 template_re = re.compile(r"(?:(?:#(?=[\w\|%]+#))|(?:{(?=[\w\|%]+})))"
44 template_re = re.compile(r"(?:(?:#(?=[\w\|%]+#))|(?:{(?=[\w\|%]+})))"
45 r"(\w+)(?:(?:%(\w+))|((?:\|\w+)*))[#}]")
45 r"(\w+)(?:(?:%(\w+))|((?:\|\w+)*))[#}]")
46
46
47 def __init__(self, mapfile, filters={}, defaults={}, cache={},
47 def __init__(self, mapfile, filters={}, defaults={}, cache={},
48 minchunk=1024, maxchunk=65536):
48 minchunk=1024, maxchunk=65536):
49 '''set up template engine.
49 '''set up template engine.
50 mapfile is name of file to read map definitions from.
50 mapfile is name of file to read map definitions from.
51 filters is dict of functions. each transforms a value into another.
51 filters is dict of functions. each transforms a value into another.
52 defaults is dict of default map definitions.'''
52 defaults is dict of default map definitions.'''
53 self.mapfile = mapfile or 'template'
53 self.mapfile = mapfile or 'template'
54 self.cache = cache.copy()
54 self.cache = cache.copy()
55 self.map = {}
55 self.map = {}
56 self.base = (mapfile and os.path.dirname(mapfile)) or ''
56 self.base = (mapfile and os.path.dirname(mapfile)) or ''
57 self.filters = filters
57 self.filters = filters
58 self.defaults = defaults
58 self.defaults = defaults
59 self.minchunk, self.maxchunk = minchunk, maxchunk
59 self.minchunk, self.maxchunk = minchunk, maxchunk
60
60
61 if not mapfile:
61 if not mapfile:
62 return
62 return
63 if not os.path.exists(mapfile):
63 if not os.path.exists(mapfile):
64 raise util.Abort(_('style not found: %s') % mapfile)
64 raise util.Abort(_('style not found: %s') % mapfile)
65
65
66 conf = config.config()
66 conf = config.config()
67 conf.read(mapfile)
67 conf.read(mapfile)
68
68
69 for key, val in conf[''].items():
69 for key, val in conf[''].items():
70 if val[0] in "'\"":
70 if val[0] in "'\"":
71 try:
71 try:
72 self.cache[key] = parsestring(val)
72 self.cache[key] = parsestring(val)
73 except SyntaxError, inst:
73 except SyntaxError, inst:
74 raise SyntaxError('%s: %s' %
74 raise SyntaxError('%s: %s' %
75 (conf.getsource('', key), inst.args[0]))
75 (conf.source('', key), inst.args[0]))
76 else:
76 else:
77 self.map[key] = os.path.join(self.base, val)
77 self.map[key] = os.path.join(self.base, val)
78
78
79 def __contains__(self, key):
79 def __contains__(self, key):
80 return key in self.cache or key in self.map
80 return key in self.cache or key in self.map
81
81
82 def _template(self, t):
82 def _template(self, t):
83 '''Get the template for the given template name. Use a local cache.'''
83 '''Get the template for the given template name. Use a local cache.'''
84 if not t in self.cache:
84 if not t in self.cache:
85 try:
85 try:
86 self.cache[t] = file(self.map[t]).read()
86 self.cache[t] = file(self.map[t]).read()
87 except IOError, inst:
87 except IOError, inst:
88 raise IOError(inst.args[0], _('template file %s: %s') %
88 raise IOError(inst.args[0], _('template file %s: %s') %
89 (self.map[t], inst.args[1]))
89 (self.map[t], inst.args[1]))
90 return self.cache[t]
90 return self.cache[t]
91
91
92 def _process(self, tmpl, map):
92 def _process(self, tmpl, map):
93 '''Render a template. Returns a generator.'''
93 '''Render a template. Returns a generator.'''
94 while tmpl:
94 while tmpl:
95 m = self.template_re.search(tmpl)
95 m = self.template_re.search(tmpl)
96 if not m:
96 if not m:
97 yield tmpl
97 yield tmpl
98 break
98 break
99
99
100 start, end = m.span(0)
100 start, end = m.span(0)
101 key, format, fl = m.groups()
101 key, format, fl = m.groups()
102
102
103 if start:
103 if start:
104 yield tmpl[:start]
104 yield tmpl[:start]
105 tmpl = tmpl[end:]
105 tmpl = tmpl[end:]
106
106
107 if key in map:
107 if key in map:
108 v = map[key]
108 v = map[key]
109 else:
109 else:
110 v = self.defaults.get(key, "")
110 v = self.defaults.get(key, "")
111 if callable(v):
111 if callable(v):
112 v = v(**map)
112 v = v(**map)
113 if format:
113 if format:
114 if not hasattr(v, '__iter__'):
114 if not hasattr(v, '__iter__'):
115 raise SyntaxError(_("Error expanding '%s%%%s'")
115 raise SyntaxError(_("Error expanding '%s%%%s'")
116 % (key, format))
116 % (key, format))
117 lm = map.copy()
117 lm = map.copy()
118 for i in v:
118 for i in v:
119 lm.update(i)
119 lm.update(i)
120 t = self._template(format)
120 t = self._template(format)
121 yield self._process(t, lm)
121 yield self._process(t, lm)
122 else:
122 else:
123 if fl:
123 if fl:
124 for f in fl.split("|")[1:]:
124 for f in fl.split("|")[1:]:
125 v = self.filters[f](v)
125 v = self.filters[f](v)
126 yield v
126 yield v
127
127
128 def __call__(self, t, **map):
128 def __call__(self, t, **map):
129 stream = self.expand(t, **map)
129 stream = self.expand(t, **map)
130 if self.minchunk:
130 if self.minchunk:
131 stream = util.increasingchunks(stream, min=self.minchunk,
131 stream = util.increasingchunks(stream, min=self.minchunk,
132 max=self.maxchunk)
132 max=self.maxchunk)
133 return stream
133 return stream
134
134
135 def expand(self, t, **map):
135 def expand(self, t, **map):
136 '''Perform expansion. t is name of map element to expand. map contains
136 '''Perform expansion. t is name of map element to expand. map contains
137 added elements for use during expansion. Is a generator.'''
137 added elements for use during expansion. Is a generator.'''
138 tmpl = self._template(t)
138 tmpl = self._template(t)
139 iters = [self._process(tmpl, map)]
139 iters = [self._process(tmpl, map)]
140 while iters:
140 while iters:
141 try:
141 try:
142 item = iters[0].next()
142 item = iters[0].next()
143 except StopIteration:
143 except StopIteration:
144 iters.pop(0)
144 iters.pop(0)
145 continue
145 continue
146 if isinstance(item, str):
146 if isinstance(item, str):
147 yield item
147 yield item
148 elif item is None:
148 elif item is None:
149 yield ''
149 yield ''
150 elif hasattr(item, '__iter__'):
150 elif hasattr(item, '__iter__'):
151 iters.insert(0, iter(item))
151 iters.insert(0, iter(item))
152 else:
152 else:
153 yield str(item)
153 yield str(item)
154
154
155 def templatepath(name=None):
155 def templatepath(name=None):
156 '''return location of template file or directory (if no name).
156 '''return location of template file or directory (if no name).
157 returns None if not found.'''
157 returns None if not found.'''
158 normpaths = []
158 normpaths = []
159
159
160 # executable version (py2exe) doesn't support __file__
160 # executable version (py2exe) doesn't support __file__
161 if hasattr(sys, 'frozen'):
161 if hasattr(sys, 'frozen'):
162 module = sys.executable
162 module = sys.executable
163 else:
163 else:
164 module = __file__
164 module = __file__
165 for f in path:
165 for f in path:
166 if f.startswith('/'):
166 if f.startswith('/'):
167 p = f
167 p = f
168 else:
168 else:
169 fl = f.split('/')
169 fl = f.split('/')
170 p = os.path.join(os.path.dirname(module), *fl)
170 p = os.path.join(os.path.dirname(module), *fl)
171 if name:
171 if name:
172 p = os.path.join(p, name)
172 p = os.path.join(p, name)
173 if name and os.path.exists(p):
173 if name and os.path.exists(p):
174 return os.path.normpath(p)
174 return os.path.normpath(p)
175 elif os.path.isdir(p):
175 elif os.path.isdir(p):
176 normpaths.append(os.path.normpath(p))
176 normpaths.append(os.path.normpath(p))
177
177
178 return normpaths
178 return normpaths
179
179
180 def stylemap(style, paths=None):
180 def stylemap(style, paths=None):
181 """Return path to mapfile for a given style.
181 """Return path to mapfile for a given style.
182
182
183 Searches mapfile in the following locations:
183 Searches mapfile in the following locations:
184 1. templatepath/style/map
184 1. templatepath/style/map
185 2. templatepath/map-style
185 2. templatepath/map-style
186 3. templatepath/map
186 3. templatepath/map
187 """
187 """
188
188
189 if paths is None:
189 if paths is None:
190 paths = templatepath()
190 paths = templatepath()
191 elif isinstance(paths, str):
191 elif isinstance(paths, str):
192 paths = [templatepath]
192 paths = [templatepath]
193
193
194 locations = style and [os.path.join(style, "map"), "map-" + style] or []
194 locations = style and [os.path.join(style, "map"), "map-" + style] or []
195 locations.append("map")
195 locations.append("map")
196 for path in paths:
196 for path in paths:
197 for location in locations:
197 for location in locations:
198 mapfile = os.path.join(path, location)
198 mapfile = os.path.join(path, location)
199 if os.path.isfile(mapfile):
199 if os.path.isfile(mapfile):
200 return mapfile
200 return mapfile
201
201
202 raise RuntimeError("No hgweb templates found in %r" % paths)
202 raise RuntimeError("No hgweb templates found in %r" % paths)
203
203
204 def stringify(thing):
204 def stringify(thing):
205 '''turn nested template iterator into string.'''
205 '''turn nested template iterator into string.'''
206 if hasattr(thing, '__iter__') and not isinstance(thing, str):
206 if hasattr(thing, '__iter__') and not isinstance(thing, str):
207 return "".join([stringify(t) for t in thing if t is not None])
207 return "".join([stringify(t) for t in thing if t is not None])
208 return str(thing)
208 return str(thing)
@@ -1,353 +1,353 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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile
9 import errno, getpass, os, re, socket, sys, tempfile
10 import config, traceback, util, error
10 import config, traceback, util, error
11
11
12 _booleans = {'1':True, 'yes':True, 'true':True, 'on':True,
12 _booleans = {'1':True, 'yes':True, 'true':True, 'on':True,
13 '0':False, 'no':False, 'false':False, 'off':False}
13 '0':False, 'no':False, 'false':False, 'off':False}
14
14
15 class ui(object):
15 class ui(object):
16 def __init__(self, src=None):
16 def __init__(self, src=None):
17 self.buffers = []
17 self.buffers = []
18 self.quiet = self.verbose = self.debugflag = self.traceback = False
18 self.quiet = self.verbose = self.debugflag = self.traceback = False
19 self.interactive = self.report_untrusted = True
19 self.interactive = self.report_untrusted = True
20 self.overlay = config.config()
20 self.overlay = config.config()
21 self.cdata = config.config()
21 self.cdata = config.config()
22 self.ucdata = config.config()
22 self.ucdata = config.config()
23 self.trusted_users = {}
23 self.trusted_users = {}
24 self.trusted_groups = {}
24 self.trusted_groups = {}
25
25
26 if src:
26 if src:
27 self.cdata = src.cdata.copy()
27 self.cdata = src.cdata.copy()
28 self.ucdata = src.ucdata.copy()
28 self.ucdata = src.ucdata.copy()
29 self.overlay = src.overlay.copy()
29 self.overlay = src.overlay.copy()
30 self.trusted_users = src.trusted_users.copy()
30 self.trusted_users = src.trusted_users.copy()
31 self.trusted_groups = src.trusted_groups.copy()
31 self.trusted_groups = src.trusted_groups.copy()
32 self.fixconfig()
32 self.fixconfig()
33 else:
33 else:
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, assumetrusted=True)
36 self.readconfig(f, assumetrusted=True)
37 def copy(self):
37 def copy(self):
38 return ui(self)
38 return ui(self)
39
39
40 _isatty = None
40 _isatty = None
41 def isatty(self):
41 def isatty(self):
42 if ui._isatty is None:
42 if ui._isatty is None:
43 try:
43 try:
44 ui._isatty = sys.stdin.isatty()
44 ui._isatty = sys.stdin.isatty()
45 except AttributeError: # not a real file object
45 except AttributeError: # not a real file object
46 ui._isatty = False
46 ui._isatty = False
47 except IOError:
47 except IOError:
48 # access to stdin is unsafe in a WSGI environment
48 # access to stdin is unsafe in a WSGI environment
49 ui._isatty = False
49 ui._isatty = False
50 return ui._isatty
50 return ui._isatty
51
51
52 def _is_trusted(self, fp, f):
52 def _is_trusted(self, fp, f):
53 st = util.fstat(fp)
53 st = util.fstat(fp)
54 if util.isowner(fp, st):
54 if util.isowner(fp, st):
55 return True
55 return True
56
56
57 tusers = self.trusted_users
57 tusers = self.trusted_users
58 tgroups = self.trusted_groups
58 tgroups = self.trusted_groups
59 if '*' in tusers or '*' in tgroups:
59 if '*' in tusers or '*' in tgroups:
60 return True
60 return True
61
61
62 user = util.username(st.st_uid)
62 user = util.username(st.st_uid)
63 group = util.groupname(st.st_gid)
63 group = util.groupname(st.st_gid)
64 if user in tusers or group in tgroups or user == util.username():
64 if user in tusers or group in tgroups or user == util.username():
65 return True
65 return True
66
66
67 if self.report_untrusted:
67 if self.report_untrusted:
68 self.warn(_('Not trusting file %s from untrusted '
68 self.warn(_('Not trusting file %s from untrusted '
69 'user %s, group %s\n') % (f, user, group))
69 'user %s, group %s\n') % (f, user, group))
70 return False
70 return False
71
71
72 def readconfig(self, filename, root=None, assumetrusted=False,
72 def readconfig(self, filename, root=None, assumetrusted=False,
73 sections = None):
73 sections = None):
74 try:
74 try:
75 fp = open(filename)
75 fp = open(filename)
76 except IOError:
76 except IOError:
77 if not sections: # ignore unless we were looking for something
77 if not sections: # ignore unless we were looking for something
78 return
78 return
79 raise
79 raise
80
80
81 cdata = config.config()
81 cdata = config.config()
82 trusted = sections or assumetrusted or self._is_trusted(fp, filename)
82 trusted = sections or assumetrusted or self._is_trusted(fp, filename)
83
83
84 try:
84 try:
85 cdata.read(filename, fp, sections=sections)
85 cdata.read(filename, fp, sections=sections)
86 except error.ConfigError, inst:
86 except error.ConfigError, inst:
87 if trusted:
87 if trusted:
88 raise
88 raise
89 self.warn(_("Ignored: %s\n") % str(inst))
89 self.warn(_("Ignored: %s\n") % str(inst))
90
90
91 if trusted:
91 if trusted:
92 self.cdata.update(cdata)
92 self.cdata.update(cdata)
93 self.cdata.update(self.overlay)
93 self.cdata.update(self.overlay)
94 self.ucdata.update(cdata)
94 self.ucdata.update(cdata)
95 self.ucdata.update(self.overlay)
95 self.ucdata.update(self.overlay)
96
96
97 if root is None:
97 if root is None:
98 root = os.path.expanduser('~')
98 root = os.path.expanduser('~')
99 self.fixconfig(root=root)
99 self.fixconfig(root=root)
100
100
101 def fixconfig(self, root=None):
101 def fixconfig(self, root=None):
102 # translate paths relative to root (or home) into absolute paths
102 # translate paths relative to root (or home) into absolute paths
103 root = root or os.getcwd()
103 root = root or os.getcwd()
104 for c in self.cdata, self.ucdata, self.overlay:
104 for c in self.cdata, self.ucdata, self.overlay:
105 for n, p in c.items('paths'):
105 for n, p in c.items('paths'):
106 if p and "://" not in p and not os.path.isabs(p):
106 if p and "://" not in p and not os.path.isabs(p):
107 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
107 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
108
108
109 # update ui options
109 # update ui options
110 self.debugflag = self.configbool('ui', 'debug')
110 self.debugflag = self.configbool('ui', 'debug')
111 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
111 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
112 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
112 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
113 if self.verbose and self.quiet:
113 if self.verbose and self.quiet:
114 self.quiet = self.verbose = False
114 self.quiet = self.verbose = False
115 self.report_untrusted = self.configbool("ui", "report_untrusted", True)
115 self.report_untrusted = self.configbool("ui", "report_untrusted", True)
116 self.interactive = self.configbool("ui", "interactive", self.isatty())
116 self.interactive = self.configbool("ui", "interactive", self.isatty())
117 self.traceback = self.configbool('ui', 'traceback', False)
117 self.traceback = self.configbool('ui', 'traceback', False)
118
118
119 # update trust information
119 # update trust information
120 for user in self.configlist('trusted', 'users'):
120 for user in self.configlist('trusted', 'users'):
121 self.trusted_users[user] = 1
121 self.trusted_users[user] = 1
122 for group in self.configlist('trusted', 'groups'):
122 for group in self.configlist('trusted', 'groups'):
123 self.trusted_groups[group] = 1
123 self.trusted_groups[group] = 1
124
124
125 def setconfig(self, section, name, value):
125 def setconfig(self, section, name, value):
126 for cdata in (self.overlay, self.cdata, self.ucdata):
126 for cdata in (self.overlay, self.cdata, self.ucdata):
127 cdata.set(section, name, value)
127 cdata.set(section, name, value)
128 self.fixconfig()
128 self.fixconfig()
129
129
130 def _get_cdata(self, untrusted):
130 def _get_cdata(self, untrusted):
131 if untrusted:
131 if untrusted:
132 return self.ucdata
132 return self.ucdata
133 return self.cdata
133 return self.cdata
134
134
135 def configsource(self, section, name, untrusted=False):
135 def configsource(self, section, name, untrusted=False):
136 return self._get_cdata(untrusted).getsource(section, name) or 'none'
136 return self._get_cdata(untrusted).source(section, name) or 'none'
137
137
138 def config(self, section, name, default=None, untrusted=False):
138 def config(self, section, name, default=None, untrusted=False):
139 value = self._get_cdata(untrusted).get(section, name, default)
139 value = self._get_cdata(untrusted).get(section, name, default)
140 if self.debugflag and not untrusted:
140 if self.debugflag and not untrusted:
141 uvalue = self.ucdata.get(section, name)
141 uvalue = self.ucdata.get(section, name)
142 if uvalue is not None and uvalue != value:
142 if uvalue is not None and uvalue != value:
143 self.warn(_("Ignoring untrusted configuration option "
143 self.warn(_("Ignoring untrusted configuration option "
144 "%s.%s = %s\n") % (section, name, uvalue))
144 "%s.%s = %s\n") % (section, name, uvalue))
145 return value
145 return value
146
146
147 def configbool(self, section, name, default=False, untrusted=False):
147 def configbool(self, section, name, default=False, untrusted=False):
148 v = self.config(section, name, None, untrusted)
148 v = self.config(section, name, None, untrusted)
149 if v == None:
149 if v == None:
150 return default
150 return default
151 if v.lower() not in _booleans:
151 if v.lower() not in _booleans:
152 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
152 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
153 % (section, name, v))
153 % (section, name, v))
154 return _booleans[v.lower()]
154 return _booleans[v.lower()]
155
155
156 def configlist(self, section, name, default=None, untrusted=False):
156 def configlist(self, section, name, default=None, untrusted=False):
157 """Return a list of comma/space separated strings"""
157 """Return a list of comma/space separated strings"""
158 result = self.config(section, name, untrusted=untrusted)
158 result = self.config(section, name, untrusted=untrusted)
159 if result is None:
159 if result is None:
160 result = default or []
160 result = default or []
161 if isinstance(result, basestring):
161 if isinstance(result, basestring):
162 result = result.replace(",", " ").split()
162 result = result.replace(",", " ").split()
163 return result
163 return result
164
164
165 def has_section(self, section, untrusted=False):
165 def has_section(self, section, untrusted=False):
166 '''tell whether section exists in config.'''
166 '''tell whether section exists in config.'''
167 return section in self._get_cdata(untrusted)
167 return section in self._get_cdata(untrusted)
168
168
169 def configitems(self, section, untrusted=False):
169 def configitems(self, section, untrusted=False):
170 items = self._get_cdata(untrusted).items(section)
170 items = self._get_cdata(untrusted).items(section)
171 if self.debugflag and not untrusted:
171 if self.debugflag and not untrusted:
172 for k,v in self.ucdata.items(section):
172 for k,v in self.ucdata.items(section):
173 if self.cdata.get(section, k) != v:
173 if self.cdata.get(section, k) != v:
174 self.warn(_("Ignoring untrusted configuration option "
174 self.warn(_("Ignoring untrusted configuration option "
175 "%s.%s = %s\n") % (section, k, v))
175 "%s.%s = %s\n") % (section, k, v))
176 return items
176 return items
177
177
178 def walkconfig(self, untrusted=False):
178 def walkconfig(self, untrusted=False):
179 cdata = self._get_cdata(untrusted)
179 cdata = self._get_cdata(untrusted)
180 for section in cdata.sections():
180 for section in cdata.sections():
181 for name, value in self.configitems(section, untrusted):
181 for name, value in self.configitems(section, untrusted):
182 yield section, name, str(value).replace('\n', '\\n')
182 yield section, name, str(value).replace('\n', '\\n')
183
183
184 def username(self):
184 def username(self):
185 """Return default username to be used in commits.
185 """Return default username to be used in commits.
186
186
187 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
187 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
188 and stop searching if one of these is set.
188 and stop searching if one of these is set.
189 If not found and ui.askusername is True, ask the user, else use
189 If not found and ui.askusername is True, ask the user, else use
190 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
190 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
191 """
191 """
192 user = os.environ.get("HGUSER")
192 user = os.environ.get("HGUSER")
193 if user is None:
193 if user is None:
194 user = self.config("ui", "username")
194 user = self.config("ui", "username")
195 if user is None:
195 if user is None:
196 user = os.environ.get("EMAIL")
196 user = os.environ.get("EMAIL")
197 if user is None and self.configbool("ui", "askusername"):
197 if user is None and self.configbool("ui", "askusername"):
198 user = self.prompt(_("enter a commit username:"), default=None)
198 user = self.prompt(_("enter a commit username:"), default=None)
199 if user is None:
199 if user is None:
200 try:
200 try:
201 user = '%s@%s' % (util.getuser(), socket.getfqdn())
201 user = '%s@%s' % (util.getuser(), socket.getfqdn())
202 self.warn(_("No username found, using '%s' instead\n") % user)
202 self.warn(_("No username found, using '%s' instead\n") % user)
203 except KeyError:
203 except KeyError:
204 pass
204 pass
205 if not user:
205 if not user:
206 raise util.Abort(_("Please specify a username."))
206 raise util.Abort(_("Please specify a username."))
207 if "\n" in user:
207 if "\n" in user:
208 raise util.Abort(_("username %s contains a newline\n") % repr(user))
208 raise util.Abort(_("username %s contains a newline\n") % repr(user))
209 return user
209 return user
210
210
211 def shortuser(self, user):
211 def shortuser(self, user):
212 """Return a short representation of a user name or email address."""
212 """Return a short representation of a user name or email address."""
213 if not self.verbose: user = util.shortuser(user)
213 if not self.verbose: user = util.shortuser(user)
214 return user
214 return user
215
215
216 def _path(self, loc):
216 def _path(self, loc):
217 p = self.config('paths', loc)
217 p = self.config('paths', loc)
218 if p and '%%' in p:
218 if p and '%%' in p:
219 ui.warn('(deprecated \'\%\%\' in path %s=%s from %s)\n' %
219 ui.warn('(deprecated \'\%\%\' in path %s=%s from %s)\n' %
220 (loc, p, self.configsource('paths', loc)))
220 (loc, p, self.configsource('paths', loc)))
221 p = p.replace('%%', '%')
221 p = p.replace('%%', '%')
222 return p
222 return p
223
223
224 def expandpath(self, loc, default=None):
224 def expandpath(self, loc, default=None):
225 """Return repository location relative to cwd or from [paths]"""
225 """Return repository location relative to cwd or from [paths]"""
226 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
226 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
227 return loc
227 return loc
228
228
229 path = self._path(loc)
229 path = self._path(loc)
230 if not path and default is not None:
230 if not path and default is not None:
231 path = self._path(default)
231 path = self._path(default)
232 return path or loc
232 return path or loc
233
233
234 def pushbuffer(self):
234 def pushbuffer(self):
235 self.buffers.append([])
235 self.buffers.append([])
236
236
237 def popbuffer(self):
237 def popbuffer(self):
238 return "".join(self.buffers.pop())
238 return "".join(self.buffers.pop())
239
239
240 def write(self, *args):
240 def write(self, *args):
241 if self.buffers:
241 if self.buffers:
242 self.buffers[-1].extend([str(a) for a in args])
242 self.buffers[-1].extend([str(a) for a in args])
243 else:
243 else:
244 for a in args:
244 for a in args:
245 sys.stdout.write(str(a))
245 sys.stdout.write(str(a))
246
246
247 def write_err(self, *args):
247 def write_err(self, *args):
248 try:
248 try:
249 if not sys.stdout.closed: sys.stdout.flush()
249 if not sys.stdout.closed: sys.stdout.flush()
250 for a in args:
250 for a in args:
251 sys.stderr.write(str(a))
251 sys.stderr.write(str(a))
252 # stderr may be buffered under win32 when redirected to files,
252 # stderr may be buffered under win32 when redirected to files,
253 # including stdout.
253 # including stdout.
254 if not sys.stderr.closed: sys.stderr.flush()
254 if not sys.stderr.closed: sys.stderr.flush()
255 except IOError, inst:
255 except IOError, inst:
256 if inst.errno != errno.EPIPE:
256 if inst.errno != errno.EPIPE:
257 raise
257 raise
258
258
259 def flush(self):
259 def flush(self):
260 try: sys.stdout.flush()
260 try: sys.stdout.flush()
261 except: pass
261 except: pass
262 try: sys.stderr.flush()
262 try: sys.stderr.flush()
263 except: pass
263 except: pass
264
264
265 def _readline(self, prompt=''):
265 def _readline(self, prompt=''):
266 if self.isatty():
266 if self.isatty():
267 try:
267 try:
268 # magically add command line editing support, where
268 # magically add command line editing support, where
269 # available
269 # available
270 import readline
270 import readline
271 # force demandimport to really load the module
271 # force demandimport to really load the module
272 readline.read_history_file
272 readline.read_history_file
273 # windows sometimes raises something other than ImportError
273 # windows sometimes raises something other than ImportError
274 except Exception:
274 except Exception:
275 pass
275 pass
276 line = raw_input(prompt)
276 line = raw_input(prompt)
277 # When stdin is in binary mode on Windows, it can cause
277 # When stdin is in binary mode on Windows, it can cause
278 # raw_input() to emit an extra trailing carriage return
278 # raw_input() to emit an extra trailing carriage return
279 if os.linesep == '\r\n' and line and line[-1] == '\r':
279 if os.linesep == '\r\n' and line and line[-1] == '\r':
280 line = line[:-1]
280 line = line[:-1]
281 return line
281 return line
282
282
283 def prompt(self, msg, pat=None, default="y"):
283 def prompt(self, msg, pat=None, default="y"):
284 """Prompt user with msg, read response, and ensure it matches pat
284 """Prompt user with msg, read response, and ensure it matches pat
285
285
286 If not interactive -- the default is returned
286 If not interactive -- the default is returned
287 """
287 """
288 if not self.interactive:
288 if not self.interactive:
289 self.note(msg, ' ', default, "\n")
289 self.note(msg, ' ', default, "\n")
290 return default
290 return default
291 while True:
291 while True:
292 try:
292 try:
293 r = self._readline(msg + ' ')
293 r = self._readline(msg + ' ')
294 if not r:
294 if not r:
295 return default
295 return default
296 if not pat or re.match(pat, r):
296 if not pat or re.match(pat, r):
297 return r
297 return r
298 else:
298 else:
299 self.write(_("unrecognized response\n"))
299 self.write(_("unrecognized response\n"))
300 except EOFError:
300 except EOFError:
301 raise util.Abort(_('response expected'))
301 raise util.Abort(_('response expected'))
302
302
303 def getpass(self, prompt=None, default=None):
303 def getpass(self, prompt=None, default=None):
304 if not self.interactive: return default
304 if not self.interactive: return default
305 try:
305 try:
306 return getpass.getpass(prompt or _('password: '))
306 return getpass.getpass(prompt or _('password: '))
307 except EOFError:
307 except EOFError:
308 raise util.Abort(_('response expected'))
308 raise util.Abort(_('response expected'))
309 def status(self, *msg):
309 def status(self, *msg):
310 if not self.quiet: self.write(*msg)
310 if not self.quiet: self.write(*msg)
311 def warn(self, *msg):
311 def warn(self, *msg):
312 self.write_err(*msg)
312 self.write_err(*msg)
313 def note(self, *msg):
313 def note(self, *msg):
314 if self.verbose: self.write(*msg)
314 if self.verbose: self.write(*msg)
315 def debug(self, *msg):
315 def debug(self, *msg):
316 if self.debugflag: self.write(*msg)
316 if self.debugflag: self.write(*msg)
317 def edit(self, text, user):
317 def edit(self, text, user):
318 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
318 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
319 text=True)
319 text=True)
320 try:
320 try:
321 f = os.fdopen(fd, "w")
321 f = os.fdopen(fd, "w")
322 f.write(text)
322 f.write(text)
323 f.close()
323 f.close()
324
324
325 editor = self.geteditor()
325 editor = self.geteditor()
326
326
327 util.system("%s \"%s\"" % (editor, name),
327 util.system("%s \"%s\"" % (editor, name),
328 environ={'HGUSER': user},
328 environ={'HGUSER': user},
329 onerr=util.Abort, errprefix=_("edit failed"))
329 onerr=util.Abort, errprefix=_("edit failed"))
330
330
331 f = open(name)
331 f = open(name)
332 t = f.read()
332 t = f.read()
333 f.close()
333 f.close()
334 t = re.sub("(?m)^HG:.*\n", "", t)
334 t = re.sub("(?m)^HG:.*\n", "", t)
335 finally:
335 finally:
336 os.unlink(name)
336 os.unlink(name)
337
337
338 return t
338 return t
339
339
340 def print_exc(self):
340 def print_exc(self):
341 '''print exception traceback if traceback printing enabled.
341 '''print exception traceback if traceback printing enabled.
342 only to call in exception handler. returns true if traceback
342 only to call in exception handler. returns true if traceback
343 printed.'''
343 printed.'''
344 if self.traceback:
344 if self.traceback:
345 traceback.print_exc()
345 traceback.print_exc()
346 return self.traceback
346 return self.traceback
347
347
348 def geteditor(self):
348 def geteditor(self):
349 '''return editor to use'''
349 '''return editor to use'''
350 return (os.environ.get("HGEDITOR") or
350 return (os.environ.get("HGEDITOR") or
351 self.config("ui", "editor") or
351 self.config("ui", "editor") or
352 os.environ.get("VISUAL") or
352 os.environ.get("VISUAL") or
353 os.environ.get("EDITOR", "vi"))
353 os.environ.get("EDITOR", "vi"))
General Comments 0
You need to be logged in to leave comments. Login now