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