##// END OF EJS Templates
create static/custom in skeleton profiles
MinRK -
Show More
@@ -1,252 +1,273 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An object for managing IPython profile directories.
3 An object for managing IPython profile directories.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25 import shutil
25 import shutil
26 import errno
26 import errno
27
27
28 from IPython.config.configurable import LoggingConfigurable
28 from IPython.config.configurable import LoggingConfigurable
29 from IPython.utils.path import get_ipython_package_dir, expand_path
29 from IPython.utils.path import get_ipython_package_dir, expand_path
30 from IPython.utils.traitlets import Unicode, Bool
30 from IPython.utils.traitlets import Unicode, Bool
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Classes and functions
33 # Classes and functions
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Module errors
38 # Module errors
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 class ProfileDirError(Exception):
41 class ProfileDirError(Exception):
42 pass
42 pass
43
43
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Class for managing profile directories
46 # Class for managing profile directories
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 class ProfileDir(LoggingConfigurable):
49 class ProfileDir(LoggingConfigurable):
50 """An object to manage the profile directory and its resources.
50 """An object to manage the profile directory and its resources.
51
51
52 The profile directory is used by all IPython applications, to manage
52 The profile directory is used by all IPython applications, to manage
53 configuration, logging and security.
53 configuration, logging and security.
54
54
55 This object knows how to find, create and manage these directories. This
55 This object knows how to find, create and manage these directories. This
56 should be used by any code that wants to handle profiles.
56 should be used by any code that wants to handle profiles.
57 """
57 """
58
58
59 security_dir_name = Unicode('security')
59 security_dir_name = Unicode('security')
60 log_dir_name = Unicode('log')
60 log_dir_name = Unicode('log')
61 startup_dir_name = Unicode('startup')
61 startup_dir_name = Unicode('startup')
62 pid_dir_name = Unicode('pid')
62 pid_dir_name = Unicode('pid')
63 static_dir_name = Unicode('static')
63 security_dir = Unicode(u'')
64 security_dir = Unicode(u'')
64 log_dir = Unicode(u'')
65 log_dir = Unicode(u'')
65 startup_dir = Unicode(u'')
66 startup_dir = Unicode(u'')
66 pid_dir = Unicode(u'')
67 pid_dir = Unicode(u'')
68 static_dir = Unicode(u'')
67
69
68 location = Unicode(u'', config=True,
70 location = Unicode(u'', config=True,
69 help="""Set the profile location directly. This overrides the logic used by the
71 help="""Set the profile location directly. This overrides the logic used by the
70 `profile` option.""",
72 `profile` option.""",
71 )
73 )
72
74
73 _location_isset = Bool(False) # flag for detecting multiply set location
75 _location_isset = Bool(False) # flag for detecting multiply set location
74
76
75 def _location_changed(self, name, old, new):
77 def _location_changed(self, name, old, new):
76 if self._location_isset:
78 if self._location_isset:
77 raise RuntimeError("Cannot set profile location more than once.")
79 raise RuntimeError("Cannot set profile location more than once.")
78 self._location_isset = True
80 self._location_isset = True
79 if not os.path.isdir(new):
81 if not os.path.isdir(new):
80 os.makedirs(new)
82 os.makedirs(new)
81
83
82 # ensure config files exist:
84 # ensure config files exist:
83 self.security_dir = os.path.join(new, self.security_dir_name)
85 self.security_dir = os.path.join(new, self.security_dir_name)
84 self.log_dir = os.path.join(new, self.log_dir_name)
86 self.log_dir = os.path.join(new, self.log_dir_name)
85 self.startup_dir = os.path.join(new, self.startup_dir_name)
87 self.startup_dir = os.path.join(new, self.startup_dir_name)
86 self.pid_dir = os.path.join(new, self.pid_dir_name)
88 self.pid_dir = os.path.join(new, self.pid_dir_name)
89 self.static_dir = os.path.join(new, self.static_dir_name)
87 self.check_dirs()
90 self.check_dirs()
88
91
89 def _log_dir_changed(self, name, old, new):
92 def _log_dir_changed(self, name, old, new):
90 self.check_log_dir()
93 self.check_log_dir()
91
94
92 def _mkdir(self, path, mode=None):
95 def _mkdir(self, path, mode=None):
93 """ensure a directory exists at a given path
96 """ensure a directory exists at a given path
94
97
95 This is a version of os.mkdir, with the following differences:
98 This is a version of os.mkdir, with the following differences:
96
99
97 - returns True if it created the directory, False otherwise
100 - returns True if it created the directory, False otherwise
98 - ignores EEXIST, protecting against race conditions where
101 - ignores EEXIST, protecting against race conditions where
99 the dir may have been created in between the check and
102 the dir may have been created in between the check and
100 the creation
103 the creation
101 - sets permissions if requested and the dir already exists
104 - sets permissions if requested and the dir already exists
102 """
105 """
103 if os.path.exists(path):
106 if os.path.exists(path):
104 if mode and os.stat(path).st_mode != mode:
107 if mode and os.stat(path).st_mode != mode:
105 try:
108 try:
106 os.chmod(path, mode)
109 os.chmod(path, mode)
107 except OSError:
110 except OSError:
108 self.log.warn(
111 self.log.warn(
109 "Could not set permissions on %s",
112 "Could not set permissions on %s",
110 path
113 path
111 )
114 )
112 return False
115 return False
113 try:
116 try:
114 if mode:
117 if mode:
115 os.mkdir(path, mode)
118 os.mkdir(path, mode)
116 else:
119 else:
117 os.mkdir(path)
120 os.mkdir(path)
118 except OSError as e:
121 except OSError as e:
119 if e.errno == errno.EEXIST:
122 if e.errno == errno.EEXIST:
120 return False
123 return False
121 else:
124 else:
122 raise
125 raise
123
126
124 return True
127 return True
125
128
126 def check_log_dir(self):
129 def check_log_dir(self):
127 self._mkdir(self.log_dir)
130 self._mkdir(self.log_dir)
128
131
129 def _startup_dir_changed(self, name, old, new):
132 def _startup_dir_changed(self, name, old, new):
130 self.check_startup_dir()
133 self.check_startup_dir()
131
134
132 def check_startup_dir(self):
135 def check_startup_dir(self):
133 self._mkdir(self.startup_dir)
136 self._mkdir(self.startup_dir)
134
137
135 readme = os.path.join(self.startup_dir, 'README')
138 readme = os.path.join(self.startup_dir, 'README')
136 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
139 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
137
140
138 if not os.path.exists(src):
141 if not os.path.exists(src):
139 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
142 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
140
143
141 if os.path.exists(src) and not os.path.exists(readme):
144 if os.path.exists(src) and not os.path.exists(readme):
142 shutil.copy(src, readme)
145 shutil.copy(src, readme)
143
146
144 def _security_dir_changed(self, name, old, new):
147 def _security_dir_changed(self, name, old, new):
145 self.check_security_dir()
148 self.check_security_dir()
146
149
147 def check_security_dir(self):
150 def check_security_dir(self):
148 self._mkdir(self.security_dir, 0o40700)
151 self._mkdir(self.security_dir, 0o40700)
149
152
150 def _pid_dir_changed(self, name, old, new):
153 def _pid_dir_changed(self, name, old, new):
151 self.check_pid_dir()
154 self.check_pid_dir()
152
155
153 def check_pid_dir(self):
156 def check_pid_dir(self):
154 self._mkdir(self.pid_dir, 0o40700)
157 self._mkdir(self.pid_dir, 0o40700)
155
158
159 def _static_dir_changed(self, name, old, new):
160 self.check_startup_dir()
161
162 def check_static_dir(self):
163 self._mkdir(self.static_dir)
164 custom = os.path.join(self.static_dir, 'custom')
165 self._mkdir(custom)
166 from IPython.html import DEFAULT_STATIC_FILES_PATH
167 for fname in ('custom.js', 'custom.css'):
168 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
169 dest = os.path.join(custom, fname)
170 if not os.path.exists(src):
171 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
172 continue
173 if not os.path.exists(dest):
174 shutil.copy(src, dest)
175
156 def check_dirs(self):
176 def check_dirs(self):
157 self.check_security_dir()
177 self.check_security_dir()
158 self.check_log_dir()
178 self.check_log_dir()
159 self.check_pid_dir()
179 self.check_pid_dir()
160 self.check_startup_dir()
180 self.check_startup_dir()
181 self.check_static_dir()
161
182
162 def copy_config_file(self, config_file, path=None, overwrite=False):
183 def copy_config_file(self, config_file, path=None, overwrite=False):
163 """Copy a default config file into the active profile directory.
184 """Copy a default config file into the active profile directory.
164
185
165 Default configuration files are kept in :mod:`IPython.config.default`.
186 Default configuration files are kept in :mod:`IPython.config.default`.
166 This function moves these from that location to the working profile
187 This function moves these from that location to the working profile
167 directory.
188 directory.
168 """
189 """
169 dst = os.path.join(self.location, config_file)
190 dst = os.path.join(self.location, config_file)
170 if os.path.isfile(dst) and not overwrite:
191 if os.path.isfile(dst) and not overwrite:
171 return False
192 return False
172 if path is None:
193 if path is None:
173 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
194 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
174 src = os.path.join(path, config_file)
195 src = os.path.join(path, config_file)
175 shutil.copy(src, dst)
196 shutil.copy(src, dst)
176 return True
197 return True
177
198
178 @classmethod
199 @classmethod
179 def create_profile_dir(cls, profile_dir, config=None):
200 def create_profile_dir(cls, profile_dir, config=None):
180 """Create a new profile directory given a full path.
201 """Create a new profile directory given a full path.
181
202
182 Parameters
203 Parameters
183 ----------
204 ----------
184 profile_dir : str
205 profile_dir : str
185 The full path to the profile directory. If it does exist, it will
206 The full path to the profile directory. If it does exist, it will
186 be used. If not, it will be created.
207 be used. If not, it will be created.
187 """
208 """
188 return cls(location=profile_dir, config=config)
209 return cls(location=profile_dir, config=config)
189
210
190 @classmethod
211 @classmethod
191 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
212 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
192 """Create a profile dir by profile name and path.
213 """Create a profile dir by profile name and path.
193
214
194 Parameters
215 Parameters
195 ----------
216 ----------
196 path : unicode
217 path : unicode
197 The path (directory) to put the profile directory in.
218 The path (directory) to put the profile directory in.
198 name : unicode
219 name : unicode
199 The name of the profile. The name of the profile directory will
220 The name of the profile. The name of the profile directory will
200 be "profile_<profile>".
221 be "profile_<profile>".
201 """
222 """
202 if not os.path.isdir(path):
223 if not os.path.isdir(path):
203 raise ProfileDirError('Directory not found: %s' % path)
224 raise ProfileDirError('Directory not found: %s' % path)
204 profile_dir = os.path.join(path, u'profile_' + name)
225 profile_dir = os.path.join(path, u'profile_' + name)
205 return cls(location=profile_dir, config=config)
226 return cls(location=profile_dir, config=config)
206
227
207 @classmethod
228 @classmethod
208 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
229 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
209 """Find an existing profile dir by profile name, return its ProfileDir.
230 """Find an existing profile dir by profile name, return its ProfileDir.
210
231
211 This searches through a sequence of paths for a profile dir. If it
232 This searches through a sequence of paths for a profile dir. If it
212 is not found, a :class:`ProfileDirError` exception will be raised.
233 is not found, a :class:`ProfileDirError` exception will be raised.
213
234
214 The search path algorithm is:
235 The search path algorithm is:
215 1. ``os.getcwdu()``
236 1. ``os.getcwdu()``
216 2. ``ipython_dir``
237 2. ``ipython_dir``
217
238
218 Parameters
239 Parameters
219 ----------
240 ----------
220 ipython_dir : unicode or str
241 ipython_dir : unicode or str
221 The IPython directory to use.
242 The IPython directory to use.
222 name : unicode or str
243 name : unicode or str
223 The name of the profile. The name of the profile directory
244 The name of the profile. The name of the profile directory
224 will be "profile_<profile>".
245 will be "profile_<profile>".
225 """
246 """
226 dirname = u'profile_' + name
247 dirname = u'profile_' + name
227 paths = [os.getcwdu(), ipython_dir]
248 paths = [os.getcwdu(), ipython_dir]
228 for p in paths:
249 for p in paths:
229 profile_dir = os.path.join(p, dirname)
250 profile_dir = os.path.join(p, dirname)
230 if os.path.isdir(profile_dir):
251 if os.path.isdir(profile_dir):
231 return cls(location=profile_dir, config=config)
252 return cls(location=profile_dir, config=config)
232 else:
253 else:
233 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
254 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
234
255
235 @classmethod
256 @classmethod
236 def find_profile_dir(cls, profile_dir, config=None):
257 def find_profile_dir(cls, profile_dir, config=None):
237 """Find/create a profile dir and return its ProfileDir.
258 """Find/create a profile dir and return its ProfileDir.
238
259
239 This will create the profile directory if it doesn't exist.
260 This will create the profile directory if it doesn't exist.
240
261
241 Parameters
262 Parameters
242 ----------
263 ----------
243 profile_dir : unicode or str
264 profile_dir : unicode or str
244 The path of the profile directory. This is expanded using
265 The path of the profile directory. This is expanded using
245 :func:`IPython.utils.genutils.expand_path`.
266 :func:`IPython.utils.genutils.expand_path`.
246 """
267 """
247 profile_dir = expand_path(profile_dir)
268 profile_dir = expand_path(profile_dir)
248 if not os.path.isdir(profile_dir):
269 if not os.path.isdir(profile_dir):
249 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
270 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
250 return cls(location=profile_dir, config=config)
271 return cls(location=profile_dir, config=config)
251
272
252
273
General Comments 0
You need to be logged in to leave comments. Login now