Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ jobs:
strategy:
matrix:
container:
- ghcr.io/robotpy/crossenv-ci-images:py308-arm64-24.04-qemu
- ghcr.io/robotpy/crossenv-ci-images:py309-arm64-24.04-qemu
- ghcr.io/robotpy/crossenv-ci-images:py310-arm64-24.04-qemu
- ghcr.io/robotpy/crossenv-ci-images:py311-arm64-24.04-qemu
- ghcr.io/robotpy/crossenv-ci-images:py312-arm64-24.04-qemu
- ghcr.io/robotpy/crossenv-ci-images:py313-arm64-24.04-qemu
Expand Down
2 changes: 1 addition & 1 deletion crossenv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ def ensure_directories(self, env_dir):
utils.remove_path(os.path.join(env_dir, sub))

context = super().ensure_directories(env_dir)
context.sys_executable = sys.executable
context.lib_path = os.path.join(env_dir, "lib")
context.exposed_libs = os.path.join(context.lib_path, "exposed.txt")
utils.mkdir_if_needed(context.lib_path)
Expand Down Expand Up @@ -893,7 +894,6 @@ def make_cross_python(self, context):
"subprocess-patch.py",
"distutils-sysconfig-patch.py",
"pip-_vendor-distlib-scripts-patch.py",
"pkg_resources-patch.py",
"packaging-tags-patch.py",
]

Expand Down
110 changes: 102 additions & 8 deletions crossenv/scripts/cross-expose.py.tmpl
Original file line number Diff line number Diff line change
@@ -1,16 +1,89 @@
#!{{context.build_env_exe}}

import sys
import os
import importlib
import argparse
import logging
import pkg_resources
import pathlib
import re
import subprocess
import tempfile


try:
import importlib.metadata

def _get_package(name):
try:
dist = importlib.metadata.distribution(name)
return dist.version
except importlib.metadata.PackageNotFoundError:
return None

except ImportError:
import pkg_resources

def _get_package(name):
try:
dist = pkg_resources.get_distribution(name)
return dist.version
except pkg_resources.DistributionNotFound:
return None


logger = logging.getLogger()
EXPOSED_LIBS = {{repr(context.exposed_libs)}}


def install_fake_wheel(name, version):
# https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization
name = re.sub(r"[-_.]+", "-", name).lower()
wheel_dist = name.replace("-", "_")

with tempfile.TemporaryDirectory() as tname:
tpath = pathlib.Path(tname)
dist_info = tpath / f"{wheel_dist}-{version}.dist-info"
dist_info.mkdir(parents=True, exist_ok=True)

with open(dist_info / "METADATA", "w") as fp:
fp.write(
"Metadata-Version: 2.1\n" f"Name: {name}\n" f"Version: {version}\n"
)

with open(dist_info / "WHEEL", "w") as fp:
fp.write(
"Wheel-Version: 1.0\n"
"Generator: crossenv\n"
"Root-Is-Purelib: true\n"
"Tag: py3-none-any\n"
)

subprocess.check_call(
[
{{repr(context.sys_executable)}},
"-m",
"wheel",
"pack",
tname,
"--dest-dir",
tname,
]
)

whl = list(tpath.glob("*.whl"))[0]

subprocess.check_call(
[
{{repr(context.cross_env_exe)}},
"-m",
"pip",
"--disable-pip-version-check",
"install",
str(whl),
]
)


def get_exposed():
exposed = set()
try:
Expand All @@ -34,22 +107,43 @@ def list_exposed():
def expose_packages(names, unexpose=False):
exposed = get_exposed()
names = set(names)
added = set()
removed = []

if not unexpose:
for name in names:
try:
pkg_resources.require(name)
except pkg_resources.DistributionNotFound:
logger.warning("%r was not found in build-python. Skipping.", name)
else:
if name in exposed:
continue
version = _get_package(name)
if version is not None:
exposed.add(name)
added.add((name, version))
else:
logger.warning("%r was not found in build-python. Skipping.", name)

else:
for name in names:
if name not in exposed:
logger.warning("%r was not exposed. Skipping.", name)
else:
exposed.remove(name)
removed.append(name)

for name, version in added:
install_fake_wheel(name, version)

if removed:
subprocess.check_call(
[
{{repr(context.cross_env_exe)}},
"-m",
"pip",
"--disable-pip-version-check",
"uninstall",
"-y",
]
+ removed
)

with open(EXPOSED_LIBS, "w") as fp:
for item in sorted(exposed):
Expand Down Expand Up @@ -129,7 +223,7 @@ def main():
expose_packages(args.MODULE, args.unexpose)
except Exception as e:
exit_code = 1
logger.error("Cannot %s %s: %s", action, mod, e)
logger.error("Cannot %s %s: %s", action, args.MODULE, e)
logger.error("Traceback:", exc_info=True)

sys.exit(exit_code)
Expand Down
46 changes: 0 additions & 46 deletions crossenv/scripts/pkg_resources-patch.py.tmpl

This file was deleted.

2 changes: 0 additions & 2 deletions crossenv/scripts/site.py.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ class CrossenvFinder(importlib.abc.MetaPathFinder):
"distutils.sysconfig": "{{context.lib_path}}/distutils-sysconfig-patch.py",
"distutils.sysconfig_pypy": "{{context.lib_path}}/distutils-sysconfig-patch.py",
"platform": "{{context.lib_path}}/platform-patch.py",
"pkg_resources": "{{context.lib_path}}/pkg_resources-patch.py",
"pip._vendor.distlib.scripts": "{{context.lib_path}}/pip-_vendor-distlib-scripts-patch.py",
"pip._vendor.pkg_resources": "{{context.lib_path}}/pkg_resources-patch.py",
"pip._vendor.packaging.tags": "{{context.lib_path}}/packaging-tags-patch.py",
"packaging.tags": "{{context.lib_path}}/packaging-tags-patch.py",
}
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
]
dependencies = [
"wheel"
]

[project.urls]
Homepage = "https://github.com/benfogle/crossenv"
Expand Down
1 change: 0 additions & 1 deletion tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ def test_run_sysconfig_module(crossenv):
assert destdirs_cmdline == out


@pytest.mark.xfail(reason="cross-expose needs to patch importlib.metadata")
def test_cross_expose(crossenv):
out = crossenv.check_output(["pip", "freeze"])
assert b"colorama" not in out
Expand Down