##// END OF EJS Templates
add get_security_file() function to utils.path...
MinRK -
Show More
@@ -1,478 +1,509
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import warnings
20 import warnings
21 from hashlib import md5
21 from hashlib import md5
22
22
23 import IPython
23 import IPython
24 from IPython.utils.process import system
24 from IPython.utils.process import system
25 from IPython.utils.importstring import import_item
25 from IPython.utils.importstring import import_item
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Code
29 # Code
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 fs_encoding = sys.getfilesystemencoding()
32 fs_encoding = sys.getfilesystemencoding()
33
33
34 def _get_long_path_name(path):
34 def _get_long_path_name(path):
35 """Dummy no-op."""
35 """Dummy no-op."""
36 return path
36 return path
37
37
38 def _writable_dir(path):
38 def _writable_dir(path):
39 """Whether `path` is a directory, to which the user has write access."""
39 """Whether `path` is a directory, to which the user has write access."""
40 return os.path.isdir(path) and os.access(path, os.W_OK)
40 return os.path.isdir(path) and os.access(path, os.W_OK)
41
41
42 if sys.platform == 'win32':
42 if sys.platform == 'win32':
43 def _get_long_path_name(path):
43 def _get_long_path_name(path):
44 """Get a long path name (expand ~) on Windows using ctypes.
44 """Get a long path name (expand ~) on Windows using ctypes.
45
45
46 Examples
46 Examples
47 --------
47 --------
48
48
49 >>> get_long_path_name('c:\\docume~1')
49 >>> get_long_path_name('c:\\docume~1')
50 u'c:\\\\Documents and Settings'
50 u'c:\\\\Documents and Settings'
51
51
52 """
52 """
53 try:
53 try:
54 import ctypes
54 import ctypes
55 except ImportError:
55 except ImportError:
56 raise ImportError('you need to have ctypes installed for this to work')
56 raise ImportError('you need to have ctypes installed for this to work')
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
59 ctypes.c_uint ]
59 ctypes.c_uint ]
60
60
61 buf = ctypes.create_unicode_buffer(260)
61 buf = ctypes.create_unicode_buffer(260)
62 rv = _GetLongPathName(path, buf, 260)
62 rv = _GetLongPathName(path, buf, 260)
63 if rv == 0 or rv > 260:
63 if rv == 0 or rv > 260:
64 return path
64 return path
65 else:
65 else:
66 return buf.value
66 return buf.value
67
67
68
68
69 def get_long_path_name(path):
69 def get_long_path_name(path):
70 """Expand a path into its long form.
70 """Expand a path into its long form.
71
71
72 On Windows this expands any ~ in the paths. On other platforms, it is
72 On Windows this expands any ~ in the paths. On other platforms, it is
73 a null operation.
73 a null operation.
74 """
74 """
75 return _get_long_path_name(path)
75 return _get_long_path_name(path)
76
76
77
77
78 def unquote_filename(name, win32=(sys.platform=='win32')):
78 def unquote_filename(name, win32=(sys.platform=='win32')):
79 """ On Windows, remove leading and trailing quotes from filenames.
79 """ On Windows, remove leading and trailing quotes from filenames.
80 """
80 """
81 if win32:
81 if win32:
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 name = name[1:-1]
83 name = name[1:-1]
84 return name
84 return name
85
85
86
86
87 def get_py_filename(name, force_win32=None):
87 def get_py_filename(name, force_win32=None):
88 """Return a valid python filename in the current directory.
88 """Return a valid python filename in the current directory.
89
89
90 If the given name is not a file, it adds '.py' and searches again.
90 If the given name is not a file, it adds '.py' and searches again.
91 Raises IOError with an informative message if the file isn't found.
91 Raises IOError with an informative message if the file isn't found.
92
92
93 On Windows, apply Windows semantics to the filename. In particular, remove
93 On Windows, apply Windows semantics to the filename. In particular, remove
94 any quoting that has been applied to it. This option can be forced for
94 any quoting that has been applied to it. This option can be forced for
95 testing purposes.
95 testing purposes.
96 """
96 """
97
97
98 name = os.path.expanduser(name)
98 name = os.path.expanduser(name)
99 if force_win32 is None:
99 if force_win32 is None:
100 win32 = (sys.platform == 'win32')
100 win32 = (sys.platform == 'win32')
101 else:
101 else:
102 win32 = force_win32
102 win32 = force_win32
103 name = unquote_filename(name, win32=win32)
103 name = unquote_filename(name, win32=win32)
104 if not os.path.isfile(name) and not name.endswith('.py'):
104 if not os.path.isfile(name) and not name.endswith('.py'):
105 name += '.py'
105 name += '.py'
106 if os.path.isfile(name):
106 if os.path.isfile(name):
107 return name
107 return name
108 else:
108 else:
109 raise IOError,'File `%s` not found.' % name
109 raise IOError,'File `%s` not found.' % name
110
110
111
111
112 def filefind(filename, path_dirs=None):
112 def filefind(filename, path_dirs=None):
113 """Find a file by looking through a sequence of paths.
113 """Find a file by looking through a sequence of paths.
114
114
115 This iterates through a sequence of paths looking for a file and returns
115 This iterates through a sequence of paths looking for a file and returns
116 the full, absolute path of the first occurence of the file. If no set of
116 the full, absolute path of the first occurence of the file. If no set of
117 path dirs is given, the filename is tested as is, after running through
117 path dirs is given, the filename is tested as is, after running through
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
119
119
120 filefind('myfile.txt')
120 filefind('myfile.txt')
121
121
122 will find the file in the current working dir, but::
122 will find the file in the current working dir, but::
123
123
124 filefind('~/myfile.txt')
124 filefind('~/myfile.txt')
125
125
126 Will find the file in the users home directory. This function does not
126 Will find the file in the users home directory. This function does not
127 automatically try any paths, such as the cwd or the user's home directory.
127 automatically try any paths, such as the cwd or the user's home directory.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 filename : str
131 filename : str
132 The filename to look for.
132 The filename to look for.
133 path_dirs : str, None or sequence of str
133 path_dirs : str, None or sequence of str
134 The sequence of paths to look for the file in. If None, the filename
134 The sequence of paths to look for the file in. If None, the filename
135 need to be absolute or be in the cwd. If a string, the string is
135 need to be absolute or be in the cwd. If a string, the string is
136 put into a sequence and the searched. If a sequence, walk through
136 put into a sequence and the searched. If a sequence, walk through
137 each element and join with ``filename``, calling :func:`expandvars`
137 each element and join with ``filename``, calling :func:`expandvars`
138 and :func:`expanduser` before testing for existence.
138 and :func:`expanduser` before testing for existence.
139
139
140 Returns
140 Returns
141 -------
141 -------
142 Raises :exc:`IOError` or returns absolute path to file.
142 Raises :exc:`IOError` or returns absolute path to file.
143 """
143 """
144
144
145 # If paths are quoted, abspath gets confused, strip them...
145 # If paths are quoted, abspath gets confused, strip them...
146 filename = filename.strip('"').strip("'")
146 filename = filename.strip('"').strip("'")
147 # If the input is an absolute path, just check it exists
147 # If the input is an absolute path, just check it exists
148 if os.path.isabs(filename) and os.path.isfile(filename):
148 if os.path.isabs(filename) and os.path.isfile(filename):
149 return filename
149 return filename
150
150
151 if path_dirs is None:
151 if path_dirs is None:
152 path_dirs = ("",)
152 path_dirs = ("",)
153 elif isinstance(path_dirs, basestring):
153 elif isinstance(path_dirs, basestring):
154 path_dirs = (path_dirs,)
154 path_dirs = (path_dirs,)
155
155
156 for path in path_dirs:
156 for path in path_dirs:
157 if path == '.': path = os.getcwdu()
157 if path == '.': path = os.getcwdu()
158 testname = expand_path(os.path.join(path, filename))
158 testname = expand_path(os.path.join(path, filename))
159 if os.path.isfile(testname):
159 if os.path.isfile(testname):
160 return os.path.abspath(testname)
160 return os.path.abspath(testname)
161
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 (filename, path_dirs) )
163 (filename, path_dirs) )
164
164
165
165
166 class HomeDirError(Exception):
166 class HomeDirError(Exception):
167 pass
167 pass
168
168
169
169
170 def get_home_dir():
170 def get_home_dir():
171 """Return the closest possible equivalent to a 'home' directory.
171 """Return the closest possible equivalent to a 'home' directory.
172
172
173 * On POSIX, we try $HOME.
173 * On POSIX, we try $HOME.
174 * On Windows we try:
174 * On Windows we try:
175 - %HOMESHARE%
175 - %HOMESHARE%
176 - %HOMEDRIVE\%HOMEPATH%
176 - %HOMEDRIVE\%HOMEPATH%
177 - %USERPROFILE%
177 - %USERPROFILE%
178 - Registry hack for My Documents
178 - Registry hack for My Documents
179 - %HOME%: rare, but some people with unix-like setups may have defined it
179 - %HOME%: rare, but some people with unix-like setups may have defined it
180 * On Dos C:\
180 * On Dos C:\
181
181
182 Currently only Posix and NT are implemented, a HomeDirError exception is
182 Currently only Posix and NT are implemented, a HomeDirError exception is
183 raised for all other OSes.
183 raised for all other OSes.
184 """
184 """
185
185
186 env = os.environ
186 env = os.environ
187
187
188 # first, check py2exe distribution root directory for _ipython.
188 # first, check py2exe distribution root directory for _ipython.
189 # This overrides all. Normally does not exist.
189 # This overrides all. Normally does not exist.
190
190
191 if hasattr(sys, "frozen"): #Is frozen by py2exe
191 if hasattr(sys, "frozen"): #Is frozen by py2exe
192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
193 root, rest = IPython.__file__.lower().split('library.zip')
193 root, rest = IPython.__file__.lower().split('library.zip')
194 else:
194 else:
195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
196 root=os.path.abspath(root).rstrip('\\')
196 root=os.path.abspath(root).rstrip('\\')
197 if _writable_dir(os.path.join(root, '_ipython')):
197 if _writable_dir(os.path.join(root, '_ipython')):
198 os.environ["IPYKITROOT"] = root
198 os.environ["IPYKITROOT"] = root
199 return py3compat.cast_unicode(root, fs_encoding)
199 return py3compat.cast_unicode(root, fs_encoding)
200
200
201 if os.name == 'posix':
201 if os.name == 'posix':
202 # Linux, Unix, AIX, OS X
202 # Linux, Unix, AIX, OS X
203 try:
203 try:
204 homedir = env['HOME']
204 homedir = env['HOME']
205 except KeyError:
205 except KeyError:
206 # Last-ditch attempt at finding a suitable $HOME, on systems where
206 # Last-ditch attempt at finding a suitable $HOME, on systems where
207 # it may not be defined in the environment but the system shell
207 # it may not be defined in the environment but the system shell
208 # still knows it - reported once as:
208 # still knows it - reported once as:
209 # https://github.com/ipython/ipython/issues/154
209 # https://github.com/ipython/ipython/issues/154
210 from subprocess import Popen, PIPE
210 from subprocess import Popen, PIPE
211 homedir = Popen('echo $HOME', shell=True,
211 homedir = Popen('echo $HOME', shell=True,
212 stdout=PIPE).communicate()[0].strip()
212 stdout=PIPE).communicate()[0].strip()
213 if homedir:
213 if homedir:
214 return py3compat.cast_unicode(homedir, fs_encoding)
214 return py3compat.cast_unicode(homedir, fs_encoding)
215 else:
215 else:
216 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
216 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
217 else:
217 else:
218 return py3compat.cast_unicode(homedir, fs_encoding)
218 return py3compat.cast_unicode(homedir, fs_encoding)
219 elif os.name == 'nt':
219 elif os.name == 'nt':
220 # Now for win9x, XP, Vista, 7?
220 # Now for win9x, XP, Vista, 7?
221 # For some strange reason all of these return 'nt' for os.name.
221 # For some strange reason all of these return 'nt' for os.name.
222 # First look for a network home directory. This will return the UNC
222 # First look for a network home directory. This will return the UNC
223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
224 # is needed when running IPython on cluster where all paths have to
224 # is needed when running IPython on cluster where all paths have to
225 # be UNC.
225 # be UNC.
226 try:
226 try:
227 homedir = env['HOMESHARE']
227 homedir = env['HOMESHARE']
228 except KeyError:
228 except KeyError:
229 pass
229 pass
230 else:
230 else:
231 if _writable_dir(homedir):
231 if _writable_dir(homedir):
232 return py3compat.cast_unicode(homedir, fs_encoding)
232 return py3compat.cast_unicode(homedir, fs_encoding)
233
233
234 # Now look for a local home directory
234 # Now look for a local home directory
235 try:
235 try:
236 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
236 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
237 except KeyError:
237 except KeyError:
238 pass
238 pass
239 else:
239 else:
240 if _writable_dir(homedir):
240 if _writable_dir(homedir):
241 return py3compat.cast_unicode(homedir, fs_encoding)
241 return py3compat.cast_unicode(homedir, fs_encoding)
242
242
243 # Now the users profile directory
243 # Now the users profile directory
244 try:
244 try:
245 homedir = os.path.join(env['USERPROFILE'])
245 homedir = os.path.join(env['USERPROFILE'])
246 except KeyError:
246 except KeyError:
247 pass
247 pass
248 else:
248 else:
249 if _writable_dir(homedir):
249 if _writable_dir(homedir):
250 return py3compat.cast_unicode(homedir, fs_encoding)
250 return py3compat.cast_unicode(homedir, fs_encoding)
251
251
252 # Use the registry to get the 'My Documents' folder.
252 # Use the registry to get the 'My Documents' folder.
253 try:
253 try:
254 import _winreg as wreg
254 import _winreg as wreg
255 key = wreg.OpenKey(
255 key = wreg.OpenKey(
256 wreg.HKEY_CURRENT_USER,
256 wreg.HKEY_CURRENT_USER,
257 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
257 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
258 )
258 )
259 homedir = wreg.QueryValueEx(key,'Personal')[0]
259 homedir = wreg.QueryValueEx(key,'Personal')[0]
260 key.Close()
260 key.Close()
261 except:
261 except:
262 pass
262 pass
263 else:
263 else:
264 if _writable_dir(homedir):
264 if _writable_dir(homedir):
265 return py3compat.cast_unicode(homedir, fs_encoding)
265 return py3compat.cast_unicode(homedir, fs_encoding)
266
266
267 # A user with a lot of unix tools in win32 may have defined $HOME.
267 # A user with a lot of unix tools in win32 may have defined $HOME.
268 # Try this as a last ditch option.
268 # Try this as a last ditch option.
269 try:
269 try:
270 homedir = env['HOME']
270 homedir = env['HOME']
271 except KeyError:
271 except KeyError:
272 pass
272 pass
273 else:
273 else:
274 if _writable_dir(homedir):
274 if _writable_dir(homedir):
275 return py3compat.cast_unicode(homedir, fs_encoding)
275 return py3compat.cast_unicode(homedir, fs_encoding)
276
276
277 # If all else fails, raise HomeDirError
277 # If all else fails, raise HomeDirError
278 raise HomeDirError('No valid home directory could be found')
278 raise HomeDirError('No valid home directory could be found')
279 elif os.name == 'dos':
279 elif os.name == 'dos':
280 # Desperate, may do absurd things in classic MacOS. May work under DOS.
280 # Desperate, may do absurd things in classic MacOS. May work under DOS.
281 return u'C:\\'
281 return u'C:\\'
282 else:
282 else:
283 raise HomeDirError('No valid home directory could be found for your OS')
283 raise HomeDirError('No valid home directory could be found for your OS')
284
284
285 def get_xdg_dir():
285 def get_xdg_dir():
286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
287
287
288 This is only for posix (Linux,Unix,OS X, etc) systems.
288 This is only for posix (Linux,Unix,OS X, etc) systems.
289 """
289 """
290
290
291 env = os.environ
291 env = os.environ
292
292
293 if os.name == 'posix':
293 if os.name == 'posix':
294 # Linux, Unix, AIX, OS X
294 # Linux, Unix, AIX, OS X
295 # use ~/.config if not set OR empty
295 # use ~/.config if not set OR empty
296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
297 if xdg and _writable_dir(xdg):
297 if xdg and _writable_dir(xdg):
298 return py3compat.cast_unicode(xdg, fs_encoding)
298 return py3compat.cast_unicode(xdg, fs_encoding)
299
299
300 return None
300 return None
301
301
302
302
303 def get_ipython_dir():
303 def get_ipython_dir():
304 """Get the IPython directory for this platform and user.
304 """Get the IPython directory for this platform and user.
305
305
306 This uses the logic in `get_home_dir` to find the home directory
306 This uses the logic in `get_home_dir` to find the home directory
307 and then adds .ipython to the end of the path.
307 and then adds .ipython to the end of the path.
308 """
308 """
309
309
310 env = os.environ
310 env = os.environ
311 pjoin = os.path.join
311 pjoin = os.path.join
312
312
313
313
314 ipdir_def = '.ipython'
314 ipdir_def = '.ipython'
315 xdg_def = 'ipython'
315 xdg_def = 'ipython'
316
316
317 home_dir = get_home_dir()
317 home_dir = get_home_dir()
318 xdg_dir = get_xdg_dir()
318 xdg_dir = get_xdg_dir()
319 # import pdb; pdb.set_trace() # dbg
319 # import pdb; pdb.set_trace() # dbg
320 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
320 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
321 if ipdir is None:
321 if ipdir is None:
322 # not set explicitly, use XDG_CONFIG_HOME or HOME
322 # not set explicitly, use XDG_CONFIG_HOME or HOME
323 home_ipdir = pjoin(home_dir, ipdir_def)
323 home_ipdir = pjoin(home_dir, ipdir_def)
324 if xdg_dir:
324 if xdg_dir:
325 # use XDG, as long as the user isn't already
325 # use XDG, as long as the user isn't already
326 # using $HOME/.ipython and *not* XDG/ipython
326 # using $HOME/.ipython and *not* XDG/ipython
327
327
328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
329
329
330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
331 ipdir = xdg_ipdir
331 ipdir = xdg_ipdir
332
332
333 if ipdir is None:
333 if ipdir is None:
334 # not using XDG
334 # not using XDG
335 ipdir = home_ipdir
335 ipdir = home_ipdir
336
336
337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
338
338
339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
340 # ipdir exists, but is not writable
340 # ipdir exists, but is not writable
341 warnings.warn("IPython dir '%s' is not a writable location,"
341 warnings.warn("IPython dir '%s' is not a writable location,"
342 " using a temp directory."%ipdir)
342 " using a temp directory."%ipdir)
343 ipdir = tempfile.mkdtemp()
343 ipdir = tempfile.mkdtemp()
344 elif not os.path.exists(ipdir):
344 elif not os.path.exists(ipdir):
345 parent = ipdir.rsplit(os.path.sep, 1)[0]
345 parent = ipdir.rsplit(os.path.sep, 1)[0]
346 if not _writable_dir(parent):
346 if not _writable_dir(parent):
347 # ipdir does not exist and parent isn't writable
347 # ipdir does not exist and parent isn't writable
348 warnings.warn("IPython parent '%s' is not a writable location,"
348 warnings.warn("IPython parent '%s' is not a writable location,"
349 " using a temp directory."%parent)
349 " using a temp directory."%parent)
350 ipdir = tempfile.mkdtemp()
350 ipdir = tempfile.mkdtemp()
351
351
352 return py3compat.cast_unicode(ipdir, fs_encoding)
352 return py3compat.cast_unicode(ipdir, fs_encoding)
353
353
354
354
355 def get_ipython_package_dir():
355 def get_ipython_package_dir():
356 """Get the base directory where IPython itself is installed."""
356 """Get the base directory where IPython itself is installed."""
357 ipdir = os.path.dirname(IPython.__file__)
357 ipdir = os.path.dirname(IPython.__file__)
358 return py3compat.cast_unicode(ipdir, fs_encoding)
358 return py3compat.cast_unicode(ipdir, fs_encoding)
359
359
360
360
361 def get_ipython_module_path(module_str):
361 def get_ipython_module_path(module_str):
362 """Find the path to an IPython module in this version of IPython.
362 """Find the path to an IPython module in this version of IPython.
363
363
364 This will always find the version of the module that is in this importable
364 This will always find the version of the module that is in this importable
365 IPython package. This will always return the path to the ``.py``
365 IPython package. This will always return the path to the ``.py``
366 version of the module.
366 version of the module.
367 """
367 """
368 if module_str == 'IPython':
368 if module_str == 'IPython':
369 return os.path.join(get_ipython_package_dir(), '__init__.py')
369 return os.path.join(get_ipython_package_dir(), '__init__.py')
370 mod = import_item(module_str)
370 mod = import_item(module_str)
371 the_path = mod.__file__.replace('.pyc', '.py')
371 the_path = mod.__file__.replace('.pyc', '.py')
372 the_path = the_path.replace('.pyo', '.py')
372 the_path = the_path.replace('.pyo', '.py')
373 return py3compat.cast_unicode(the_path, fs_encoding)
373 return py3compat.cast_unicode(the_path, fs_encoding)
374
374
375
375
376 def expand_path(s):
376 def expand_path(s):
377 """Expand $VARS and ~names in a string, like a shell
377 """Expand $VARS and ~names in a string, like a shell
378
378
379 :Examples:
379 :Examples:
380
380
381 In [2]: os.environ['FOO']='test'
381 In [2]: os.environ['FOO']='test'
382
382
383 In [3]: expand_path('variable FOO is $FOO')
383 In [3]: expand_path('variable FOO is $FOO')
384 Out[3]: 'variable FOO is test'
384 Out[3]: 'variable FOO is test'
385 """
385 """
386 # This is a pretty subtle hack. When expand user is given a UNC path
386 # This is a pretty subtle hack. When expand user is given a UNC path
387 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
387 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
388 # the $ to get (\\server\share\%username%). I think it considered $
388 # the $ to get (\\server\share\%username%). I think it considered $
389 # alone an empty var. But, we need the $ to remains there (it indicates
389 # alone an empty var. But, we need the $ to remains there (it indicates
390 # a hidden share).
390 # a hidden share).
391 if os.name=='nt':
391 if os.name=='nt':
392 s = s.replace('$\\', 'IPYTHON_TEMP')
392 s = s.replace('$\\', 'IPYTHON_TEMP')
393 s = os.path.expandvars(os.path.expanduser(s))
393 s = os.path.expandvars(os.path.expanduser(s))
394 if os.name=='nt':
394 if os.name=='nt':
395 s = s.replace('IPYTHON_TEMP', '$\\')
395 s = s.replace('IPYTHON_TEMP', '$\\')
396 return s
396 return s
397
397
398
398
399 def target_outdated(target,deps):
399 def target_outdated(target,deps):
400 """Determine whether a target is out of date.
400 """Determine whether a target is out of date.
401
401
402 target_outdated(target,deps) -> 1/0
402 target_outdated(target,deps) -> 1/0
403
403
404 deps: list of filenames which MUST exist.
404 deps: list of filenames which MUST exist.
405 target: single filename which may or may not exist.
405 target: single filename which may or may not exist.
406
406
407 If target doesn't exist or is older than any file listed in deps, return
407 If target doesn't exist or is older than any file listed in deps, return
408 true, otherwise return false.
408 true, otherwise return false.
409 """
409 """
410 try:
410 try:
411 target_time = os.path.getmtime(target)
411 target_time = os.path.getmtime(target)
412 except os.error:
412 except os.error:
413 return 1
413 return 1
414 for dep in deps:
414 for dep in deps:
415 dep_time = os.path.getmtime(dep)
415 dep_time = os.path.getmtime(dep)
416 if dep_time > target_time:
416 if dep_time > target_time:
417 #print "For target",target,"Dep failed:",dep # dbg
417 #print "For target",target,"Dep failed:",dep # dbg
418 #print "times (dep,tar):",dep_time,target_time # dbg
418 #print "times (dep,tar):",dep_time,target_time # dbg
419 return 1
419 return 1
420 return 0
420 return 0
421
421
422
422
423 def target_update(target,deps,cmd):
423 def target_update(target,deps,cmd):
424 """Update a target with a given command given a list of dependencies.
424 """Update a target with a given command given a list of dependencies.
425
425
426 target_update(target,deps,cmd) -> runs cmd if target is outdated.
426 target_update(target,deps,cmd) -> runs cmd if target is outdated.
427
427
428 This is just a wrapper around target_outdated() which calls the given
428 This is just a wrapper around target_outdated() which calls the given
429 command if target is outdated."""
429 command if target is outdated."""
430
430
431 if target_outdated(target,deps):
431 if target_outdated(target,deps):
432 system(cmd)
432 system(cmd)
433
433
434 def filehash(path):
434 def filehash(path):
435 """Make an MD5 hash of a file, ignoring any differences in line
435 """Make an MD5 hash of a file, ignoring any differences in line
436 ending characters."""
436 ending characters."""
437 with open(path, "rU") as f:
437 with open(path, "rU") as f:
438 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
438 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
439
439
440 # If the config is unmodified from the default, we'll just delete it.
440 # If the config is unmodified from the default, we'll just delete it.
441 # These are consistent for 0.10.x, thankfully. We're not going to worry about
441 # These are consistent for 0.10.x, thankfully. We're not going to worry about
442 # older versions.
442 # older versions.
443 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
443 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
444 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
444 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
445
445
446 def check_for_old_config(ipython_dir=None):
446 def check_for_old_config(ipython_dir=None):
447 """Check for old config files, and present a warning if they exist.
447 """Check for old config files, and present a warning if they exist.
448
448
449 A link to the docs of the new config is included in the message.
449 A link to the docs of the new config is included in the message.
450
450
451 This should mitigate confusion with the transition to the new
451 This should mitigate confusion with the transition to the new
452 config system in 0.11.
452 config system in 0.11.
453 """
453 """
454 if ipython_dir is None:
454 if ipython_dir is None:
455 ipython_dir = get_ipython_dir()
455 ipython_dir = get_ipython_dir()
456
456
457 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
457 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
458 warned = False
458 warned = False
459 for cfg in old_configs:
459 for cfg in old_configs:
460 f = os.path.join(ipython_dir, cfg)
460 f = os.path.join(ipython_dir, cfg)
461 if os.path.exists(f):
461 if os.path.exists(f):
462 if filehash(f) == old_config_md5.get(cfg, ''):
462 if filehash(f) == old_config_md5.get(cfg, ''):
463 os.unlink(f)
463 os.unlink(f)
464 else:
464 else:
465 warnings.warn("Found old IPython config file %r (modified by user)"%f)
465 warnings.warn("Found old IPython config file %r (modified by user)"%f)
466 warned = True
466 warned = True
467
467
468 if warned:
468 if warned:
469 warnings.warn("""
469 warnings.warn("""
470 The IPython configuration system has changed as of 0.11, and these files will
470 The IPython configuration system has changed as of 0.11, and these files will
471 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
471 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
472 of the new config system.
472 of the new config system.
473 To start configuring IPython, do `ipython profile create`, and edit
473 To start configuring IPython, do `ipython profile create`, and edit
474 `ipython_config.py` in <ipython_dir>/profile_default.
474 `ipython_config.py` in <ipython_dir>/profile_default.
475 If you need to leave the old config files in place for an older version of
475 If you need to leave the old config files in place for an older version of
476 IPython and want to suppress this warning message, set
476 IPython and want to suppress this warning message, set
477 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
477 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
478
478
479 def get_security_file(filename, profile='default'):
480 """Return the absolute path of a security file given by filename and profile
481
482 This allows users and developers to find security files without
483 knowledge of the IPython directory structure. The search path
484 will be ['.', profile.security_dir]
485
486 Parameters
487 ----------
488
489 filename : str
490 The file to be found. If it is passed as an absolute path, it will
491 simply be returned.
492 profile : str [default: 'default']
493 The name of the profile to search. Leaving this unspecified
494 The file to be found. If it is passed as an absolute path, fname will
495 simply be returned.
496
497 Returns
498 -------
499 Raises :exc:`IOError` if file not found or returns absolute path to file.
500 """
501 # import here, because profiledir also imports from utils.path
502 from IPython.core.profiledir import ProfileDir
503 try:
504 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
505 except Exception:
506 # will raise ProfileDirError if no such profile
507 raise IOError("Profile %r not found")
508 return filefind(filename, ['.', pd.security_dir])
509
General Comments 0
You need to be logged in to leave comments. Login now