##// END OF EJS Templates
path.sep
Min RK -
Show More
@@ -1,328 +1,328 b''
1 1 # coding: utf-8
2 2 """Utilities for installing Javascript extensions for the notebook"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 9 import os
10 10 import shutil
11 11 import sys
12 12 import tarfile
13 13 import zipfile
14 14 from os.path import basename, join as pjoin
15 15
16 16 # Deferred imports
17 17 try:
18 18 from urllib.parse import urlparse # Py3
19 19 from urllib.request import urlretrieve
20 20 except ImportError:
21 21 from urlparse import urlparse
22 22 from urllib import urlretrieve
23 23
24 24 from IPython.utils.path import get_ipython_dir, ensure_dir_exists
25 25 from IPython.utils.py3compat import string_types, cast_unicode_py2
26 26 from IPython.utils.tempdir import TemporaryDirectory
27 27
28 28 class ArgumentConflict(ValueError):
29 29 pass
30 30
31 31 # Packagers: modify the next block if you store system-installed nbextensions elsewhere (unlikely)
32 32 SYSTEM_NBEXTENSIONS_DIRS = []
33 33
34 34 if os.name == 'nt':
35 35 programdata = os.environ.get('PROGRAMDATA', None)
36 36 if programdata: # PROGRAMDATA is not defined by default on XP.
37 37 SYSTEM_NBEXTENSIONS_DIRS = [pjoin(programdata, 'jupyter', 'nbextensions')]
38 38 prefixes = []
39 39 else:
40 prefixes = ['/usr/local', '/usr']
40 prefixes = [os.path.sep + pjoin('usr', 'local'), os.path.sep + 'usr']
41 41
42 42 # add sys.prefix at the front
43 43 if sys.prefix not in prefixes:
44 44 prefixes.insert(0, sys.prefix)
45 45
46 46 for prefix in prefixes:
47 nbext = os.path.join(prefix, 'share', 'jupyter', 'nbextensions')
47 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
48 48 if nbext not in SYSTEM_NBEXTENSIONS_DIRS:
49 49 SYSTEM_NBEXTENSIONS_DIRS.append(nbext)
50 50
51 51 if os.name == 'nt':
52 52 # PROGRAMDATA
53 53 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-1]
54 54 else:
55 55 # /usr/local
56 56 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-2]
57 57
58 58
59 59 def _should_copy(src, dest, verbose=1):
60 60 """should a file be copied?"""
61 61 if not os.path.exists(dest):
62 62 return True
63 63 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
64 64 if verbose >= 2:
65 65 print("%s is out of date" % dest)
66 66 return True
67 67 if verbose >= 2:
68 68 print("%s is up to date" % dest)
69 69 return False
70 70
71 71
72 72 def _maybe_copy(src, dest, verbose=1):
73 73 """copy a file if it needs updating"""
74 74 if _should_copy(src, dest, verbose):
75 75 if verbose >= 1:
76 76 print("copying %s -> %s" % (src, dest))
77 77 shutil.copy2(src, dest)
78 78
79 79
80 80 def _safe_is_tarfile(path):
81 81 """safe version of is_tarfile, return False on IOError"""
82 82 try:
83 83 return tarfile.is_tarfile(path)
84 84 except IOError:
85 85 return False
86 86
87 87
88 88 def check_nbextension(files, nbextensions_dir=None):
89 89 """Check whether nbextension files have been installed
90 90
91 91 files should be a list of relative paths within nbextensions.
92 92
93 93 Returns True if all files are found, False if any are missing.
94 94 """
95 95 if nbextensions_dir:
96 96 nbext = nbextensions_dir
97 97 else:
98 98 nbext = pjoin(get_ipython_dir(), u'nbextensions')
99 99 # make sure nbextensions dir exists
100 100 if not os.path.exists(nbext):
101 101 return False
102 102
103 103 if isinstance(files, string_types):
104 104 # one file given, turn it into a list
105 105 files = [files]
106 106
107 107 return all(os.path.exists(pjoin(nbext, f)) for f in files)
108 108
109 109
110 110 def install_nbextension(files, overwrite=False, symlink=False, user=False, prefix=None, nbextensions_dir=None, verbose=1):
111 111 """Install a Javascript extension for the notebook
112 112
113 113 Stages files and/or directories into the nbextensions directory.
114 114 By default, this compares modification time, and only stages files that need updating.
115 115 If `overwrite` is specified, matching files are purged before proceeding.
116 116
117 117 Parameters
118 118 ----------
119 119
120 120 files : list(paths or URLs)
121 121 One or more paths or URLs to existing files directories to install.
122 122 These will be installed with their base name, so '/path/to/foo'
123 123 will install to 'nbextensions/foo'.
124 124 Archives (zip or tarballs) will be extracted into the nbextensions directory.
125 125 overwrite : bool [default: False]
126 126 If True, always install the files, regardless of what may already be installed.
127 127 symlink : bool [default: False]
128 128 If True, create a symlink in nbextensions, rather than copying files.
129 129 Not allowed with URLs or archives. Windows support for symlinks requires
130 130 Vista or above, Python 3, and a permission bit which only admin users
131 131 have by default, so don't rely on it.
132 132 user : bool [default: False]
133 133 Whether to install to the user's .ipython/nbextensions directory.
134 134 Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
135 135 prefix : str [optional]
136 136 Specify install prefix, if it should differ from default (e.g. /usr/local).
137 137 Will install to prefix/share/jupyter/nbextensions
138 138 nbextensions_dir : str [optional]
139 139 Specify absolute path of nbextensions directory explicitly.
140 140 verbose : int [default: 1]
141 141 Set verbosity level. The default is 1, where file actions are printed.
142 142 set verbose=2 for more output, or verbose=0 for silence.
143 143 """
144 144 if sum(map(bool, [user, prefix, nbextensions_dir])) > 1:
145 145 raise ArgumentConflict("Cannot specify more than one of user, prefix, or nbextensions_dir.")
146 146 if user:
147 147 nbext = pjoin(get_ipython_dir(), u'nbextensions')
148 148 else:
149 149 if prefix:
150 150 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
151 151 elif nbextensions_dir:
152 152 nbext = nbextensions_dir
153 153 else:
154 154 nbext = SYSTEM_NBEXTENSIONS_INSTALL_DIR
155 155 # make sure nbextensions dir exists
156 156 ensure_dir_exists(nbext)
157 157
158 158 if isinstance(files, string_types):
159 159 # one file given, turn it into a list
160 160 files = [files]
161 161
162 162 for path in map(cast_unicode_py2, files):
163 163
164 164 if path.startswith(('https://', 'http://')):
165 165 if symlink:
166 166 raise ValueError("Cannot symlink from URLs")
167 167 # Given a URL, download it
168 168 with TemporaryDirectory() as td:
169 169 filename = urlparse(path).path.split('/')[-1]
170 170 local_path = os.path.join(td, filename)
171 171 if verbose >= 1:
172 172 print("downloading %s to %s" % (path, local_path))
173 173 urlretrieve(path, local_path)
174 174 # now install from the local copy
175 175 install_nbextension(local_path, overwrite=overwrite, symlink=symlink, nbextensions_dir=nbext, verbose=verbose)
176 176 continue
177 177
178 178 # handle archives
179 179 archive = None
180 180 if path.endswith('.zip'):
181 181 archive = zipfile.ZipFile(path)
182 182 elif _safe_is_tarfile(path):
183 183 archive = tarfile.open(path)
184 184
185 185 if archive:
186 186 if symlink:
187 187 raise ValueError("Cannot symlink from archives")
188 188 if verbose >= 1:
189 189 print("extracting %s to %s" % (path, nbext))
190 190 archive.extractall(nbext)
191 191 archive.close()
192 192 continue
193 193
194 194 dest = pjoin(nbext, basename(path))
195 195 if overwrite and os.path.exists(dest):
196 196 if verbose >= 1:
197 197 print("removing %s" % dest)
198 198 if os.path.isdir(dest) and not os.path.islink(dest):
199 199 shutil.rmtree(dest)
200 200 else:
201 201 os.remove(dest)
202 202
203 203 if symlink:
204 204 path = os.path.abspath(path)
205 205 if not os.path.exists(dest):
206 206 if verbose >= 1:
207 207 print("symlink %s -> %s" % (dest, path))
208 208 os.symlink(path, dest)
209 209 continue
210 210
211 211 if os.path.isdir(path):
212 212 strip_prefix_len = len(path) - len(basename(path))
213 213 for parent, dirs, files in os.walk(path):
214 214 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
215 215 if not os.path.exists(dest_dir):
216 216 if verbose >= 2:
217 217 print("making directory %s" % dest_dir)
218 218 os.makedirs(dest_dir)
219 219 for file in files:
220 220 src = pjoin(parent, file)
221 221 # print("%r, %r" % (dest_dir, file))
222 222 dest = pjoin(dest_dir, file)
223 223 _maybe_copy(src, dest, verbose)
224 224 else:
225 225 src = path
226 226 _maybe_copy(src, dest, verbose)
227 227
228 228 #----------------------------------------------------------------------
229 229 # install nbextension app
230 230 #----------------------------------------------------------------------
231 231
232 232 from IPython.utils.traitlets import Bool, Enum, Unicode, TraitError
233 233 from IPython.core.application import BaseIPythonApplication
234 234
235 235 flags = {
236 236 "overwrite" : ({
237 237 "NBExtensionApp" : {
238 238 "overwrite" : True,
239 239 }}, "Force overwrite of existing files"
240 240 ),
241 241 "debug" : ({
242 242 "NBExtensionApp" : {
243 243 "verbose" : 2,
244 244 }}, "Extra output"
245 245 ),
246 246 "quiet" : ({
247 247 "NBExtensionApp" : {
248 248 "verbose" : 0,
249 249 }}, "Minimal output"
250 250 ),
251 251 "symlink" : ({
252 252 "NBExtensionApp" : {
253 253 "symlink" : True,
254 254 }}, "Create symlinks instead of copying files"
255 255 ),
256 256 "user" : ({
257 257 "NBExtensionApp" : {
258 258 "user" : True,
259 259 }}, "Install to the user's IPython directory"
260 260 ),
261 261 }
262 262 flags['s'] = flags['symlink']
263 263
264 264 aliases = {
265 265 "ipython-dir" : "NBExtensionApp.ipython_dir",
266 266 "prefix" : "NBExtensionApp.prefix",
267 267 "nbextensions" : "NBExtensionApp.nbextensions_dir",
268 268 }
269 269
270 270 class NBExtensionApp(BaseIPythonApplication):
271 271 """Entry point for installing notebook extensions"""
272 272
273 273 description = """Install IPython notebook extensions
274 274
275 275 Usage
276 276
277 277 ipython install-nbextension file [more files, folders, archives or urls]
278 278
279 279 This copies files and/or folders into the IPython nbextensions directory.
280 280 If a URL is given, it will be downloaded.
281 281 If an archive is given, it will be extracted into nbextensions.
282 282 If the requested files are already up to date, no action is taken
283 283 unless --overwrite is specified.
284 284 """
285 285
286 286 examples = """
287 287 ipython install-nbextension /path/to/d3.js /path/to/myextension
288 288 """
289 289 aliases = aliases
290 290 flags = flags
291 291
292 292 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
293 293 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
294 294 user = Bool(False, config=True, help="Whether to do a user install")
295 295 prefix = Unicode('', config=True, help="Installation prefix")
296 296 nbextensions_dir = Unicode('', config=True, help="Full path to nbextensions dir (probably use prefix or user)")
297 297 verbose = Enum((0,1,2), default_value=1, config=True,
298 298 help="Verbosity level"
299 299 )
300 300
301 301 def install_extensions(self):
302 302 install_nbextension(self.extra_args,
303 303 overwrite=self.overwrite,
304 304 symlink=self.symlink,
305 305 verbose=self.verbose,
306 306 user=self.user,
307 307 prefix=self.prefix,
308 308 nbextensions_dir=self.nbextensions_dir,
309 309 )
310 310
311 311 def start(self):
312 312 if not self.extra_args:
313 313 for nbext in [pjoin(self.ipython_dir, u'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS:
314 314 if os.path.exists(nbext):
315 315 print("Notebook extensions in %s:" % nbext)
316 316 for ext in os.listdir(nbext):
317 317 print(u" %s" % ext)
318 318 else:
319 319 try:
320 320 self.install_extensions()
321 321 except ArgumentConflict as e:
322 322 print(str(e), file=sys.stderr)
323 323 self.exit(1)
324 324
325 325
326 326 if __name__ == '__main__':
327 327 NBExtensionApp.launch_instance()
328 328 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now