77import shutil
88import subprocess
99import tarfile
10+ import tempfile
1011import time
1112import urllib .request
1213import warnings
@@ -52,7 +53,7 @@ def get_libc():
5253 libc = platform .libc_ver ()[0 ].lower ()
5354 return libc_aliases .get (libc , libc )
5455
55- def compatible_julia_versions (compat = None , stable = True , kind = None ):
56+ def compatible_julia_versions (compat = None ):
5657 os = get_os ()
5758 arch = get_arch ()
5859 libc = get_libc ()
@@ -62,12 +63,12 @@ def compatible_julia_versions(compat=None, stable=True, kind=None):
6263 ans = {}
6364 for (k , v ) in all_julia_versions ().items ():
6465 v = v .copy ()
65- if stable is not None and v ['stable' ] != stable :
66+ if not v ['stable' ]:
6667 continue
6768 files = []
6869 for f in v ['files' ]:
6970 assert f ['version' ] == k
70- if kind is not None and f ['kind' ] != kind :
71+ if not any ( f ['url' ]. endswith ( ext ) for ext in julia_installers ) :
7172 continue
7273 if f ['os' ] != os :
7374 continue
@@ -92,27 +93,34 @@ def compatible_julia_versions(compat=None, stable=True, kind=None):
9293 raise Exception (f'multiple matching triplets { sorted (triplets )} - this is a bug, please report' )
9394 return ans
9495
95- def install_julia (vers , prefix ):
96+ def best_julia_version (compat = None ):
97+ vers = compatible_julia_versions (compat )
9698 if not vers :
9799 raise Exception ('no compatible Julia version found' )
98- for v in sorted (vers .keys (), key = Version , reverse = True ):
99- for f in vers [v ]['files' ]:
100- url = f ['url' ]
101- if url .endswith ('.tar.gz' ):
102- installer = install_julia_tar_gz
103- elif url .endswith ('.zip' ):
104- installer = install_julia_zip
105- elif url .endswith ('.dmg' ):
106- installer = install_julia_dmg
107- else :
108- continue
109- buf = download_julia (f )
110- prefix2 = prefix .format (version = v )
111- print (f'Installing Julia to { prefix2 } ' )
112- if os .path .exists (prefix2 ):
113- shutil .rmtree (prefix2 )
114- installer (f , buf , prefix2 )
115- return
100+ v = sorted (vers .keys (), key = Version , reverse = True )[0 ]
101+ return v , vers [v ]
102+
103+ def install_julia (ver , prefix ):
104+ for f in ver ['files' ]:
105+ url = f ['url' ]
106+ # find a suitable installer
107+ installer = None
108+ for ext in julia_installers :
109+ if url .endswith (ext ):
110+ installer = julia_installers [ext ]
111+ break
112+ if installer is None :
113+ continue
114+ # download julia
115+ buf = download_julia (f )
116+ # include the version in the prefix
117+ print (f'Installing Julia to { prefix } ' )
118+ if os .path .exists (prefix ):
119+ shutil .rmtree (prefix )
120+ if os .path .dirname (prefix ):
121+ os .makedirs (os .path .dirname (prefix ))
122+ installer (f , buf , prefix )
123+ return
116124 raise Exception ('no installable Julia version found' )
117125
118126def download_julia (f ):
@@ -130,7 +138,7 @@ def download_julia(f):
130138 break
131139 buf .write (data )
132140 if time .time () > t :
133- print (f' downloaded { buf .tell ()/ (1 << 20 ):.3f } MB of { size / (1 << 20 ):.3f } MB' )
141+ print (f' downloaded { buf .tell ()/ (1 << 20 ):.1f } MB of { size / (1 << 20 ):.1f } MB' )
134142 t = time .time () + freq
135143 print (' download complete' )
136144 print (f'Verifying download' )
@@ -144,55 +152,50 @@ def download_julia(f):
144152 return buf
145153
146154def install_julia_zip (f , buf , prefix ):
147- os .makedirs (prefix )
148- with zipfile .ZipFile (buf ) as zf :
149- zf .extractall (prefix )
150- fns = os .listdir (prefix )
151- if 'bin' not in fns :
152- if len (fns ) != 1 :
153- raise Exception ('expecting one subdirectory' )
154- top = fns [0 ]
155- fns = os .listdir (os .path .join (prefix , top ))
156- if 'bin' not in fns :
157- raise Exception ('expecting a bin directory' )
158- for fn in fns :
159- os .rename (os .path .join (prefix , top , fn ), os .path .join (prefix , fn ))
160- os .rmdir (os .path .join (prefix , top ))
155+ with tempfile .TemporaryDirectory () as tmpdir :
156+ # extract all files
157+ with zipfile .ZipFile (buf ) as zf :
158+ zf .extractall (tmpdir )
159+ # copy stuff out
160+ srcdirs = [d for d in os .listdir (tmpdir ) if d .startswith ('julia' )]
161+ if len (srcdirs ) != 1 :
162+ raise Exception ('expecting one julia* directory' )
163+ shutil .copytree (os .path .join (tmpdir , srcdirs [0 ]), prefix , symlinks = True )
161164
162165def install_julia_tar_gz (f , buf , prefix ):
163- os .makedirs (prefix )
164- with gzip .GzipFile (fileobj = buf ) as gf :
165- with tarfile .TarFile (fileobj = gf ) as tf :
166- tf .extractall (prefix )
167- fns = os .listdir (prefix )
168- if 'bin' not in fns :
169- if len (fns ) != 1 :
170- raise Exception ('expecting one subdirectory' )
171- top = fns [0 ]
172- fns = os .listdir (os .path .join (prefix , top ))
173- if 'bin' not in fns :
174- raise Exception ('expecting a bin directory' )
175- for fn in fns :
176- os .rename (os .path .join (prefix , top , fn ), os .path .join (prefix , fn ))
177- os .rmdir (os .path .join (prefix , top ))
166+ with tempfile .TemporaryDirectory () as tmpdir :
167+ # extract all files
168+ with gzip .GzipFile (fileobj = buf ) as gf :
169+ with tarfile .TarFile (fileobj = gf ) as tf :
170+ tf .extractall (tmpdir )
171+ # copy stuff out
172+ srcdirs = [d for d in os .listdir (tmpdir ) if d .startswith ('julia' )]
173+ if len (srcdirs ) != 1 :
174+ raise Exception ('expecting one julia* directory' )
175+ shutil .copytree (os .path .join (tmpdir , srcdirs [0 ]), prefix , symlinks = True )
178176
179177def install_julia_dmg (f , buf , prefix ):
180- tmpdir = prefix + '.tmp'
181- os .makedirs (tmpdir )
182- # write the dmg file out
183- dmg = os .path .join (tmpdir , 'dmg' )
184- with open (dmg , 'wb' ) as f :
185- f .write (buf .read ())
186- # mount it
187- mount = os .path .join (tmpdir , 'mount' )
188- subprocess .run (['hdiutil' , 'mount' , '-mount' , 'required' , '-mountpoint' , mount , dmg ], check = True , capture_output = True )
189- # copy stuff out
190- appdirs = [d for d in os .listdir (mount ) if d .startswith ('Julia' ) and d .endswith ('.app' )]
191- if len (appdirs ) != 1 :
192- raise Exception ('expecting one Julia*.app directory' )
193- srcdir = os .path .join (mount , appdirs [0 ], 'Contents' , 'Resources' , 'julia' )
194- shutil .copytree (srcdir , prefix , symlinks = True )
195- # unmount
196- subprocess .run (['umount' , mount ], check = True , capture_output = True )
197- # delete tmpdir
198- shutil .rmtree (tmpdir )
178+ with tempfile .TemporaryDirectory () as tmpdir :
179+ # write the dmg file out
180+ dmg = os .path .join (tmpdir , 'dmg' )
181+ with open (dmg , 'wb' ) as f :
182+ f .write (buf .read ())
183+ # mount it
184+ mount = os .path .join (tmpdir , 'mount' )
185+ subprocess .run (['hdiutil' , 'mount' , '-mount' , 'required' , '-mountpoint' , mount , dmg ], check = True , capture_output = True )
186+ try :
187+ # copy stuff out
188+ appdirs = [d for d in os .listdir (mount ) if d .startswith ('Julia' ) and d .endswith ('.app' )]
189+ if len (appdirs ) != 1 :
190+ raise Exception ('expecting one Julia*.app directory' )
191+ srcdir = os .path .join (mount , appdirs [0 ], 'Contents' , 'Resources' , 'julia' )
192+ shutil .copytree (srcdir , prefix , symlinks = True )
193+ finally :
194+ # unmount
195+ subprocess .run (['umount' , mount ], check = True , capture_output = True )
196+
197+ julia_installers = {
198+ '.tar.gz' : install_julia_tar_gz ,
199+ '.zip' : install_julia_zip ,
200+ '.dmg' : install_julia_dmg ,
201+ }
0 commit comments