use cid::multihash::Multihash;
use cid::Cid;
use fil_actor_bundler::Bundler;
use std::error::Error;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
use std::thread;
type Package = str;
type ID = str;
const ACTORS: &[(&Package, &ID)] = &[
("system", "system"),
("init", "init"),
("cron", "cron"),
("account", "account"),
("multisig", "multisig"),
("power", "storagepower"),
("miner", "storageminer"),
("market", "storagemarket"),
("paych", "paymentchannel"),
("reward", "reward"),
("verifreg", "verifiedregistry"),
];
const IPLD_RAW: u64 = 0x55;
const FORCED_CID_PREFIX: &str = "fil/7/";
const WASM_FEATURES: &[&str] = &["+bulk-memory", "+crt-static"];
const NETWORK_ENV: &str = "BUILD_FIL_NETWORK";
fn network_name() -> String {
let env_network = std::env::var_os(NETWORK_ENV);
let feat_network = if cfg!(feature = "mainnet") {
Some("mainnet")
} else if cfg!(feature = "caterpillarnet") {
Some("caterpillarnet")
} else if cfg!(feature = "butterflynet") {
Some("butterflynet")
} else if cfg!(feature = "calibrationnet") {
Some("calibrationnet")
} else if cfg!(feature = "devnet") {
Some("devnet")
} else if cfg!(feature = "testing") {
Some("testing")
} else if cfg!(feature = "testing-fake-proofs") {
Some("testing-fake-proofs")
} else {
None
};
match (feat_network, &env_network) {
(Some(from_feature), Some(from_env)) => {
assert_eq!(from_feature, from_env, "different target network configured via the features than via the {} environment variable", NETWORK_ENV);
from_feature
}
(Some(net), None) => net,
(None, Some(net)) => net.to_str().expect("network name not utf8"),
(None, None) => "mainnet",
}.to_owned()
}
fn main() -> Result<(), Box<dyn Error>> {
let cargo = std::env::var_os("CARGO").expect("no CARGO env var");
println!("cargo:warning=cargo: {:?}", &cargo);
let out_dir = std::env::var_os("OUT_DIR")
.as_ref()
.map(Path::new)
.map(|p| p.join("bundle"))
.expect("no OUT_DIR env var");
println!("cargo:warning=out_dir: {:?}", &out_dir);
let packages =
ACTORS.iter().map(|(pkg, _)| String::from("fil_actor_") + pkg).collect::<Vec<String>>();
let manifest_path =
Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR unset"))
.join("Cargo.toml");
println!("cargo:warning=manifest_path={:?}", &manifest_path);
let network_name = network_name();
println!("cargo:warning=network name: {}", network_name);
println!("cargo:rerun-if-env-changed={}", NETWORK_ENV);
for file in ["actors", "Cargo.toml", "Cargo.lock", "src", "build.rs"] {
println!("cargo:rerun-if-changed={}", file);
}
let rustflags =
WASM_FEATURES.iter().flat_map(|flag| ["-Ctarget-feature=", *flag, " "]).collect::<String>()
+ "-Clink-arg=--export-table";
let mut cmd = Command::new(&cargo);
cmd.arg("build")
.args(packages.iter().map(|pkg| "-p=".to_owned() + pkg))
.arg("--target=wasm32-unknown-unknown")
.arg("--profile=wasm")
.arg("--locked")
.arg("--manifest-path=".to_owned() + manifest_path.to_str().unwrap())
.env("RUSTFLAGS", rustflags)
.env(NETWORK_ENV, network_name)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("CARGO_TARGET_DIR", &out_dir)
.env_remove("CARGO_ENCODED_RUSTFLAGS");
println!("cargo:warning=cmd={:?}", &cmd);
let mut child = cmd.spawn().expect("failed to launch cargo build");
let stdout = child.stdout.take().expect("no stdout");
let stderr = child.stderr.take().expect("no stderr");
let j1 = thread::spawn(move || {
for line in BufReader::new(stderr).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});
let j2 = thread::spawn(move || {
for line in BufReader::new(stdout).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});
j1.join().unwrap();
j2.join().unwrap();
let dst = Path::new(&out_dir).join("bundle.car");
let mut bundler = Bundler::new(&dst);
for (pkg, id) in ACTORS {
let bytecode_path = Path::new(&out_dir)
.join("wasm32-unknown-unknown/wasm")
.join(format!("fil_actor_{}.wasm", pkg));
let forced_cid = {
let identity = FORCED_CID_PREFIX.to_owned() + id;
Cid::new_v1(IPLD_RAW, Multihash::wrap(0, identity.as_bytes())?)
};
let cid =
bundler.add_from_file(id, Some(&forced_cid), &bytecode_path).unwrap_or_else(|err| {
panic!("failed to add file {:?} to bundle for actor {}: {}", bytecode_path, id, err)
});
println!("cargo:warning=added actor {} to bundle with CID {}", id, cid);
}
bundler.finish().expect("failed to finish bundle");
println!("cargo:warning=bundle={}", dst.display());
Ok(())
}