-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
currently the contents for the {name}.pth file is hardcoded for the psf/black project (because of course :P)
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,10 +34,16 @@ | |
import contextlib | ||
import tempfile | ||
import warnings | ||
import zipfile | ||
import base64 | ||
import textwrap | ||
import hashlib | ||
import csv | ||
|
||
import setuptools | ||
import distutils | ||
|
||
import pkg_resources | ||
from pkg_resources import parse_requirements | ||
|
||
__all__ = ['get_requires_for_build_sdist', | ||
|
@@ -126,6 +132,27 @@ def suppress_known_deprecation(): | |
yield | ||
|
||
|
||
def _urlsafe_b64encode(data): | ||
"""urlsafe_b64encode without padding""" | ||
return base64.urlsafe_b64encode(data).rstrip(b"=") | ||
|
||
|
||
def _add_wheel_record(archive, dist_info): | ||
""" | ||
Add the wheel RECORD manifest. | ||
""" | ||
buffer = io.StringIO() | ||
writer = csv.writer(buffer, delimiter=',', quotechar='"', lineterminator='\n') | ||
for f in archive.namelist(): | ||
data = archive.read(f) | ||
size = len(data) | ||
digest = hashlib.sha256(data).digest() | ||
digest = "sha256=" + (_urlsafe_b64encode(digest).decode("ascii")) | ||
writer.writerow((f, digest, size)) | ||
record_path = os.path.join(dist_info, "RECORD") | ||
archive.writestr(zipfile.ZipInfo(record_path), buffer.read()) | ||
|
||
|
||
class _BuildMetaBackend(object): | ||
|
||
def _fix_config(self, config_settings): | ||
|
@@ -146,6 +173,29 @@ def _get_build_requires(self, config_settings, requirements): | |
|
||
return requirements | ||
|
||
def _build_dist_info_metadata(self, result_directory): | ||
sys.argv = sys.argv[:1] + [ | ||
'dist_info', '--egg-base', result_directory] | ||
with no_install_setup_requires(): | ||
self.run_setup() | ||
|
||
dist_info_directory = result_directory | ||
while True: | ||
dist_infos = [f for f in os.listdir(dist_info_directory) | ||
if f.endswith('.dist-info')] | ||
|
||
if ( | ||
len(dist_infos) == 0 and | ||
len(_get_immediate_subdirectories(dist_info_directory)) == 1 | ||
): | ||
|
||
dist_info_directory = os.path.join( | ||
dist_info_directory, os.listdir(dist_info_directory)[0]) | ||
continue | ||
|
||
assert len(dist_infos) == 1 | ||
return dist_infos[0], dist_info_directory | ||
|
||
def run_setup(self, setup_script='setup.py'): | ||
# Note that we can reuse our build directory between calls | ||
# Correctness comes first, then optimization later | ||
|
@@ -166,39 +216,23 @@ def get_requires_for_build_sdist(self, config_settings=None): | |
config_settings = self._fix_config(config_settings) | ||
return self._get_build_requires(config_settings, requirements=[]) | ||
|
||
def get_requires_for_build_editable(self, config_settings=None): | ||
config_settings = self._fix_config(config_settings) | ||
return self._get_build_requires(config_settings, requirements=[]) | ||
|
||
def prepare_metadata_for_build_wheel(self, metadata_directory, | ||
config_settings=None): | ||
sys.argv = sys.argv[:1] + [ | ||
'dist_info', '--egg-base', metadata_directory] | ||
with no_install_setup_requires(): | ||
self.run_setup() | ||
|
||
dist_info_directory = metadata_directory | ||
while True: | ||
dist_infos = [f for f in os.listdir(dist_info_directory) | ||
if f.endswith('.dist-info')] | ||
|
||
if ( | ||
len(dist_infos) == 0 and | ||
len(_get_immediate_subdirectories(dist_info_directory)) == 1 | ||
): | ||
|
||
dist_info_directory = os.path.join( | ||
dist_info_directory, os.listdir(dist_info_directory)[0]) | ||
continue | ||
|
||
assert len(dist_infos) == 1 | ||
break | ||
|
||
dist_info, dist_info_directory = \ | ||
self._build_dist_info_metadata(metadata_directory) | ||
# PEP 517 requires that the .dist-info directory be placed in the | ||
# metadata_directory. To comply, we MUST copy the directory to the root | ||
if dist_info_directory != metadata_directory: | ||
shutil.move( | ||
os.path.join(dist_info_directory, dist_infos[0]), | ||
os.path.join(dist_info_directory, dist_info), | ||
metadata_directory) | ||
shutil.rmtree(dist_info_directory, ignore_errors=True) | ||
|
||
return dist_infos[0] | ||
return dist_info | ||
|
||
def _build_with_temp_dir(self, setup_command, result_extension, | ||
result_directory, config_settings): | ||
|
@@ -235,6 +269,55 @@ def build_sdist(self, sdist_directory, config_settings=None): | |
'.tar.gz', sdist_directory, | ||
config_settings) | ||
|
||
def build_editable(self, wheel_directory, config_settings=None, | ||
metadata_directory=None): | ||
config_settings = self._fix_config(config_settings) | ||
# TODO: using wheel_directory like this is probably a bad idea, fix it | ||
dist_info, dist_info_directory = self._build_dist_info_metadata(wheel_directory) | ||
This comment has been minimized.
Sorry, something went wrong. |
||
dist_info_path = os.path.join(dist_info_directory, dist_info) | ||
|
||
sys.argv = [ | ||
*sys.argv[:1], 'build_ext', '--inplace', | ||
*config_settings['--global-option'] | ||
] | ||
with no_install_setup_requires(): | ||
self.run_setup() | ||
# TODO: this is super sketchy, it's worth a cleanup | ||
provider = pkg_resources.PathMetadata(dist_info_path, dist_info_path) | ||
This comment has been minimized.
Sorry, something went wrong.
ichard26
Author
Owner
|
||
dist = pkg_resources.DistInfoDistribution.from_filename( | ||
dist_info_path, metadata=provider | ||
) | ||
wheel_name = f"{dist.project_name}-{dist.version}-ed.py3-none-any.whl" | ||
This comment has been minimized.
Sorry, something went wrong. |
||
wheel_path = os.path.join(wheel_directory, wheel_name) | ||
|
||
with zipfile.ZipFile( | ||
wheel_path, "a", compression=zipfile.ZIP_DEFLATED | ||
) as archive: | ||
# TODO: don't hardcode this obviously *somehow* | ||
data = "/home/ichard26/programming/oss/black/src" | ||
This comment has been minimized.
Sorry, something went wrong.
ichard26
Author
Owner
|
||
archive.writestr(zipfile.ZipInfo(f'{dist.project_name}.pth'), data) | ||
|
||
for file in sorted(os.listdir(dist_info_path)): | ||
file = os.path.join(dist_info_path, file) | ||
with open(file, "r", encoding="utf-8") as metadata: | ||
zip_filename = os.path.relpath(file, dist_info_directory) | ||
archive.writestr( | ||
zipfile.ZipInfo(zip_filename), metadata.read() | ||
) | ||
|
||
archive.writestr( | ||
zipfile.ZipInfo(os.path.join(dist_info, "WHEEL")), | ||
textwrap.dedent(f"""\ | ||
Wheel-Version: 1.0 | ||
Generator: setuptools ({setuptools.__version__}) | ||
Root-Is-Purelib: false | ||
Tag: ed.py3-none-any | ||
""") | ||
) | ||
_add_wheel_record(archive, dist_info) | ||
|
||
return os.path.basename(wheel_path) | ||
|
||
|
||
class _BuildMetaLegacyBackend(_BuildMetaBackend): | ||
"""Compatibility backend for setuptools | ||
|
@@ -281,9 +364,12 @@ def run_setup(self, setup_script='setup.py'): | |
|
||
get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel | ||
get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist | ||
get_requires_for_build_editable = _BACKEND.get_requires_for_build_editable | ||
prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel | ||
prepare_metadata_for_build_editable = _BACKEND.prepare_metadata_for_build_wheel | ||
build_wheel = _BACKEND.build_wheel | ||
build_sdist = _BACKEND.build_sdist | ||
build_editable = _BACKEND.build_editable | ||
|
||
|
||
# The legacy backend | ||
|
This is honestly just a stopgap solution until I figure out how I'm going to query the importable base (see below for comment). Either this is going become a in-tree metadata build or
result_directory
will become a TemporaryDirectory.