1#!/usr/bin/env python3
2
3from pathlib import Path
4from typing import List
5import json
6import os
7import shutil
8import shutil
9import subprocess
10import sys
11import tempfile
12
13
14def run_subprocess(command: List[str]) -> subprocess.CompletedProcess[str]:
15    proc = subprocess.run(command, capture_output=True, check=False)
16
17    if proc.returncode:
18        print("Subcommand exited with error", proc.returncode, file=sys.stderr)
19        print("Args:", proc.args, file=sys.stderr)
20        print("stderr:", proc.stderr.decode("utf-8"), file=sys.stderr)
21        print("stdout:", proc.stdout.decode("utf-8"), file=sys.stderr)
22        exit(proc.returncode)
23
24    return proc
25
26
27def main() -> None:
28    """The main entrypoint."""
29    workspace_root = Path(
30        os.environ.get(
31            "BUILD_WORKSPACE_DIRECTORY",
32            str(Path(__file__).parent.parent.parent.parent.parent),
33        )
34    )
35    metadata_dir = workspace_root / "crate_universe/test_data/metadata"
36    cargo = os.getenv("CARGO", "cargo")
37
38    with tempfile.TemporaryDirectory() as temp_dir:
39        temp_dir_path = Path(temp_dir)
40        temp_dir_path.mkdir(parents=True, exist_ok=True)
41
42        for test_dir in metadata_dir.iterdir():
43
44            # Check to see if the directory contains a Cargo manifest
45            real_manifest = test_dir / "Cargo.toml"
46            if not real_manifest.exists():
47                continue
48
49            # Copy the test directory into a temp directory (and out from under a Cargo workspace)
50            manifest_dir = temp_dir_path / test_dir.name
51            shutil.copytree(test_dir, manifest_dir)
52
53            manifest = manifest_dir / "Cargo.toml"
54            lockfile = manifest_dir / "Cargo.lock"
55
56            if lockfile.exists():
57                proc = run_subprocess(
58                    [cargo, "update", "--manifest-path", str(manifest), "--workspace"]
59                )
60            else:
61                # Generate Lockfile
62                proc = run_subprocess(
63                    [cargo, "generate-lockfile", "--manifest-path", str(manifest)]
64                )
65
66                if not lockfile.exists():
67                    print("Faield to generate lockfile")
68                    print("Args:", proc.args, file=sys.stderr)
69                    print("stderr:", proc.stderr.decode("utf-8"), file=sys.stderr)
70                    print("stdout:", proc.stdout.decode("utf-8"), file=sys.stderr)
71                    exit(1)
72
73            shutil.copy2(str(lockfile), str(test_dir / "Cargo.lock"))
74
75            # Generate metadata
76            proc = run_subprocess(
77                [
78                    cargo,
79                    "metadata",
80                    "--format-version",
81                    "1",
82                    "--manifest-path",
83                    str(manifest),
84                ]
85            )
86
87            cargo_home = os.environ.get("CARGO_HOME", str(Path.home() / ".cargo"))
88
89            # Replace the temporary directory so package IDs are predictable
90            metadata_text = proc.stdout.decode("utf-8")
91            metadata_text = metadata_text.replace(temp_dir, "{TEMP_DIR}")
92            metadata_text = metadata_text.replace(cargo_home, "{CARGO_HOME}")
93
94            # Write metadata to disk
95            metadata = json.loads(metadata_text)
96            output = test_dir / "metadata.json"
97            output.write_text(json.dumps(metadata, indent=4, sort_keys=True) + "\n")
98
99
100if __name__ == "__main__":
101    main()
102