##// END OF EJS Templates
Add way to install MathJax to a particular profile
Kyle Kelley -
Show More
@@ -1,315 +1,328 b''
1 1 #!/usr/bin/python
2 2 """Utility function for installing MathJax javascript library into
3 3 the notebook's 'static' directory, for offline use.
4 4
5 5 Authors:
6 6
7 7 * Min RK
8 8 * Mark Sienkiewicz
9 9 * Matthias Bussonnier
10 10
11 11 To download and install MathJax:
12 12
13 13 From Python:
14 14
15 15 >>> from IPython.external.mathjax import install_mathjax
16 16 >>> install_mathjax()
17 17
18 18 From the command line:
19 19
20 20 $ python -m IPython.external.mathjax
21 21
22 22 To install MathJax from a file you have already downloaded:
23 23
24 24 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
25 25 $ python -m IPython.external.mathjax mathjax-xxx.zip
26 26
27 27 It will not install MathJax if it is already there. Use -r to
28 28 replace the existing copy of MathJax.
29 29
30 30 To find the directory where IPython would like MathJax installed:
31 31
32 32 $ python -m IPython.external.mathjax -d
33 33
34 34 """
35 35
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Copyright (C) 2008-2011 The IPython Development Team
39 39 #
40 40 # Distributed under the terms of the BSD License. The full license is in
41 41 # the file COPYING, distributed as part of this software.
42 42 #-----------------------------------------------------------------------------
43 43
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Imports
47 47 #-----------------------------------------------------------------------------
48 48
49 49 import os
50 50 import shutil
51 51 import sys
52 52 import tarfile
53 53 import urllib2
54 54 import zipfile
55 55
56 56
57 57 from IPython.utils.path import locate_profile
58 58 from IPython.external import argparse
59 59 #-----------------------------------------------------------------------------
60 60 #
61 61 #-----------------------------------------------------------------------------
62 62
63 63 # Where mathjax will be installed.
64 64
65 65 static = os.path.join(locate_profile('default'), 'static')
66 66 default_dest = os.path.join(static, 'mathjax')
67 67
68 68 ##
69 69
70 70 # Test for access to install mathjax.
71 71
72 72 def check_perms(dest, replace=False):
73 73 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
74 74 components = dest.split(os.path.sep)
75 75 subpaths = [ os.path.sep+os.path.sep.join(components[1:i]) for i in range(1,len(components))]
76 76
77 77 existing_path = filter(os.path.exists, subpaths)
78 78 last_writable = existing_path[-1]
79 79 if not os.access(last_writable, os.W_OK):
80 80 raise IOError("Need have write access to %s" % parent)
81 81 not_existing = [ path for path in subpaths if path not in existing_path]
82 82 # subfolder we will create, will obviously be writable
83 83 # should we still considere checking separately that
84 84 # ipython profiles have been created ?
85 85 for folder in not_existing:
86 86 os.mkdir(folder)
87 87
88 88 if os.path.exists(dest):
89 89 if replace:
90 90 if not os.access(dest, os.W_OK):
91 91 raise IOError("Need have write access to %s" % dest)
92 92 print "removing previous MathJax install"
93 93 shutil.rmtree(dest)
94 94 return True
95 95 else:
96 96 print "offline MathJax apparently already installed"
97 97 return False
98 98 else :
99 99 return True
100 100
101 101 ##
102 102
103 103 def extract_tar( fd, dest ) :
104 104 # use 'r|gz' stream mode, because socket file-like objects can't seek:
105 105 tar = tarfile.open(fileobj=fd, mode='r|gz')
106 106
107 107 # we just happen to know that the first entry in the mathjax
108 108 # archive is the directory that the remaining members are in.
109 109 topdir = tar.firstmember.path
110 110
111 111 # extract the archive (contains a single directory) to the static/ directory
112 112 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
113 113 tar.extractall(parent)
114 114
115 115 # it will be mathjax-MathJax-<sha>, rename to just mathjax
116 116 os.rename(os.path.join(parent, topdir), dest)
117 117
118 118 ##
119 119
120 120 def extract_zip( fd, dest ) :
121 121 z = zipfile.ZipFile( fd, 'r' )
122 122
123 123 # we just happen to know that the first entry in the mathjax
124 124 # archive is the directory that the remaining members are in.
125 125 topdir = z.namelist()[0]
126 126
127 127 # extract the archive (contains a single directory) to the static/ directory
128 128 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
129 129 z.extractall( parent )
130 130
131 131 # it will be mathjax-MathJax-<sha>, rename to just mathjax
132 132 d = os.path.join(parent, topdir)
133 133 print d
134 134 os.rename(os.path.join(parent, topdir), dest)
135 135
136 136 ##
137 137
138 138 def install_mathjax(tag='v2.0', dest=default_dest, replace=False, file=None, extractor=extract_tar ):
139 139 """Download and/or install MathJax for offline use.
140 140
141 141 This will install mathjax to the 'static' dir in the IPython notebook
142 142 package, so it will fail if the caller does not have write access
143 143 to that location.
144 144
145 145 MathJax is a ~15MB download, and ~150MB installed.
146 146
147 147 Parameters
148 148 ----------
149 149
150 150 replace : bool [False]
151 151 Whether to remove and replace an existing install.
152 152 dest : str [path to default profile]
153 153 Where to locally install mathjax
154 154 tag : str ['v2.0']
155 155 Which tag to download. Default is 'v2.0', the current stable release,
156 156 but alternatives include 'v1.1a' and 'master'.
157 157 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
158 158 File handle from which to untar/unzip/... mathjax
159 159 extractor : function
160 160 Method tu use to untar/unzip/... `file`
161 161 """
162 162 if not check_perms(dest, replace) :
163 163 return
164 164
165 165 if file is None :
166 166 # download mathjax
167 167 mathjax_url = "https://github.com/mathjax/MathJax/tarball/%s" % tag
168 168 print "Downloading mathjax source from %s" % mathjax_url
169 169 response = urllib2.urlopen(mathjax_url)
170 170 file = response.fp
171 171
172 172 print "Extracting to %s" % dest
173 173 extractor( file, dest )
174 174
175 175 ##
176 176
177 177 def test_func( remove, dest) :
178 178 """See if mathjax appears to be installed correctly"""
179 179 status = 0
180 180 if not os.path.isdir( dest ) :
181 181 print "%s directory not found" % dest
182 182 status = 1
183 183 if not os.path.exists( dest + "/MathJax.js" ) :
184 184 print "MathJax.js not present in %s" % dest
185 185 status = 1
186 186 print "ok"
187 187 if remove and os.path.exists(dest):
188 188 shutil.rmtree( dest )
189 189 return status
190 190
191 191 ##
192 192
193 193 def main() :
194 194 # This main is just simple enough that it is not worth the
195 195 # complexity of argparse
196 196
197 197 # What directory is mathjax in?
198 198 parser = argparse.ArgumentParser(
199 199 description="""Install mathjax from internet or local archive""",
200 200 )
201 201
202 202 parser.add_argument(
203 '-p',
204 '--profile',
205 default='default',
206 help='profile to install MathJax to. Takes precedence over install-dir option')
207
208 parser.add_argument(
203 209 '-i',
204 210 '--install-dir',
205 211 default=default_dest,
206 212 help='installation directory (by default : %s)' % (default_dest))
207 213 parser.add_argument(
208 214 '-d',
209 215 '--dest',
210 216 action='store_true',
211 help='print where is current mathjax would be installed and exit')
217 help='print where current mathjax would be installed and exit')
212 218 parser.add_argument(
213 219 '-r',
214 220 '--replace',
215 221 action='store_true',
216 help='Wether to replace current mathjax if already exist')
222 help='Whether to replace current mathjax if it already exists')
217 223 parser.add_argument(
218 224 '-t',
219 225 '--test',
220 226 action='store_true')
221 227 parser.add_argument('tarball',
222 228 help="the local tar/zip-ball containing mathjax",
223 229 nargs='?',
224 230 metavar='tarball')
225 231
226 232 pargs = parser.parse_args()
227 233
228 dest = pargs.install_dir
234 if(pargs.profile):
235 profile = pargs.profile
236 static = os.path.join(locate_profile(profile), 'static')
237 dest = os.path.join(static, 'mathjax')
238 else:
239 dest = pargs.install_dir
240
241
229 242 if pargs.dest :
230 243 print dest
231 244 return
232 245
233 246 # remove/replace existing mathjax?
234 247 if pargs.replace :
235 248 replace = True
236 249 else :
237 250 replace = False
238 251
239 252 # undocumented test interface
240 253 if pargs.test :
241 254 return test_func( replace, dest)
242 255
243 256 # do it
244 257 if pargs.tarball :
245 258 fname = pargs.tarball
246 259
247 260 # automatically detect zip/tar - could do something based
248 261 # on file content, but really not cost-effective here.
249 262 if fname.endswith('.zip') :
250 263 extractor = extract_zip
251 264 else :
252 265 extractor = extract_tar
253 266 # do it
254 267 install_mathjax(file=open(fname, "r"), replace=replace, extractor=extractor, dest=dest )
255 268 else:
256 269 install_mathjax(replace=replace, dest=dest)
257 270
258 271
259 272 if __name__ == '__main__' :
260 273 sys.exit(main())
261 274
262 275 __all__ = ['install_mathjax', 'main', 'dest']
263 276
264 277 """
265 278 Test notes:
266 279
267 280 IPython uses IPython.testing.iptest as a custom test controller
268 281 (though it is based on nose). It might be possible to fit automatic
269 282 tests of installation into that framework, but it looks awkward to me.
270 283 So, here is a manual procedure for testing this automatic installer.
271 284
272 285 Mark Sienkiewicz, 2012-08-06
273 286 first 8 letters of my last name @ stsci.edu
274 287
275 288 # remove mathjax from the installed ipython instance
276 289 # IOError ok if mathjax was never installed yet.
277 290
278 291 python -m IPython.external.mathjax --test -r
279 292
280 293 # download and install mathjax from command line:
281 294
282 295 python -m IPython.external.mathjax
283 296 python -m IPython.external.mathjax --test -r
284 297
285 298 # download and install from within python
286 299
287 300 python -c "from IPython.external.mathjax import install_mathjax; install_mathjax()"
288 301 python -m IPython.external.mathjax --test -r
289 302
290 303 # view http://www.mathjax.org/download/ in your browser
291 304 # save-as the link for MathJax-2.0 near the bottom of the page.
292 305 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.zip
293 306
294 307 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.zip
295 308 python -m IPython.external.mathjax --test -r
296 309
297 310 # download https://github.com/mathjax/MathJax/tarball/v2.0 in your browser
298 311 # (this is the url used internally by install_mathjax)
299 312 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.tar.gz
300 313
301 314 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
302 315
303 316 python -m IPython.external.mathjax --test
304 317 # note no -r
305 318
306 319 # install it again while it is already there
307 320
308 321 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
309 322 # says "offline MathJax apparently already installed"
310 323
311 324 python -m IPython.external.mathjax ~/mathjax-MathJax-v2.0-20-g07669ac.tar.gz
312 325 python -m IPython.external.mathjax --test
313 326
314 327
315 328 """
General Comments 0
You need to be logged in to leave comments. Login now