#!/usr/bin/env python3 """在开发容器组装在线安装资源;不下载工具链、不发布或激活版本。""" import argparse import json from pathlib import Path import subprocess import tomllib from development import SOURCE, TRIPLE, copy, digest, native_tools, output, prepare, record, script def archive(directory, destination): with destination.open("xb") as stream: subprocess.run([ "tar", "--sort=name", "--mtime=@0", "--owner=0", "--group=0", "--numeric-owner", "-C", str(directory.parent), "-I", "xz -T4 -6", "-cf", "-", directory.name, ], stdout=stream, check=True) return digest(destination) def checksum(path): Path(str(path) + ".sha256").write_text(f"{digest(path)} {path.name}\n") def dependencies(bundle, rust_version): """Cargo 自己裁剪锁文件;安装时只下载本机运行库依赖,不带作者编译依赖。""" project = bundle / "toolchain/project" (project / "src").mkdir(parents=True) (project / "src/main.rs").write_text("fn main() {}\n") features = sorted(tomllib.loads((bundle / "rust/src/runtime/Cargo.toml").read_text())["features"]) (project / "Cargo.toml").write_text( '[package]\nname = "dever-development-dependencies"\nversion = "0.0.0"\nedition = "2024"\n' '[workspace]\n[dependencies]\n' f'dever-runtime = {{ path = "../../rust/src/runtime", features = {json.dumps(features)} }}\n' ) copy(bundle / "rust/Cargo.lock", project / "Cargo.lock") subprocess.run(["cargo", f"+{rust_version}", "metadata", "--offline", "--format-version", "1", "--manifest-path", str(project / "Cargo.toml")], stdout=subprocess.DEVNULL, check=True) def compiler_licenses(tools, rust_version): metadata = json.loads(output("cargo", f"+{rust_version}", "metadata", "--locked", "--offline", "--all-features", "--format-version", "1", cwd=SOURCE / "rust")) for package in metadata["packages"]: if not package["source"]: continue source = Path(package["manifest_path"]).parent licenses = {path for path in source.rglob("*") if path.is_file() and path.name.upper().startswith(("LICENSE", "COPYING", "COPYRIGHT", "NOTICE", "AUTHORS"))} if package["license_file"]: licenses.add(source / package["license_file"]) for path in licenses: copy(path, tools / "licenses/cargo" / source.name / path.relative_to(source)) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--compiler", required=True, type=Path) parser.add_argument("--work", required=True, type=Path) parser.add_argument("--output", required=True, type=Path, help="new release assets directory") args = parser.parse_args() system = Path("/etc/os-release").read_text() if 'ID=debian\n' not in system or 'VERSION_ID="13"' not in system: parser.error("prepare native tools in the Debian 13 development container") compiler = args.compiler.resolve(strict=True) work, destination = args.work.absolute(), args.output.absolute() if work.exists() or destination.exists(): parser.error("work and output must be new directories") destination.mkdir(parents=True) bundle, version, rust_version = prepare(compiler, work) tools = bundle / "toolchain" tools.mkdir() native = work / "native-tools" native.mkdir() native_tools(native) native_archive = destination / "native.tar.xz" native_id = archive(native, native_archive) native_archive = native_archive.rename(destination / f"dever-native-linux-x86_64-{native_id}.tar.xz") checksum(native_archive) copy(native / "bin/cc", tools / "bin/cc") script(tools / "bin/cargo", '''export CARGO_HOME="$tools/cache" export RUSTC="$tools/rust/bin/rustc" export CC="$tools/bin/cc" export AR="$tools/native/usr/bin/x86_64-linux-gnu-ar" export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="$CC" export LD_LIBRARY_PATH="$tools/lib" export PATH="$tools/native/usr/bin:/usr/bin:/bin" exec "$tools/rust/bin/cargo" "$@" ''') script(tools / "bin/rustc", '''export LD_LIBRARY_PATH="$tools/lib" exec "$tools/rust/bin/rustc" "$@" ''') (tools / "online").write_text(f"{rust_version} {native_id}\n") copy(SOURCE / "build/prepare.sh", tools / "prepare") dependencies(bundle, rust_version) compiler_licenses(tools, rust_version) copy(SOURCE / "build/README.md", bundle / "DEVELOPMENT.md") record(bundle, [bundle / "DEVELOPMENT.md", *tools.rglob("*")]) core_archive = destination / f"dever-{version}-linux-x86_64.tar.xz" archive(bundle, core_archive) checksum(core_archive) installer = (SOURCE / "install").read_text().replace('@DEVER_VERSION@', version) (destination / "install").write_text(installer) (destination / "install").chmod(0o755) checksum(destination / "install") print(json.dumps({"version": version, "compiler_sha256": digest(compiler), "core_bytes": core_archive.stat().st_size, "native_bytes": native_archive.stat().st_size, "installer_bytes": (destination / "install").stat().st_size, "rust": rust_version, "target": TRIPLE})) if __name__ == "__main__": main()