113 lines
2.9 KiB
Python
113 lines
2.9 KiB
Python
|
#!/usr/bin/python3
|
||
|
"""Vendor PyCA cryptography's Rust crates
|
||
|
"""
|
||
|
import argparse
|
||
|
import os
|
||
|
import re
|
||
|
import tarfile
|
||
|
import tempfile
|
||
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
|
||
|
VENDOR_DIR = "vendor"
|
||
|
CARGO_TOML = "src/rust/Cargo.toml"
|
||
|
RE_VERSION = re.compile("Version:\s*(.*)")
|
||
|
|
||
|
parser = argparse.ArgumentParser(description="Vendor Rust packages")
|
||
|
parser.add_argument(
|
||
|
"--spec", default="python-cryptography.spec", help="cryptography source tar bundle"
|
||
|
)
|
||
|
|
||
|
|
||
|
def cargo(cmd, manifest):
|
||
|
args = ["cargo", cmd, f"--manifest-path={manifest}"]
|
||
|
return subprocess.check_call(
|
||
|
args, stdout=subprocess.DEVNULL, stderr=sys.stderr, env={}
|
||
|
)
|
||
|
|
||
|
|
||
|
def tar_reset(tarinfo):
|
||
|
"""Reset user, group, mtime, and mode to create reproducible tar"""
|
||
|
tarinfo.uid = 0
|
||
|
tarinfo.gid = 0
|
||
|
tarinfo.uname = "root"
|
||
|
tarinfo.gname = "root"
|
||
|
tarinfo.mtime = 0
|
||
|
if tarinfo.type == tarfile.DIRTYPE:
|
||
|
tarinfo.mode = 0o755
|
||
|
else:
|
||
|
tarinfo.mode = 0o644
|
||
|
if tarinfo.pax_headers:
|
||
|
raise ValueError(tarinfo.name, tarinfo.pax_headers)
|
||
|
return tarinfo
|
||
|
|
||
|
|
||
|
def tar_reproducible(tar, basedir):
|
||
|
"""Create reproducible tar file"""
|
||
|
|
||
|
content = [basedir]
|
||
|
for root, dirs, files in os.walk(basedir):
|
||
|
for directory in dirs:
|
||
|
content.append(os.path.join(root, directory))
|
||
|
for filename in files:
|
||
|
content.append(os.path.join(root, filename))
|
||
|
content.sort()
|
||
|
|
||
|
for fn in content:
|
||
|
tar.add(fn, filter=tar_reset, recursive=False, arcname=fn)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
args = parser.parse_args()
|
||
|
spec = args.spec
|
||
|
|
||
|
# change cwd to work in bundle directory
|
||
|
here = os.path.dirname(os.path.abspath(spec))
|
||
|
os.chdir(here)
|
||
|
|
||
|
# extract version number from bundle name
|
||
|
with open(spec) as f:
|
||
|
for line in f:
|
||
|
mo = RE_VERSION.search(line)
|
||
|
if mo is not None:
|
||
|
version = mo.group(1)
|
||
|
break
|
||
|
else:
|
||
|
raise ValueError(f"Cannot find version in {spec}")
|
||
|
|
||
|
bundle_file = f"cryptography-{version}.tar.gz"
|
||
|
vendor_file = f"cryptography-{version}-vendor.tar.bz2"
|
||
|
|
||
|
# remove existing vendor directory and file
|
||
|
if os.path.isdir(VENDOR_DIR):
|
||
|
shutil.rmtree(VENDOR_DIR)
|
||
|
try:
|
||
|
os.unlink(vendor_file)
|
||
|
except FileNotFoundError:
|
||
|
pass
|
||
|
|
||
|
print(f"Getting crates for {bundle_file}", file=sys.stderr)
|
||
|
|
||
|
# extract tar file in tempdir
|
||
|
# fetch and vendor Rust crates
|
||
|
with tempfile.TemporaryDirectory(dir=here) as tmp:
|
||
|
with tarfile.open(bundle_file) as tar:
|
||
|
tar.extractall(path=tmp)
|
||
|
manifest = os.path.join(tmp, f"cryptography-{version}", CARGO_TOML)
|
||
|
cargo("fetch", manifest)
|
||
|
cargo("vendor", manifest)
|
||
|
|
||
|
print("\nCreating tar ball...", file=sys.stderr)
|
||
|
with tarfile.open(vendor_file, "x:bz2") as tar:
|
||
|
tar_reproducible(tar, VENDOR_DIR)
|
||
|
|
||
|
# remove vendor dir
|
||
|
shutil.rmtree(VENDOR_DIR)
|
||
|
|
||
|
parser.exit(0, f"Created {vendor_file}\n")
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|