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