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}