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