|
@@ -2,14 +2,16 @@
|
|
|
import fnmatch
|
|
|
import hashlib
|
|
|
import logging
|
|
|
-from pathlib import Path
|
|
|
+import glob
|
|
|
+import os
|
|
|
import re
|
|
|
import shutil
|
|
|
-from tempfile import mkdtemp
|
|
|
+import yarg
|
|
|
import zipfile
|
|
|
|
|
|
-import yarg
|
|
|
+from pathlib import Path
|
|
|
from requests_download import download, HashTracker
|
|
|
+from tempfile import mkdtemp
|
|
|
|
|
|
from .util import get_cache_dir, normalize_path
|
|
|
|
|
@@ -82,8 +84,8 @@ class WheelLocator(object):
|
|
|
Returns a Path or None.
|
|
|
"""
|
|
|
whl_filename_prefix = '{name}-{version}-'.format(
|
|
|
- name=re.sub("[^\w\d.]+", "_", self.name),
|
|
|
- version=re.sub("[^\w\d.]+", "_", self.version),
|
|
|
+ name=re.sub(r'[^\w\d.]+', '_', self.name),
|
|
|
+ version=re.sub(r'[^\w\d.]+', '_', self.version),
|
|
|
)
|
|
|
for source in self.extra_sources:
|
|
|
candidates = [CachedRelease(p.name)
|
|
@@ -92,7 +94,6 @@ class WheelLocator(object):
|
|
|
rel = self.pick_best_wheel(candidates)
|
|
|
if rel:
|
|
|
path = source / rel.filename
|
|
|
- logger.info('Using wheel from extra directory: %s', path)
|
|
|
return path
|
|
|
|
|
|
def check_cache(self):
|
|
@@ -109,7 +110,6 @@ class WheelLocator(object):
|
|
|
if rel is None:
|
|
|
return None
|
|
|
|
|
|
- logger.info('Using cached wheel: %s', rel.filename)
|
|
|
return release_dir / rel.filename
|
|
|
|
|
|
def get_from_pypi(self):
|
|
@@ -158,10 +158,12 @@ class WheelLocator(object):
|
|
|
"""Find and return a compatible wheel (main interface)"""
|
|
|
p = self.check_extra_sources()
|
|
|
if p is not None:
|
|
|
+ logger.info('Using wheel from extra directory: %s', p)
|
|
|
return p
|
|
|
|
|
|
p = self.check_cache()
|
|
|
if p is not None:
|
|
|
+ logger.info('Using cached wheel: %s', p)
|
|
|
return p
|
|
|
|
|
|
return self.get_from_pypi()
|
|
@@ -250,12 +252,58 @@ def extract_wheel(whl_file, target_dir, exclude=None):
|
|
|
shutil.rmtree(str(td))
|
|
|
|
|
|
|
|
|
-def fetch_pypi_wheels(requirements, target_dir, py_version, bitness,
|
|
|
- extra_sources=None, exclude=None):
|
|
|
- for req in requirements:
|
|
|
+def fetch_pypi_wheels(wheels_requirements, wheels_paths, target_dir, py_version,
|
|
|
+ bitness, extra_sources=None, exclude=None):
|
|
|
+ """
|
|
|
+ Gather wheels included explicitly by wheels_pypi parameter
|
|
|
+ or matching glob paths given in local_wheels parameter.
|
|
|
+ """
|
|
|
+ distributions = []
|
|
|
+ # We try to get the wheels from wheels_pypi requirements parameter
|
|
|
+ for req in wheels_requirements:
|
|
|
wl = WheelLocator(req, py_version, bitness, extra_sources)
|
|
|
- whl_file = wl.fetch()
|
|
|
+ whl_file = wl.fetch()
|
|
|
extract_wheel(whl_file, target_dir, exclude=exclude)
|
|
|
+ distributions.append(wl.name)
|
|
|
+ # Then from the local_wheels paths parameter
|
|
|
+ for glob_path in wheels_paths:
|
|
|
+ paths = glob.glob(glob_path)
|
|
|
+ if not paths:
|
|
|
+ raise ValueError('Error, glob path {0} does not match any wheel file'.format(glob_path))
|
|
|
+ for path in paths:
|
|
|
+ logger.info('Collecting wheel file: %s (from: %s)', os.path.basename(path), glob_path)
|
|
|
+ validate_wheel(path, distributions, py_version, bitness)
|
|
|
+ extract_wheel(path, target_dir, exclude=exclude)
|
|
|
+
|
|
|
+
|
|
|
+def extract_distribution_and_version(wheel_name):
|
|
|
+ """Extract distribution and version from a wheel file name"""
|
|
|
+ search = re.search(r'^([^-]+)-([^-]+)-.*\.whl$', wheel_name)
|
|
|
+ if not search:
|
|
|
+ raise ValueError('Invalid wheel file name: {0}'.format(wheel_name))
|
|
|
+
|
|
|
+ return (search.group(1), search.group(2))
|
|
|
+
|
|
|
+
|
|
|
+def validate_wheel(whl_path, distributions, py_version, bitness):
|
|
|
+ """
|
|
|
+ Verify that the given wheel can safely be included in the current installer.
|
|
|
+ If so, the given wheel info will be included in the given wheel info array.
|
|
|
+ If not, an exception will be raised.
|
|
|
+ """
|
|
|
+ wheel_name = os.path.basename(whl_path)
|
|
|
+ (distribution, version) = extract_distribution_and_version(wheel_name)
|
|
|
+
|
|
|
+ # Check that a distribution of same name has not been included before
|
|
|
+ if distribution in distributions:
|
|
|
+ raise ValueError('Error, wheel distribution {0} already included'.format(distribution))
|
|
|
+
|
|
|
+ # Check that the wheel is compatible with the installer environment
|
|
|
+ locator = WheelLocator('{0}=={1}'.format(distribution, version), py_version, bitness, [Path(os.path.dirname(whl_path))])
|
|
|
+ if not locator.check_extra_sources():
|
|
|
+ raise ValueError('Error, wheel {0} is not compatible with Python {1} for Windows'.format(wheel_name, py_version))
|
|
|
+
|
|
|
+ distributions.append(distribution)
|
|
|
|
|
|
|
|
|
def is_excluded(path, exclude):
|