##// END OF EJS Templates
opener: introduce an abstact superclass of it...
Dan Villiom Podlaski Christiansen -
r14089:d3f7e110 default
parent child Browse files
Show More
@@ -1,424 +1,431 b''
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright 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 util, error, osutil
9 import util, error, osutil
10 import os, errno, stat, sys
10 import os, errno, stat, sys
11
11
12 def checkfilename(f):
12 def checkfilename(f):
13 '''Check that the filename f is an acceptable filename for a tracked file'''
13 '''Check that the filename f is an acceptable filename for a tracked file'''
14 if '\r' in f or '\n' in f:
14 if '\r' in f or '\n' in f:
15 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
15 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
16
16
17 def checkportable(ui, f):
17 def checkportable(ui, f):
18 '''Check if filename f is portable and warn or abort depending on config'''
18 '''Check if filename f is portable and warn or abort depending on config'''
19 checkfilename(f)
19 checkfilename(f)
20 if showportabilityalert(ui):
20 if showportabilityalert(ui):
21 msg = util.checkwinfilename(f)
21 msg = util.checkwinfilename(f)
22 if msg:
22 if msg:
23 portabilityalert(ui, "%s: %r" % (msg, f))
23 portabilityalert(ui, "%s: %r" % (msg, f))
24
24
25 def checkcasecollision(ui, f, files):
25 def checkcasecollision(ui, f, files):
26 if f.lower() in files and files[f.lower()] != f:
26 if f.lower() in files and files[f.lower()] != f:
27 portabilityalert(ui, _('possible case-folding collision for %s') % f)
27 portabilityalert(ui, _('possible case-folding collision for %s') % f)
28 files[f.lower()] = f
28 files[f.lower()] = f
29
29
30 def checkportabilityalert(ui):
30 def checkportabilityalert(ui):
31 '''check if the user's config requests nothing, a warning, or abort for
31 '''check if the user's config requests nothing, a warning, or abort for
32 non-portable filenames'''
32 non-portable filenames'''
33 val = ui.config('ui', 'portablefilenames', 'warn')
33 val = ui.config('ui', 'portablefilenames', 'warn')
34 lval = val.lower()
34 lval = val.lower()
35 bval = util.parsebool(val)
35 bval = util.parsebool(val)
36 abort = os.name == 'nt' or lval == 'abort'
36 abort = os.name == 'nt' or lval == 'abort'
37 warn = bval or lval == 'warn'
37 warn = bval or lval == 'warn'
38 if bval is None and not (warn or abort or lval == 'ignore'):
38 if bval is None and not (warn or abort or lval == 'ignore'):
39 raise error.ConfigError(
39 raise error.ConfigError(
40 _("ui.portablefilenames value is invalid ('%s')") % val)
40 _("ui.portablefilenames value is invalid ('%s')") % val)
41 return abort, warn
41 return abort, warn
42
42
43 def showportabilityalert(ui):
43 def showportabilityalert(ui):
44 '''check if the user wants any notification of portability problems'''
44 '''check if the user wants any notification of portability problems'''
45 abort, warn = checkportabilityalert(ui)
45 abort, warn = checkportabilityalert(ui)
46 return abort or warn
46 return abort or warn
47
47
48 def portabilityalert(ui, msg):
48 def portabilityalert(ui, msg):
49 if not msg:
49 if not msg:
50 return
50 return
51 abort, warn = checkportabilityalert(ui)
51 abort, warn = checkportabilityalert(ui)
52 if abort:
52 if abort:
53 raise util.Abort("%s" % msg)
53 raise util.Abort("%s" % msg)
54 elif warn:
54 elif warn:
55 ui.warn(_("warning: %s\n") % msg)
55 ui.warn(_("warning: %s\n") % msg)
56
56
57 class path_auditor(object):
57 class path_auditor(object):
58 '''ensure that a filesystem path contains no banned components.
58 '''ensure that a filesystem path contains no banned components.
59 the following properties of a path are checked:
59 the following properties of a path are checked:
60
60
61 - ends with a directory separator
61 - ends with a directory separator
62 - under top-level .hg
62 - under top-level .hg
63 - starts at the root of a windows drive
63 - starts at the root of a windows drive
64 - contains ".."
64 - contains ".."
65 - traverses a symlink (e.g. a/symlink_here/b)
65 - traverses a symlink (e.g. a/symlink_here/b)
66 - inside a nested repository (a callback can be used to approve
66 - inside a nested repository (a callback can be used to approve
67 some nested repositories, e.g., subrepositories)
67 some nested repositories, e.g., subrepositories)
68 '''
68 '''
69
69
70 def __init__(self, root, callback=None):
70 def __init__(self, root, callback=None):
71 self.audited = set()
71 self.audited = set()
72 self.auditeddir = set()
72 self.auditeddir = set()
73 self.root = root
73 self.root = root
74 self.callback = callback
74 self.callback = callback
75
75
76 def __call__(self, path):
76 def __call__(self, path):
77 '''Check the relative path.
77 '''Check the relative path.
78 path may contain a pattern (e.g. foodir/**.txt)'''
78 path may contain a pattern (e.g. foodir/**.txt)'''
79
79
80 if path in self.audited:
80 if path in self.audited:
81 return
81 return
82 # AIX ignores "/" at end of path, others raise EISDIR.
82 # AIX ignores "/" at end of path, others raise EISDIR.
83 if util.endswithsep(path):
83 if util.endswithsep(path):
84 raise util.Abort(_("path ends in directory separator: %s") % path)
84 raise util.Abort(_("path ends in directory separator: %s") % path)
85 normpath = os.path.normcase(path)
85 normpath = os.path.normcase(path)
86 parts = util.splitpath(normpath)
86 parts = util.splitpath(normpath)
87 if (os.path.splitdrive(path)[0]
87 if (os.path.splitdrive(path)[0]
88 or parts[0].lower() in ('.hg', '.hg.', '')
88 or parts[0].lower() in ('.hg', '.hg.', '')
89 or os.pardir in parts):
89 or os.pardir in parts):
90 raise util.Abort(_("path contains illegal component: %s") % path)
90 raise util.Abort(_("path contains illegal component: %s") % path)
91 if '.hg' in path.lower():
91 if '.hg' in path.lower():
92 lparts = [p.lower() for p in parts]
92 lparts = [p.lower() for p in parts]
93 for p in '.hg', '.hg.':
93 for p in '.hg', '.hg.':
94 if p in lparts[1:]:
94 if p in lparts[1:]:
95 pos = lparts.index(p)
95 pos = lparts.index(p)
96 base = os.path.join(*parts[:pos])
96 base = os.path.join(*parts[:pos])
97 raise util.Abort(_('path %r is inside nested repo %r')
97 raise util.Abort(_('path %r is inside nested repo %r')
98 % (path, base))
98 % (path, base))
99
99
100 parts.pop()
100 parts.pop()
101 prefixes = []
101 prefixes = []
102 while parts:
102 while parts:
103 prefix = os.sep.join(parts)
103 prefix = os.sep.join(parts)
104 if prefix in self.auditeddir:
104 if prefix in self.auditeddir:
105 break
105 break
106 curpath = os.path.join(self.root, prefix)
106 curpath = os.path.join(self.root, prefix)
107 try:
107 try:
108 st = os.lstat(curpath)
108 st = os.lstat(curpath)
109 except OSError, err:
109 except OSError, err:
110 # EINVAL can be raised as invalid path syntax under win32.
110 # EINVAL can be raised as invalid path syntax under win32.
111 # They must be ignored for patterns can be checked too.
111 # They must be ignored for patterns can be checked too.
112 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
112 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
113 raise
113 raise
114 else:
114 else:
115 if stat.S_ISLNK(st.st_mode):
115 if stat.S_ISLNK(st.st_mode):
116 raise util.Abort(
116 raise util.Abort(
117 _('path %r traverses symbolic link %r')
117 _('path %r traverses symbolic link %r')
118 % (path, prefix))
118 % (path, prefix))
119 elif (stat.S_ISDIR(st.st_mode) and
119 elif (stat.S_ISDIR(st.st_mode) and
120 os.path.isdir(os.path.join(curpath, '.hg'))):
120 os.path.isdir(os.path.join(curpath, '.hg'))):
121 if not self.callback or not self.callback(curpath):
121 if not self.callback or not self.callback(curpath):
122 raise util.Abort(_('path %r is inside nested repo %r') %
122 raise util.Abort(_('path %r is inside nested repo %r') %
123 (path, prefix))
123 (path, prefix))
124 prefixes.append(prefix)
124 prefixes.append(prefix)
125 parts.pop()
125 parts.pop()
126
126
127 self.audited.add(path)
127 self.audited.add(path)
128 # only add prefixes to the cache after checking everything: we don't
128 # only add prefixes to the cache after checking everything: we don't
129 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
129 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
130 self.auditeddir.update(prefixes)
130 self.auditeddir.update(prefixes)
131
131
132 class opener(object):
132 class abstractopener(object):
133 """Abstract base class; cannot be instantiated"""
134
135 def __init__(self, *args, **kwargs):
136 '''Prevent instantiation; don't call this from subclasses.'''
137 raise NotImplementedError('attempted instantiating ' + str(type(self)))
138
139 class opener(abstractopener):
133 '''Open files relative to a base directory
140 '''Open files relative to a base directory
134
141
135 This class is used to hide the details of COW semantics and
142 This class is used to hide the details of COW semantics and
136 remote file access from higher level code.
143 remote file access from higher level code.
137 '''
144 '''
138 def __init__(self, base, audit=True):
145 def __init__(self, base, audit=True):
139 self.base = base
146 self.base = base
140 if audit:
147 if audit:
141 self.auditor = path_auditor(base)
148 self.auditor = path_auditor(base)
142 else:
149 else:
143 self.auditor = util.always
150 self.auditor = util.always
144 self.createmode = None
151 self.createmode = None
145 self._trustnlink = None
152 self._trustnlink = None
146
153
147 @util.propertycache
154 @util.propertycache
148 def _can_symlink(self):
155 def _can_symlink(self):
149 return util.checklink(self.base)
156 return util.checklink(self.base)
150
157
151 def _fixfilemode(self, name):
158 def _fixfilemode(self, name):
152 if self.createmode is None:
159 if self.createmode is None:
153 return
160 return
154 os.chmod(name, self.createmode & 0666)
161 os.chmod(name, self.createmode & 0666)
155
162
156 def __call__(self, path, mode="r", text=False, atomictemp=False):
163 def __call__(self, path, mode="r", text=False, atomictemp=False):
157 r = util.checkosfilename(path)
164 r = util.checkosfilename(path)
158 if r:
165 if r:
159 raise util.Abort("%s: %r" % (r, path))
166 raise util.Abort("%s: %r" % (r, path))
160 self.auditor(path)
167 self.auditor(path)
161 f = os.path.join(self.base, path)
168 f = os.path.join(self.base, path)
162
169
163 if not text and "b" not in mode:
170 if not text and "b" not in mode:
164 mode += "b" # for that other OS
171 mode += "b" # for that other OS
165
172
166 nlink = -1
173 nlink = -1
167 dirname, basename = os.path.split(f)
174 dirname, basename = os.path.split(f)
168 # If basename is empty, then the path is malformed because it points
175 # If basename is empty, then the path is malformed because it points
169 # to a directory. Let the posixfile() call below raise IOError.
176 # to a directory. Let the posixfile() call below raise IOError.
170 if basename and mode not in ('r', 'rb'):
177 if basename and mode not in ('r', 'rb'):
171 if atomictemp:
178 if atomictemp:
172 if not os.path.isdir(dirname):
179 if not os.path.isdir(dirname):
173 util.makedirs(dirname, self.createmode)
180 util.makedirs(dirname, self.createmode)
174 return util.atomictempfile(f, mode, self.createmode)
181 return util.atomictempfile(f, mode, self.createmode)
175 try:
182 try:
176 if 'w' in mode:
183 if 'w' in mode:
177 util.unlink(f)
184 util.unlink(f)
178 nlink = 0
185 nlink = 0
179 else:
186 else:
180 # nlinks() may behave differently for files on Windows
187 # nlinks() may behave differently for files on Windows
181 # shares if the file is open.
188 # shares if the file is open.
182 fd = util.posixfile(f)
189 fd = util.posixfile(f)
183 nlink = util.nlinks(f)
190 nlink = util.nlinks(f)
184 if nlink < 1:
191 if nlink < 1:
185 nlink = 2 # force mktempcopy (issue1922)
192 nlink = 2 # force mktempcopy (issue1922)
186 fd.close()
193 fd.close()
187 except (OSError, IOError), e:
194 except (OSError, IOError), e:
188 if e.errno != errno.ENOENT:
195 if e.errno != errno.ENOENT:
189 raise
196 raise
190 nlink = 0
197 nlink = 0
191 if not os.path.isdir(dirname):
198 if not os.path.isdir(dirname):
192 util.makedirs(dirname, self.createmode)
199 util.makedirs(dirname, self.createmode)
193 if nlink > 0:
200 if nlink > 0:
194 if self._trustnlink is None:
201 if self._trustnlink is None:
195 self._trustnlink = nlink > 1 or util.checknlink(f)
202 self._trustnlink = nlink > 1 or util.checknlink(f)
196 if nlink > 1 or not self._trustnlink:
203 if nlink > 1 or not self._trustnlink:
197 util.rename(util.mktempcopy(f), f)
204 util.rename(util.mktempcopy(f), f)
198 fp = util.posixfile(f, mode)
205 fp = util.posixfile(f, mode)
199 if nlink == 0:
206 if nlink == 0:
200 self._fixfilemode(f)
207 self._fixfilemode(f)
201 return fp
208 return fp
202
209
203 def symlink(self, src, dst):
210 def symlink(self, src, dst):
204 self.auditor(dst)
211 self.auditor(dst)
205 linkname = os.path.join(self.base, dst)
212 linkname = os.path.join(self.base, dst)
206 try:
213 try:
207 os.unlink(linkname)
214 os.unlink(linkname)
208 except OSError:
215 except OSError:
209 pass
216 pass
210
217
211 dirname = os.path.dirname(linkname)
218 dirname = os.path.dirname(linkname)
212 if not os.path.exists(dirname):
219 if not os.path.exists(dirname):
213 util.makedirs(dirname, self.createmode)
220 util.makedirs(dirname, self.createmode)
214
221
215 if self._can_symlink:
222 if self._can_symlink:
216 try:
223 try:
217 os.symlink(src, linkname)
224 os.symlink(src, linkname)
218 except OSError, err:
225 except OSError, err:
219 raise OSError(err.errno, _('could not symlink to %r: %s') %
226 raise OSError(err.errno, _('could not symlink to %r: %s') %
220 (src, err.strerror), linkname)
227 (src, err.strerror), linkname)
221 else:
228 else:
222 f = self(dst, "w")
229 f = self(dst, "w")
223 f.write(src)
230 f.write(src)
224 f.close()
231 f.close()
225 self._fixfilemode(dst)
232 self._fixfilemode(dst)
226
233
227 def canonpath(root, cwd, myname, auditor=None):
234 def canonpath(root, cwd, myname, auditor=None):
228 '''return the canonical path of myname, given cwd and root'''
235 '''return the canonical path of myname, given cwd and root'''
229 if util.endswithsep(root):
236 if util.endswithsep(root):
230 rootsep = root
237 rootsep = root
231 else:
238 else:
232 rootsep = root + os.sep
239 rootsep = root + os.sep
233 name = myname
240 name = myname
234 if not os.path.isabs(name):
241 if not os.path.isabs(name):
235 name = os.path.join(root, cwd, name)
242 name = os.path.join(root, cwd, name)
236 name = os.path.normpath(name)
243 name = os.path.normpath(name)
237 if auditor is None:
244 if auditor is None:
238 auditor = path_auditor(root)
245 auditor = path_auditor(root)
239 if name != rootsep and name.startswith(rootsep):
246 if name != rootsep and name.startswith(rootsep):
240 name = name[len(rootsep):]
247 name = name[len(rootsep):]
241 auditor(name)
248 auditor(name)
242 return util.pconvert(name)
249 return util.pconvert(name)
243 elif name == root:
250 elif name == root:
244 return ''
251 return ''
245 else:
252 else:
246 # Determine whether `name' is in the hierarchy at or beneath `root',
253 # Determine whether `name' is in the hierarchy at or beneath `root',
247 # by iterating name=dirname(name) until that causes no change (can't
254 # by iterating name=dirname(name) until that causes no change (can't
248 # check name == '/', because that doesn't work on windows). For each
255 # check name == '/', because that doesn't work on windows). For each
249 # `name', compare dev/inode numbers. If they match, the list `rel'
256 # `name', compare dev/inode numbers. If they match, the list `rel'
250 # holds the reversed list of components making up the relative file
257 # holds the reversed list of components making up the relative file
251 # name we want.
258 # name we want.
252 root_st = os.stat(root)
259 root_st = os.stat(root)
253 rel = []
260 rel = []
254 while True:
261 while True:
255 try:
262 try:
256 name_st = os.stat(name)
263 name_st = os.stat(name)
257 except OSError:
264 except OSError:
258 break
265 break
259 if util.samestat(name_st, root_st):
266 if util.samestat(name_st, root_st):
260 if not rel:
267 if not rel:
261 # name was actually the same as root (maybe a symlink)
268 # name was actually the same as root (maybe a symlink)
262 return ''
269 return ''
263 rel.reverse()
270 rel.reverse()
264 name = os.path.join(*rel)
271 name = os.path.join(*rel)
265 auditor(name)
272 auditor(name)
266 return util.pconvert(name)
273 return util.pconvert(name)
267 dirname, basename = os.path.split(name)
274 dirname, basename = os.path.split(name)
268 rel.append(basename)
275 rel.append(basename)
269 if dirname == name:
276 if dirname == name:
270 break
277 break
271 name = dirname
278 name = dirname
272
279
273 raise util.Abort('%s not under root' % myname)
280 raise util.Abort('%s not under root' % myname)
274
281
275 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
282 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
276 '''yield every hg repository under path, recursively.'''
283 '''yield every hg repository under path, recursively.'''
277 def errhandler(err):
284 def errhandler(err):
278 if err.filename == path:
285 if err.filename == path:
279 raise err
286 raise err
280 if followsym and hasattr(os.path, 'samestat'):
287 if followsym and hasattr(os.path, 'samestat'):
281 def _add_dir_if_not_there(dirlst, dirname):
288 def _add_dir_if_not_there(dirlst, dirname):
282 match = False
289 match = False
283 samestat = os.path.samestat
290 samestat = os.path.samestat
284 dirstat = os.stat(dirname)
291 dirstat = os.stat(dirname)
285 for lstdirstat in dirlst:
292 for lstdirstat in dirlst:
286 if samestat(dirstat, lstdirstat):
293 if samestat(dirstat, lstdirstat):
287 match = True
294 match = True
288 break
295 break
289 if not match:
296 if not match:
290 dirlst.append(dirstat)
297 dirlst.append(dirstat)
291 return not match
298 return not match
292 else:
299 else:
293 followsym = False
300 followsym = False
294
301
295 if (seen_dirs is None) and followsym:
302 if (seen_dirs is None) and followsym:
296 seen_dirs = []
303 seen_dirs = []
297 _add_dir_if_not_there(seen_dirs, path)
304 _add_dir_if_not_there(seen_dirs, path)
298 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
305 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
299 dirs.sort()
306 dirs.sort()
300 if '.hg' in dirs:
307 if '.hg' in dirs:
301 yield root # found a repository
308 yield root # found a repository
302 qroot = os.path.join(root, '.hg', 'patches')
309 qroot = os.path.join(root, '.hg', 'patches')
303 if os.path.isdir(os.path.join(qroot, '.hg')):
310 if os.path.isdir(os.path.join(qroot, '.hg')):
304 yield qroot # we have a patch queue repo here
311 yield qroot # we have a patch queue repo here
305 if recurse:
312 if recurse:
306 # avoid recursing inside the .hg directory
313 # avoid recursing inside the .hg directory
307 dirs.remove('.hg')
314 dirs.remove('.hg')
308 else:
315 else:
309 dirs[:] = [] # don't descend further
316 dirs[:] = [] # don't descend further
310 elif followsym:
317 elif followsym:
311 newdirs = []
318 newdirs = []
312 for d in dirs:
319 for d in dirs:
313 fname = os.path.join(root, d)
320 fname = os.path.join(root, d)
314 if _add_dir_if_not_there(seen_dirs, fname):
321 if _add_dir_if_not_there(seen_dirs, fname):
315 if os.path.islink(fname):
322 if os.path.islink(fname):
316 for hgname in walkrepos(fname, True, seen_dirs):
323 for hgname in walkrepos(fname, True, seen_dirs):
317 yield hgname
324 yield hgname
318 else:
325 else:
319 newdirs.append(d)
326 newdirs.append(d)
320 dirs[:] = newdirs
327 dirs[:] = newdirs
321
328
322 def os_rcpath():
329 def os_rcpath():
323 '''return default os-specific hgrc search path'''
330 '''return default os-specific hgrc search path'''
324 path = system_rcpath()
331 path = system_rcpath()
325 path.extend(user_rcpath())
332 path.extend(user_rcpath())
326 path = [os.path.normpath(f) for f in path]
333 path = [os.path.normpath(f) for f in path]
327 return path
334 return path
328
335
329 _rcpath = None
336 _rcpath = None
330
337
331 def rcpath():
338 def rcpath():
332 '''return hgrc search path. if env var HGRCPATH is set, use it.
339 '''return hgrc search path. if env var HGRCPATH is set, use it.
333 for each item in path, if directory, use files ending in .rc,
340 for each item in path, if directory, use files ending in .rc,
334 else use item.
341 else use item.
335 make HGRCPATH empty to only look in .hg/hgrc of current repo.
342 make HGRCPATH empty to only look in .hg/hgrc of current repo.
336 if no HGRCPATH, use default os-specific path.'''
343 if no HGRCPATH, use default os-specific path.'''
337 global _rcpath
344 global _rcpath
338 if _rcpath is None:
345 if _rcpath is None:
339 if 'HGRCPATH' in os.environ:
346 if 'HGRCPATH' in os.environ:
340 _rcpath = []
347 _rcpath = []
341 for p in os.environ['HGRCPATH'].split(os.pathsep):
348 for p in os.environ['HGRCPATH'].split(os.pathsep):
342 if not p:
349 if not p:
343 continue
350 continue
344 p = util.expandpath(p)
351 p = util.expandpath(p)
345 if os.path.isdir(p):
352 if os.path.isdir(p):
346 for f, kind in osutil.listdir(p):
353 for f, kind in osutil.listdir(p):
347 if f.endswith('.rc'):
354 if f.endswith('.rc'):
348 _rcpath.append(os.path.join(p, f))
355 _rcpath.append(os.path.join(p, f))
349 else:
356 else:
350 _rcpath.append(p)
357 _rcpath.append(p)
351 else:
358 else:
352 _rcpath = os_rcpath()
359 _rcpath = os_rcpath()
353 return _rcpath
360 return _rcpath
354
361
355 if os.name != 'nt':
362 if os.name != 'nt':
356
363
357 def rcfiles(path):
364 def rcfiles(path):
358 rcs = [os.path.join(path, 'hgrc')]
365 rcs = [os.path.join(path, 'hgrc')]
359 rcdir = os.path.join(path, 'hgrc.d')
366 rcdir = os.path.join(path, 'hgrc.d')
360 try:
367 try:
361 rcs.extend([os.path.join(rcdir, f)
368 rcs.extend([os.path.join(rcdir, f)
362 for f, kind in osutil.listdir(rcdir)
369 for f, kind in osutil.listdir(rcdir)
363 if f.endswith(".rc")])
370 if f.endswith(".rc")])
364 except OSError:
371 except OSError:
365 pass
372 pass
366 return rcs
373 return rcs
367
374
368 def system_rcpath():
375 def system_rcpath():
369 path = []
376 path = []
370 # old mod_python does not set sys.argv
377 # old mod_python does not set sys.argv
371 if len(getattr(sys, 'argv', [])) > 0:
378 if len(getattr(sys, 'argv', [])) > 0:
372 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
379 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
373 '/../etc/mercurial'))
380 '/../etc/mercurial'))
374 path.extend(rcfiles('/etc/mercurial'))
381 path.extend(rcfiles('/etc/mercurial'))
375 return path
382 return path
376
383
377 def user_rcpath():
384 def user_rcpath():
378 return [os.path.expanduser('~/.hgrc')]
385 return [os.path.expanduser('~/.hgrc')]
379
386
380 else:
387 else:
381
388
382 _HKEY_LOCAL_MACHINE = 0x80000002L
389 _HKEY_LOCAL_MACHINE = 0x80000002L
383
390
384 def system_rcpath():
391 def system_rcpath():
385 '''return default os-specific hgrc search path'''
392 '''return default os-specific hgrc search path'''
386 rcpath = []
393 rcpath = []
387 filename = util.executable_path()
394 filename = util.executable_path()
388 # Use mercurial.ini found in directory with hg.exe
395 # Use mercurial.ini found in directory with hg.exe
389 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
396 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
390 if os.path.isfile(progrc):
397 if os.path.isfile(progrc):
391 rcpath.append(progrc)
398 rcpath.append(progrc)
392 return rcpath
399 return rcpath
393 # Use hgrc.d found in directory with hg.exe
400 # Use hgrc.d found in directory with hg.exe
394 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
401 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
395 if os.path.isdir(progrcd):
402 if os.path.isdir(progrcd):
396 for f, kind in osutil.listdir(progrcd):
403 for f, kind in osutil.listdir(progrcd):
397 if f.endswith('.rc'):
404 if f.endswith('.rc'):
398 rcpath.append(os.path.join(progrcd, f))
405 rcpath.append(os.path.join(progrcd, f))
399 return rcpath
406 return rcpath
400 # else look for a system rcpath in the registry
407 # else look for a system rcpath in the registry
401 value = util.lookup_reg('SOFTWARE\\Mercurial', None,
408 value = util.lookup_reg('SOFTWARE\\Mercurial', None,
402 _HKEY_LOCAL_MACHINE)
409 _HKEY_LOCAL_MACHINE)
403 if not isinstance(value, str) or not value:
410 if not isinstance(value, str) or not value:
404 return rcpath
411 return rcpath
405 value = value.replace('/', os.sep)
412 value = value.replace('/', os.sep)
406 for p in value.split(os.pathsep):
413 for p in value.split(os.pathsep):
407 if p.lower().endswith('mercurial.ini'):
414 if p.lower().endswith('mercurial.ini'):
408 rcpath.append(p)
415 rcpath.append(p)
409 elif os.path.isdir(p):
416 elif os.path.isdir(p):
410 for f, kind in osutil.listdir(p):
417 for f, kind in osutil.listdir(p):
411 if f.endswith('.rc'):
418 if f.endswith('.rc'):
412 rcpath.append(os.path.join(p, f))
419 rcpath.append(os.path.join(p, f))
413 return rcpath
420 return rcpath
414
421
415 def user_rcpath():
422 def user_rcpath():
416 '''return os-specific hgrc search path to the user dir'''
423 '''return os-specific hgrc search path to the user dir'''
417 home = os.path.expanduser('~')
424 home = os.path.expanduser('~')
418 path = [os.path.join(home, 'mercurial.ini'),
425 path = [os.path.join(home, 'mercurial.ini'),
419 os.path.join(home, '.hgrc')]
426 os.path.join(home, '.hgrc')]
420 userprofile = os.environ.get('USERPROFILE')
427 userprofile = os.environ.get('USERPROFILE')
421 if userprofile:
428 if userprofile:
422 path.append(os.path.join(userprofile, 'mercurial.ini'))
429 path.append(os.path.join(userprofile, 'mercurial.ini'))
423 path.append(os.path.join(userprofile, '.hgrc'))
430 path.append(os.path.join(userprofile, '.hgrc'))
424 return path
431 return path
General Comments 0
You need to be logged in to leave comments. Login now