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