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