fn generate_install_parameters() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
let out_path = std::path::PathBuf::from(&out_dir);
let root_dir = out_path
.parent() .and_then(|p| p.parent()) .and_then(|p| p.parent()) .and_then(|p| p.parent()) .and_then(|p| p.parent()) .and_then(|p| p.parent()) .expect("Could not find root directory from OUT_DIR");
println!("cargo:warning=Root directory: {}", root_dir.display());
let output = std::process::Command::new("cargo")
.current_dir(root_dir)
.args(&["metadata", "--format-version", "1", "--no-deps"])
.output()
.expect("Failed to execute cargo metadata");
let metadata: serde_json::Value =
serde_json::from_slice(&output.stdout).expect("Failed to parse cargo metadata output");
println!("cargo:warning=Looking for ledger metadata...");
if let Some(packages) = metadata["packages"].as_array() {
for package in packages {
let pkg_name = package["name"].as_str().unwrap_or("unknown");
println!("cargo:warning=Checking package: {}", pkg_name);
if let Some(metadata_ledger) = package["metadata"]["ledger"].as_object() {
println!(
"cargo:warning=Found ledger metadata in package: {}",
pkg_name
);
let app_name = metadata_ledger["name"].as_str().expect("name not found");
println!("cargo:rustc-env=APP_NAME={}", app_name);
println!("cargo:warning=APP_NAME is {}", app_name);
let app_flags = metadata_ledger["flags"].as_str().expect("flags not found");
println!("cargo:rustc-env=APP_FLAGS={}", app_flags);
println!("cargo:warning=APP_FLAGS is {}", app_flags);
let app_version = package["version"].as_str().expect("version not found");
println!("cargo:rustc-env=APP_VERSION={}", app_version);
println!("cargo:warning=APP_VERSION is {}", app_version);
let curves = metadata_ledger["curve"]
.as_array()
.expect("curves not found")
.iter()
.map(|v| format!("{}", v.as_str().unwrap()))
.collect::<Vec<_>>();
println!("cargo:warning=curves are {:x?}", curves);
let paths = metadata_ledger["path"]
.as_array()
.expect("paths not found")
.iter()
.map(|v| format!("{}", v.as_str().unwrap()))
.collect::<Vec<_>>();
println!("cargo:warning=paths are {:x?}", paths);
let paths_slip21: Vec<String> = metadata_ledger
.get("path_slip21")
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str())
.map(|s| s.to_string())
.collect()
})
.unwrap_or_default();
if !paths_slip21.is_empty() {
println!("cargo:warning=paths_slip21 are {:x?}", paths_slip21);
}
let install_params_exe = match std::env::var("LEDGER_SDK_PATH") {
Ok(path) => format!("{}/install_params.py", path),
Err(_) => {
let device_os = std::env::var_os("CARGO_CFG_TARGET_OS").unwrap();
let device_os = device_os.to_str().unwrap().split('_').next().unwrap();
format!("/opt/{}-secure-sdk/install_params.py", device_os)
}
};
let mut generate_tlv_install_params = std::process::Command::new("python3");
generate_tlv_install_params.arg(install_params_exe.as_str());
generate_tlv_install_params.arg("--appName").arg(app_name);
generate_tlv_install_params
.arg("--appVersion")
.arg(app_version);
curves.iter().for_each(|p| {
generate_tlv_install_params.arg("--curve").arg(p.as_str());
});
paths.iter().for_each(|p| {
generate_tlv_install_params
.arg("--path")
.arg(p.as_str().trim_end_matches('/'));
});
paths_slip21.iter().for_each(|p| {
generate_tlv_install_params
.arg("--path_slip21")
.arg(p.as_str());
});
let output = generate_tlv_install_params
.output()
.expect("Failed to execute install_params_generator");
if !output.status.success() {
panic!(
"call to install_params.py failed: {}",
std::str::from_utf8(&output.stderr).unwrap()
);
}
let tlv_blob = format!(
"[{}]",
std::str::from_utf8(output.stdout.as_slice())
.unwrap()
.trim()
);
let bytes: Vec<u8> = tlv_blob
.trim_matches(|c| c == '[' || c == ']')
.split(',')
.filter_map(|s| {
let trimmed = s.trim();
if trimmed.is_empty() {
None
} else {
u8::from_str_radix(trimmed.trim_start_matches("0x"), 16).ok()
}
})
.collect();
let byte_array_str = bytes
.iter()
.map(|b| format!("0x{:02x}", b))
.collect::<Vec<_>>()
.join(",");
let out_dir = std::env::var("OUT_DIR").unwrap();
std::fs::write(
std::path::Path::new(&out_dir).join("install_params.txt"),
format!("[{}]", byte_array_str),
)
.unwrap();
std::fs::write(
std::path::Path::new(&out_dir).join("install_params_len.txt"),
bytes.len().to_string(),
)
.unwrap();
println!("cargo:warning=INSTALL_PARAMS_BYTES is [{}]", byte_array_str);
println!("cargo:warning=INSTALL_PARAMS_LEN is {}", bytes.len());
return;
}
}
}
println!(
"cargo:warning=No [package.metadata.ledger] section found - empty install parameters generation"
);
let out_dir = std::env::var("OUT_DIR").unwrap();
std::fs::write(
std::path::Path::new(&out_dir).join("install_params.txt"),
"[]",
)
.unwrap();
std::fs::write(
std::path::Path::new(&out_dir).join("install_params_len.txt"),
"0",
)
.unwrap();
}
fn main() {
println!("cargo:rerun-if-changed=Cargo.toml");
generate_install_parameters();
}