|
| 1 | +//! Rebuilds Piltover mock contracts from source via the `piltover` |
| 2 | +//! submodule + scarb. The submodule is the single source of truth for the |
| 3 | +//! Sierra bytecode embedded in saya-ops. |
| 4 | +//! |
| 5 | +//! Dev setup: run `make install-scarb` from the repo root before `cargo build`. |
| 6 | +//! This build script hard-fails if asdf/scarb is missing — there is no |
| 7 | +//! vendored fallback for the mock contracts. |
| 8 | +//! |
| 9 | +//! NOT rebuilt: `contracts/core_contract.json`. Its class hash is load-bearing |
| 10 | +//! for already-deployed Piltover on Sepolia/Mainnet, and the Cairo source in |
| 11 | +//! the pinned piltover rev has diverged from the rev it was originally |
| 12 | +//! compiled at. It remains vendored. |
| 13 | +
|
| 14 | +use std::env; |
| 15 | +use std::path::{Path, PathBuf}; |
| 16 | +use std::process::Command; |
| 17 | + |
| 18 | +/// Pairs of (piltover scarb output name, OUT_DIR name for include_bytes!). |
| 19 | +const CONTRACTS: &[(&str, &str)] = &[ |
| 20 | + ("piltover_fact_registry_mock.contract_class.json", "fact_registry_mock.json"), |
| 21 | + ("piltover_mock_amd_tee_registry.contract_class.json", "tee_registry_mock.json"), |
| 22 | +]; |
| 23 | + |
| 24 | +fn main() { |
| 25 | + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); |
| 26 | + let workspace_root = manifest_dir.join("../.."); |
| 27 | + let piltover_dir = workspace_root.join("piltover"); |
| 28 | + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); |
| 29 | + |
| 30 | + println!("cargo:rerun-if-changed=build.rs"); |
| 31 | + println!("cargo:rerun-if-changed=../../piltover/src"); |
| 32 | + println!("cargo:rerun-if-changed=../../piltover/Scarb.toml"); |
| 33 | + println!("cargo:rerun-if-changed=../../piltover/Scarb.lock"); |
| 34 | + println!("cargo:rerun-if-changed=../../piltover/.tool-versions"); |
| 35 | + |
| 36 | + // Auto-init the submodule if it's empty (user may have cloned without |
| 37 | + // `--recursive`). Mirrors katana's `initialize_submodule` helper in |
| 38 | + // `crates/contracts/build.rs`. |
| 39 | + initialize_submodule_if_empty(&piltover_dir); |
| 40 | + |
| 41 | + // Hard-fail if scarb isn't on PATH. Dev must run `make install-scarb` first |
| 42 | + // (or install scarb directly). We invoke `scarb` directly rather than |
| 43 | + // `asdf exec scarb` so CI environments that install scarb via the official |
| 44 | + // installer (without asdf) also work. Local dev via asdf still works |
| 45 | + // transparently: asdf shims intercept the `scarb` call and route to the |
| 46 | + // version pinned by `piltover/.tool-versions`. |
| 47 | + let scarb_check = Command::new("scarb") |
| 48 | + .arg("--version") |
| 49 | + .current_dir(&piltover_dir) |
| 50 | + .output(); |
| 51 | + if !scarb_check.as_ref().map(|o| o.status.success()).unwrap_or(false) { |
| 52 | + panic!( |
| 53 | + "scarb not found on PATH. Run `make install-scarb` from the repo root to \ |
| 54 | + install the version pinned by `piltover/.tool-versions`, or install scarb \ |
| 55 | + directly from https://docs.swmansion.com/scarb/download.html." |
| 56 | + ); |
| 57 | + } |
| 58 | + |
| 59 | + // Build piltover contracts via scarb. |
| 60 | + let status = Command::new("scarb") |
| 61 | + .arg("build") |
| 62 | + .current_dir(&piltover_dir) |
| 63 | + .status() |
| 64 | + .expect("`scarb build` failed to spawn"); |
| 65 | + if !status.success() { |
| 66 | + panic!("scarb build failed in {}", piltover_dir.display()); |
| 67 | + } |
| 68 | + |
| 69 | + // Copy the two mock artifacts into OUT_DIR under stable names so the |
| 70 | + // corresponding `include_bytes!` sites in `core_contract/constants.rs` |
| 71 | + // can resolve them. |
| 72 | + for (scarb_name, out_name) in CONTRACTS { |
| 73 | + let src = piltover_dir.join("target/dev").join(scarb_name); |
| 74 | + let dst = out_dir.join(out_name); |
| 75 | + std::fs::copy(&src, &dst).unwrap_or_else(|e| { |
| 76 | + panic!( |
| 77 | + "failed to copy scarb output {} -> {}: {e}", |
| 78 | + src.display(), |
| 79 | + dst.display() |
| 80 | + ) |
| 81 | + }); |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +/// Auto-initializes the piltover submodule if the working tree is empty. |
| 86 | +/// Prints a `cargo:warning` so the user knows it's happening. |
| 87 | +fn initialize_submodule_if_empty(submodule_dir: &Path) { |
| 88 | + if submodule_dir.join("Scarb.toml").exists() { |
| 89 | + return; |
| 90 | + } |
| 91 | + println!( |
| 92 | + "cargo:warning=piltover submodule at {} not initialized, running `git submodule \ |
| 93 | + update --init --recursive --force`...", |
| 94 | + submodule_dir.display() |
| 95 | + ); |
| 96 | + let in_git_repo = Command::new("git") |
| 97 | + .args(["rev-parse", "--git-dir"]) |
| 98 | + .output() |
| 99 | + .map(|o| o.status.success()) |
| 100 | + .unwrap_or(false); |
| 101 | + if !in_git_repo { |
| 102 | + panic!( |
| 103 | + "Not in a git repo, and {} is empty. Clone saya with `--recursive`, or run \ |
| 104 | + `git submodule update --init --recursive` from a proper checkout.", |
| 105 | + submodule_dir.display() |
| 106 | + ); |
| 107 | + } |
| 108 | + let status = Command::new("git") |
| 109 | + .args(["submodule", "update", "--init", "--recursive", "--force"]) |
| 110 | + .arg(submodule_dir) |
| 111 | + .status() |
| 112 | + .expect("`git submodule update` failed to spawn"); |
| 113 | + if !status.success() { |
| 114 | + panic!("Failed to initialize piltover submodule at {}", submodule_dir.display()); |
| 115 | + } |
| 116 | +} |
0 commit comments