@@ -48,7 +48,7 @@ def _get_ssl_context():
4848 return ssl .create_default_context (cafile = certifi .where ())
4949
5050
51- def download_or_cache (url , sha ):
51+ def get_from_cache_or_download (url , sha ):
5252 """
5353 Get bytes from the given url or local cache.
5454
@@ -86,7 +86,7 @@ def download_or_cache(url, sha):
8686 file_sha = _get_hash (data )
8787 if file_sha != sha :
8888 raise Exception (
89- f"The download file does not match the expected sha. { url } was "
89+ f"The downloaded file does not match the expected sha. { url } was "
9090 f"expected to have { sha } but it had { file_sha } " )
9191
9292 if cache_dir is not None : # Try to cache the downloaded file.
@@ -100,6 +100,45 @@ def download_or_cache(url, sha):
100100 return BytesIO (data )
101101
102102
103+ def get_and_extract_tarball (urls , sha , dirname ):
104+ """
105+ Obtain a tarball (from cache or download) and extract it.
106+
107+ Parameters
108+ ----------
109+ urls : list[str]
110+ URLs from which download is attempted (in order of attempt), if the
111+ tarball is not in the cache yet.
112+ sha : str
113+ SHA256 hash of the tarball; used both as a cache key (by
114+ `get_from_cache_or_download`) and to validate a downloaded tarball.
115+ dirname : path-like
116+ Directory where the tarball is extracted.
117+ """
118+ toplevel = Path ("build" , dirname )
119+ if not toplevel .exists (): # Download it or load it from cache.
120+ Path ("build" ).mkdir (exist_ok = True )
121+ for url in urls :
122+ try :
123+ tar_contents = get_from_cache_or_download (url , sha )
124+ break
125+ except Exception :
126+ pass
127+ else :
128+ raise IOError (
129+ f"Failed to download any of the following: { urls } . "
130+ f"Please download one of these urls and extract it into "
131+ f"'build/' at the top-level of the source repository." )
132+ print ("Extracting {}" .format (urllib .parse .urlparse (url ).path ))
133+ with tarfile .open (fileobj = tar_contents , mode = "r:gz" ) as tgz :
134+ if os .path .commonpath (tgz .getnames ()) != dirname :
135+ raise IOError (
136+ f"The downloaded tgz file was expected to have { dirname } "
137+ f"as sole top-level directory, but that is not the case" )
138+ tgz .extractall ("build" )
139+ return toplevel
140+
141+
103142# SHA256 hashes of the FreeType tarballs
104143_freetype_hashes = {
105144 '2.6.1' :
@@ -515,7 +554,7 @@ def add_qhull_flags(ext):
515554 if options .get ("system_qhull" ):
516555 ext .libraries .append ("qhull" )
517556 else :
518- qhull_path = Path (f'extern /qhull-{ LOCAL_QHULL_VERSION } /src' )
557+ qhull_path = Path (f'build /qhull-{ LOCAL_QHULL_VERSION } /src' )
519558 ext .include_dirs .insert (0 , str (qhull_path ))
520559 ext .sources .extend (map (str , sorted (qhull_path .glob ('libqhull_r/*.c' ))))
521560 if sysconfig .get_config_var ("LIBM" ) == "-lm" :
@@ -560,46 +599,24 @@ def do_custom_build(self, env):
560599 if options .get ('system_freetype' ):
561600 return
562601
563- src_path = Path ('build' , f'freetype-{ LOCAL_FREETYPE_VERSION } ' )
602+ tarball = f'freetype-{ LOCAL_FREETYPE_VERSION } .tar.gz'
603+ src_path = get_and_extract_tarball (
604+ urls = [
605+ (f'https://downloads.sourceforge.net/project/freetype'
606+ f'/freetype2/{ LOCAL_FREETYPE_VERSION } /{ tarball } ' ),
607+ (f'https://download.savannah.gnu.org/releases/freetype'
608+ f'/{ tarball } ' )
609+ ],
610+ sha = LOCAL_FREETYPE_HASH ,
611+ dirname = f'freetype-{ LOCAL_FREETYPE_VERSION } ' ,
612+ )
564613
565- # We've already built freetype
566614 if sys .platform == 'win32' :
567615 libfreetype = 'libfreetype.lib'
568616 else :
569617 libfreetype = 'libfreetype.a'
570-
571- # bailing because it is already built
572618 if (src_path / 'objs' / '.libs' / libfreetype ).is_file ():
573- return
574-
575- # do we need to download / load the source from cache?
576- if not src_path .exists ():
577- os .makedirs ('build' , exist_ok = True )
578-
579- tarball = f'freetype-{ LOCAL_FREETYPE_VERSION } .tar.gz'
580- target_urls = [
581- (f'https://downloads.sourceforge.net/project/freetype'
582- f'/freetype2/{ LOCAL_FREETYPE_VERSION } /{ tarball } ' ),
583- (f'https://download.savannah.gnu.org/releases/freetype'
584- f'/{ tarball } ' )
585- ]
586-
587- for tarball_url in target_urls :
588- try :
589- tar_contents = download_or_cache (tarball_url ,
590- LOCAL_FREETYPE_HASH )
591- break
592- except Exception :
593- pass
594- else :
595- raise IOError (
596- f"Failed to download FreeType. Please download one of "
597- f"{ target_urls } and extract it into { src_path } at the "
598- f"top-level of the source repository." )
599-
600- print (f"Extracting { tarball } " )
601- with tarfile .open (fileobj = tar_contents , mode = "r:gz" ) as tgz :
602- tgz .extractall ("build" )
619+ return # Bail out because we have already built FreeType.
603620
604621 print (f"Building freetype in { src_path } " )
605622 if sys .platform != 'win32' : # compilation on non-windows
0 commit comments