|
|
@ -10,6 +10,7 @@ import dataclasses
|
|
|
|
import datetime
|
|
|
|
import datetime
|
|
|
|
import enum
|
|
|
|
import enum
|
|
|
|
import functools
|
|
|
|
import functools
|
|
|
|
|
|
|
|
import gzip
|
|
|
|
import hashlib
|
|
|
|
import hashlib
|
|
|
|
import http.client
|
|
|
|
import http.client
|
|
|
|
import inspect
|
|
|
|
import inspect
|
|
|
@ -21,6 +22,7 @@ import re
|
|
|
|
import secrets
|
|
|
|
import secrets
|
|
|
|
import shlex
|
|
|
|
import shlex
|
|
|
|
import shutil
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
import stat
|
|
|
|
import subprocess
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
import tarfile
|
|
|
|
import tarfile
|
|
|
@ -765,6 +767,41 @@ def set_ansible_version(current_version: Version, requested_version: Version) ->
|
|
|
|
ANSIBLE_RELEASE_FILE.write_text(updated)
|
|
|
|
ANSIBLE_RELEASE_FILE.write_text(updated)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_reproducible_sdist(original_path: pathlib.Path, output_path: pathlib.Path, mtime: int) -> None:
|
|
|
|
|
|
|
|
"""Read the specified sdist and write out a new copy with uniform file metadata at the specified location."""
|
|
|
|
|
|
|
|
with tarfile.open(original_path) as original_archive:
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
|
|
|
|
|
|
tar_file = pathlib.Path(temp_dir) / "sdist.tar"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with tarfile.open(tar_file, mode="w") as tar_archive:
|
|
|
|
|
|
|
|
for original_info in original_archive.getmembers(): # type: tarfile.TarInfo
|
|
|
|
|
|
|
|
tar_archive.addfile(create_reproducible_tar_info(original_info, mtime), original_archive.extractfile(original_info))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with tar_file.open("rb") as tar_archive:
|
|
|
|
|
|
|
|
with gzip.GzipFile(output_path, "wb", mtime=mtime) as output_archive:
|
|
|
|
|
|
|
|
shutil.copyfileobj(tar_archive, output_archive)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_reproducible_tar_info(original: tarfile.TarInfo, mtime: int) -> tarfile.TarInfo:
|
|
|
|
|
|
|
|
"""Return a copy of the given TarInfo with uniform file metadata."""
|
|
|
|
|
|
|
|
sanitized = tarfile.TarInfo()
|
|
|
|
|
|
|
|
sanitized.name = original.name
|
|
|
|
|
|
|
|
sanitized.size = original.size
|
|
|
|
|
|
|
|
sanitized.mtime = mtime
|
|
|
|
|
|
|
|
sanitized.mode = (original.mode & ~(stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)) | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
|
|
|
|
|
|
|
|
sanitized.type = original.type
|
|
|
|
|
|
|
|
sanitized.linkname = original.linkname
|
|
|
|
|
|
|
|
sanitized.uid = 0
|
|
|
|
|
|
|
|
sanitized.gid = 0
|
|
|
|
|
|
|
|
sanitized.uname = "root"
|
|
|
|
|
|
|
|
sanitized.gname = "root"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if original.mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
|
|
|
|
|
|
|
|
sanitized.mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sanitized
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_built_artifact(path: pathlib.Path) -> None:
|
|
|
|
def test_built_artifact(path: pathlib.Path) -> None:
|
|
|
|
"""Test the specified built artifact by installing it in a venv and running some basic commands."""
|
|
|
|
"""Test the specified built artifact by installing it in a venv and running some basic commands."""
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir_name:
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir_name:
|
|
|
@ -823,6 +860,12 @@ def get_release_artifact_details(repository: str, version: Version, validate: bo
|
|
|
|
|
|
|
|
|
|
|
|
artifacts = [describe_release_artifact(version, item, validate) for item in data["urls"]]
|
|
|
|
artifacts = [describe_release_artifact(version, item, validate) for item in data["urls"]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expected_artifact_types = {"bdist_wheel", "sdist"}
|
|
|
|
|
|
|
|
found_artifact_types = set(artifact.package_type for artifact in artifacts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if found_artifact_types != expected_artifact_types:
|
|
|
|
|
|
|
|
raise RuntimeError(f"Expected {expected_artifact_types} artifact types, but found {found_artifact_types} instead.")
|
|
|
|
|
|
|
|
|
|
|
|
return artifacts
|
|
|
|
return artifacts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1228,12 +1271,18 @@ def build(allow_dirty: bool = False) -> None:
|
|
|
|
temp_dir = pathlib.Path(temp_dir_name)
|
|
|
|
temp_dir = pathlib.Path(temp_dir_name)
|
|
|
|
dist_dir = temp_dir / "dist"
|
|
|
|
dist_dir = temp_dir / "dist"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
commit_time = int(git("show", "-s", "--format=%ct", capture_output=True).stdout)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
env.update(
|
|
|
|
|
|
|
|
SOURCE_DATE_EPOCH=str(commit_time),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
git("worktree", "add", "-d", temp_dir)
|
|
|
|
git("worktree", "add", "-d", temp_dir)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
run("python", "-m", "build", "--config-setting=--build-manpages", env=env, cwd=temp_dir)
|
|
|
|
run("python", "-m", "build", "--config-setting=--build-manpages", env=env, cwd=temp_dir)
|
|
|
|
|
|
|
|
|
|
|
|
get_sdist_path(version, dist_dir).rename(sdist_file)
|
|
|
|
create_reproducible_sdist(get_sdist_path(version, dist_dir), sdist_file, commit_time)
|
|
|
|
get_wheel_path(version, dist_dir).rename(wheel_file)
|
|
|
|
get_wheel_path(version, dist_dir).rename(wheel_file)
|
|
|
|
finally:
|
|
|
|
finally:
|
|
|
|
git("worktree", "remove", temp_dir)
|
|
|
|
git("worktree", "remove", temp_dir)
|
|
|
|