11#!{{context.build_env_exe }}
22
33import sys
4- import os
54import importlib
65import argparse
76import logging
8- import pkg_resources
7+ import pathlib
8+ import re
9+ import subprocess
10+ import tempfile
11+
12+
13+ try:
14+ import importlib.metadata
15+
16+ def _get_package(name):
17+ try:
18+ dist = importlib.metadata.distribution (name)
19+ return dist.version
20+ except importlib.metadata.PackageNotFoundError :
21+ return None
22+
23+ except ImportError:
24+ import pkg_resources
25+
26+ def _get_package(name):
27+ try:
28+ dist = pkg_resources.get_distribution (name)
29+ return dist.version
30+ except pkg_resources.DistributionNotFound :
31+ return None
32+
933
1034logger = logging.getLogger ()
1135EXPOSED_LIBS = {{repr(context.exposed_libs )}}
1236
1337
38+ def install_fake_wheel(name, version):
39+ # https://packaging.python.org /en/latest/specifications/name-normalization/#name-normalization
40+ name = re.sub (r" [-_.]+" , " -" , name).lower ()
41+ wheel_dist = name.replace (" -" , " _" )
42+
43+ with tempfile.TemporaryDirectory () as tname:
44+ tpath = pathlib.Path (tname)
45+ dist_info = tpath / f" {wheel_dist}-{version}.dist-info"
46+ dist_info.mkdir (parents= True, exist_ok= True)
47+
48+ with open(dist_info / " METADATA" , " w" ) as fp:
49+ fp.write (
50+ " Metadata-Version: 2.1\n " f" Name: {name}\n " f" Version: {version}\n "
51+ )
52+
53+ with open(dist_info / " WHEEL" , " w" ) as fp:
54+ fp.write (
55+ " Wheel-Version: 1.0\n "
56+ " Generator: crossenv\n "
57+ " Root-Is-Purelib: true\n "
58+ " Tag: py3-none-any\n "
59+ )
60+
61+ subprocess.check_call (
62+ [
63+ {{repr(context.sys_executable )}},
64+ " -m" ,
65+ " wheel" ,
66+ " pack" ,
67+ tname,
68+ " --dest-dir" ,
69+ tname,
70+ ]
71+ )
72+
73+ whl = list(tpath.glob (" *.whl" ))[0]
74+
75+ subprocess.check_call (
76+ [
77+ {{repr(context.cross_env_exe )}},
78+ " -m" ,
79+ " pip" ,
80+ " --disable-pip-version-check" ,
81+ " install" ,
82+ str(whl),
83+ ]
84+ )
85+
86+
1487def get_exposed():
1588 exposed = set()
1689 try:
@@ -34,22 +107,43 @@ def list_exposed():
34107def expose_packages(names, unexpose= False):
35108 exposed = get_exposed()
36109 names = set(names)
110+ added = set()
111+ removed = []
37112
38113 if not unexpose:
39114 for name in names:
40- try:
41- pkg_resources.require (name)
42- except pkg_resources.DistributionNotFound :
43- logger.warning (" %r was not found in build-python. Skipping." , name)
44- else :
115+ if name in exposed:
116+ continue
117+ version = _get_package(name)
118+ if version is not None:
45119 exposed.add (name)
120+ added.add ((name, version))
121+ else :
122+ logger.warning (" %r was not found in build-python. Skipping." , name)
46123
47124 else :
48125 for name in names:
49126 if name not in exposed:
50127 logger.warning (" %r was not exposed. Skipping." , name)
51128 else :
52129 exposed.remove (name)
130+ removed.append (name)
131+
132+ for name, version in added:
133+ install_fake_wheel(name, version)
134+
135+ if removed:
136+ subprocess.check_call (
137+ [
138+ {{repr(context.cross_env_exe )}},
139+ " -m" ,
140+ " pip" ,
141+ " --disable-pip-version-check" ,
142+ " uninstall" ,
143+ " -y" ,
144+ ]
145+ + removed
146+ )
53147
54148 with open(EXPOSED_LIBS, " w" ) as fp:
55149 for item in sorted(exposed):
@@ -129,7 +223,7 @@ def main():
129223 expose_packages(args.MODULE , args.unexpose )
130224 except Exception as e:
131225 exit_code = 1
132- logger.error (" Cannot %s %s : %s " , action, mod , e)
226+ logger.error (" Cannot %s %s : %s " , action, args .MODULE , e)
133227 logger.error (" Traceback:" , exc_info= True)
134228
135229 sys.exit (exit_code)
0 commit comments