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