leo_lang/cli/commands/devnet/utilities.rs
1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18
19use anyhow::{Result, ensure};
20#[cfg(unix)]
21use std::os::unix::fs::PermissionsExt;
22use std::{
23 fs,
24 path::{Path, PathBuf},
25 process::Command,
26};
27
28/// Compiles & installs snarkOS and returns the **final binary path**.
29///
30/// * `snarkos_path` – the exact `--snarkos` value (may not exist yet)
31/// * `version` – optional `--version` (`"4.1.0"` etc.)
32/// * `features` – `--features ..` list (may be empty)
33pub fn install_snarkos(snarkos_path: &Path, version: Option<&str>, features: &[String]) -> Result<PathBuf> {
34 //───────────────── 1. resolve & prepare directories ─────────────────
35 // Create a temporary install directory.
36 let tempdir = tempfile::tempdir()?;
37 let install_root = tempdir.path();
38
39 //───────────────── 2. `cargo install` into <root> ───────────────────
40 let mut cmd = Command::new("cargo");
41 cmd.args(["install", "--locked", "--force", "snarkos", "--root", install_root.to_str().unwrap()]);
42 if let Some(v) = version {
43 cmd.arg("--version").arg(v);
44 }
45 if !features.is_empty() {
46 cmd.arg("--features").arg(features.join(","));
47 }
48
49 println!("🔧 Building snarkOS into {} …", install_root.display());
50 ensure!(cmd.status()?.success(), "`cargo install` failed");
51
52 //───────────────── 3. link / copy to requested path ─────────────────
53 // Get the path to the built `snarkos` binary.
54 let built_bin = install_root.join("bin").join(if cfg!(windows) { "snarkos.exe" } else { "snarkos" });
55
56 // Remove the existing file if it exists, to ensure we overwrite it.
57 if snarkos_path.exists() {
58 fs::remove_file(snarkos_path)?; // overwrite consistently
59 }
60
61 // Copy the built binary to the requested path, ensuring the parent directory exists.
62 fs::create_dir_all(snarkos_path.parent().unwrap())?;
63 fs::copy(&built_bin, snarkos_path)?;
64
65 // Set permissions to be executable (if on Unix).
66 #[cfg(unix)]
67 {
68 let mut perms = fs::metadata(snarkos_path)?.permissions();
69 perms.set_mode(0o755); // rwxr-xr-x
70 fs::set_permissions(snarkos_path, perms)?;
71 }
72
73 ensure!(snarkos_path.is_file(), "snarkOS binary not produced at {}", snarkos_path.display());
74 println!("✅ Installed snarkOS ⇒ {}", snarkos_path.display());
75 Ok(snarkos_path.to_path_buf())
76}
77
78/// Cleans a ledger associated with a snarkOS node.
79pub fn clean_snarkos<S: AsRef<OsStr>>(
80 snarkos: S,
81 network: usize,
82 _role: &str,
83 idx: usize,
84 _storage: &Path,
85) -> std::io::Result<Child> {
86 StdCommand::new(snarkos)
87 .arg("clean")
88 .arg("--network")
89 .arg(network.to_string())
90 .arg("--dev")
91 .arg(idx.to_string())
92 .stdout(Stdio::null())
93 .stderr(Stdio::null())
94 .spawn()
95}