This commit is contained in:
ton
2024-10-07 10:13:40 +07:00
parent aa1631742f
commit 3a7d696db6
9729 changed files with 1832837 additions and 161742 deletions

View File

@@ -14,25 +14,25 @@ class WheelError(Exception):
pass
def unpack_f(args):
def unpack_f(args: argparse.Namespace) -> None:
from .unpack import unpack
unpack(args.wheelfile, args.dest)
def pack_f(args):
def pack_f(args: argparse.Namespace) -> None:
from .pack import pack
pack(args.directory, args.dest_dir, args.build_number)
def convert_f(args):
def convert_f(args: argparse.Namespace) -> None:
from .convert import convert
convert(args.files, args.dest_dir, args.verbose)
def tags_f(args):
def tags_f(args: argparse.Namespace) -> None:
from .tags import tags
names = (
@@ -51,14 +51,14 @@ def tags_f(args):
print(name)
def version_f(args):
def version_f(args: argparse.Namespace) -> None:
from .. import __version__
print("wheel %s" % __version__)
print(f"wheel {__version__}")
def parse_build_tag(build_tag: str) -> str:
if not build_tag[0].isdigit():
if build_tag and not build_tag[0].isdigit():
raise ArgumentTypeError("build tag must begin with a digit")
elif "-" in build_tag:
raise ArgumentTypeError("invalid character ('-') in build tag")

View File

@@ -7,7 +7,7 @@ import tempfile
import zipfile
from glob import iglob
from ..bdist_wheel import bdist_wheel
from .._bdist_wheel import bdist_wheel
from ..wheelfile import WheelFile
from . import WheelError
@@ -42,7 +42,7 @@ class _bdist_wheel_tag(bdist_wheel):
return bdist_wheel.get_tag(self)
def egg2wheel(egg_path: str, dest_dir: str):
def egg2wheel(egg_path: str, dest_dir: str) -> None:
filename = os.path.basename(egg_path)
match = egg_info_re.match(filename)
if not match:
@@ -96,7 +96,7 @@ def egg2wheel(egg_path: str, dest_dir: str):
shutil.rmtree(dir)
def parse_wininst_info(wininfo_name, egginfo_name):
def parse_wininst_info(wininfo_name: str, egginfo_name: str | None):
"""Extract metadata from filenames.
Extracts the 4 metadataitems needed (name, version, pyversion, arch) from
@@ -167,7 +167,7 @@ def parse_wininst_info(wininfo_name, egginfo_name):
return {"name": w_name, "ver": w_ver, "arch": w_arch, "pyver": w_pyver}
def wininst2wheel(path, dest_dir):
def wininst2wheel(path: str, dest_dir: str) -> None:
with zipfile.ZipFile(path) as bdw:
# Search for egg-info in the archive
egginfo_name = None
@@ -189,11 +189,11 @@ def wininst2wheel(path, dest_dir):
paths = {"platlib": ""}
dist_info = "{name}-{ver}".format(**info)
datadir = "%s.data/" % dist_info
datadir = f"{dist_info}.data/"
# rewrite paths to trick ZipFile into extracting an egg
# XXX grab wininst .ini - between .exe, padding, and first zip file.
members = []
members: list[str] = []
egginfo_name = ""
for zipinfo in bdw.infolist():
key, basename = zipinfo.filename.split("/", 1)
@@ -246,7 +246,7 @@ def wininst2wheel(path, dest_dir):
bw.full_tag_supplied = True
bw.full_tag = (pyver, abi, arch)
dist_info_dir = os.path.join(dir, "%s.dist-info" % dist_info)
dist_info_dir = os.path.join(dir, f"{dist_info}.dist-info")
bw.egg2dist(os.path.join(dir, egginfo_name), dist_info_dir)
bw.write_wheelfile(dist_info_dir, generator="wininst2wheel")
@@ -257,7 +257,7 @@ def wininst2wheel(path, dest_dir):
shutil.rmtree(dir)
def convert(files, dest_dir, verbose):
def convert(files: list[str], dest_dir: str, verbose: bool) -> None:
for pat in files:
for installer in iglob(pat):
if os.path.splitext(installer)[1] == ".egg":

View File

@@ -1,16 +1,18 @@
from __future__ import annotations
import email.policy
import os.path
import re
from email.generator import BytesGenerator
from email.parser import BytesParser
from wheel.cli import WheelError
from wheel.wheelfile import WheelFile
DIST_INFO_RE = re.compile(r"^(?P<namever>(?P<name>.+?)-(?P<ver>\d.*?))\.dist-info$")
BUILD_NUM_RE = re.compile(rb"Build: (\d\w*)$")
def pack(directory: str, dest_dir: str, build_number: str | None):
def pack(directory: str, dest_dir: str, build_number: str | None) -> None:
"""Repack a previously unpacked wheel directory into a new wheel file.
The .dist-info/WHEEL file must contain one or more tags so that the target
@@ -35,31 +37,29 @@ def pack(directory: str, dest_dir: str, build_number: str | None):
name_version = DIST_INFO_RE.match(dist_info_dir).group("namever")
# Read the tags and the existing build number from .dist-info/WHEEL
existing_build_number = None
wheel_file_path = os.path.join(directory, dist_info_dir, "WHEEL")
with open(wheel_file_path, "rb") as f:
tags, existing_build_number = read_tags(f.read())
info = BytesParser(policy=email.policy.compat32).parse(f)
tags: list[str] = info.get_all("Tag", [])
existing_build_number = info.get("Build")
if not tags:
raise WheelError(
"No tags present in {}/WHEEL; cannot determine target wheel "
"filename".format(dist_info_dir)
f"No tags present in {dist_info_dir}/WHEEL; cannot determine target "
f"wheel filename"
)
# Set the wheel file name and add/replace/remove the Build tag in .dist-info/WHEEL
build_number = build_number if build_number is not None else existing_build_number
if build_number is not None:
del info["Build"]
if build_number:
info["Build"] = build_number
name_version += "-" + build_number
if build_number != existing_build_number:
with open(wheel_file_path, "rb+") as f:
wheel_file_content = f.read()
wheel_file_content = set_build_number(wheel_file_content, build_number)
f.seek(0)
f.truncate()
f.write(wheel_file_content)
with open(wheel_file_path, "wb") as f:
BytesGenerator(f, maxheaderlen=0).flatten(info)
# Reassemble the tags for the wheel file
tagline = compute_tagline(tags)
@@ -73,45 +73,6 @@ def pack(directory: str, dest_dir: str, build_number: str | None):
print("OK")
def read_tags(input_str: bytes) -> tuple[list[str], str | None]:
"""Read tags from a string.
:param input_str: A string containing one or more tags, separated by spaces
:return: A list of tags and a list of build tags
"""
tags = []
existing_build_number = None
for line in input_str.splitlines():
if line.startswith(b"Tag: "):
tags.append(line.split(b" ")[1].rstrip().decode("ascii"))
elif line.startswith(b"Build: "):
existing_build_number = line.split(b" ")[1].rstrip().decode("ascii")
return tags, existing_build_number
def set_build_number(wheel_file_content: bytes, build_number: str | None) -> bytes:
"""Compute a build tag and add/replace/remove as necessary.
:param wheel_file_content: The contents of .dist-info/WHEEL
:param build_number: The build tags present in .dist-info/WHEEL
:return: The (modified) contents of .dist-info/WHEEL
"""
replacement = (
("Build: %s\r\n" % build_number).encode("ascii") if build_number else b""
)
wheel_file_content, num_replaced = BUILD_NUM_RE.subn(
replacement, wheel_file_content
)
if not num_replaced:
wheel_file_content += replacement
return wheel_file_content
def compute_tagline(tags: list[str]) -> str:
"""Compute a tagline from a list of tags.

View File

@@ -1,11 +1,12 @@
from __future__ import annotations
import email.policy
import itertools
import os
from collections.abc import Iterable
from email.parser import BytesParser
from ..wheelfile import WheelFile
from .pack import read_tags, set_build_number
def _compute_tags(original_tags: Iterable[str], new_tags: str | None) -> set[str]:
@@ -48,6 +49,7 @@ def tags(
assert f.filename, f"{f.filename} must be available"
wheel_info = f.read(f.dist_info_path + "/WHEEL")
info = BytesParser(policy=email.policy.compat32).parsebytes(wheel_info)
original_wheel_name = os.path.basename(f.filename)
namever = f.parsed_filename.group("namever")
@@ -56,7 +58,8 @@ def tags(
original_abi_tags = f.parsed_filename.group("abi").split(".")
original_plat_tags = f.parsed_filename.group("plat").split(".")
tags, existing_build_tag = read_tags(wheel_info)
tags: list[str] = info.get_all("Tag", [])
existing_build_tag = info.get("Build")
impls = {tag.split("-")[0] for tag in tags}
abivers = {tag.split("-")[1] for tag in tags}
@@ -103,12 +106,13 @@ def tags(
final_wheel_name = "-".join(final_tags) + ".whl"
if original_wheel_name != final_wheel_name:
tags = [
f"{a}-{b}-{c}"
for a, b, c in itertools.product(
final_python_tags, final_abi_tags, final_plat_tags
)
]
del info["Tag"], info["Build"]
for a, b, c in itertools.product(
final_python_tags, final_abi_tags, final_plat_tags
):
info["Tag"] = f"{a}-{b}-{c}"
if build:
info["Build"] = build
original_wheel_path = os.path.join(
os.path.dirname(f.filename), original_wheel_name
@@ -125,10 +129,7 @@ def tags(
if item.filename == f.dist_info_path + "/RECORD":
continue
if item.filename == f.dist_info_path + "/WHEEL":
content = fin.read(item)
content = set_tags(content, tags)
content = set_build_number(content, build)
fout.writestr(item, content)
fout.writestr(item, info.as_bytes())
else:
fout.writestr(item, fin.read(item))
@@ -136,18 +137,3 @@ def tags(
os.remove(original_wheel_path)
return final_wheel_name
def set_tags(in_string: bytes, tags: Iterable[str]) -> bytes:
"""Set the tags in the .dist-info/WHEEL file contents.
:param in_string: The string to modify.
:param tags: The tags to set.
"""
lines = [line for line in in_string.splitlines() if not line.startswith(b"Tag:")]
for tag in tags:
lines.append(b"Tag: " + tag.encode("ascii"))
in_string = b"\r\n".join(lines) + b"\r\n"
return in_string