diff --git a/crates/acvm_backend_barretenberg/src/lib.rs b/crates/acvm_backend_barretenberg/src/lib.rs index 9c04746cfd5..9f327ad8398 100644 --- a/crates/acvm_backend_barretenberg/src/lib.rs +++ b/crates/acvm_backend_barretenberg/src/lib.rs @@ -8,9 +8,16 @@ mod cli; mod proof_system; mod smart_contract; +const BACKENDS_DIR: &str = ".nargo/backends"; + +pub fn backends_directory() -> PathBuf { + let home_directory = dirs::home_dir().unwrap(); + home_directory.join(BACKENDS_DIR) +} + #[cfg(test)] fn get_bb() -> Backend { - let bb = Backend::new(); + let bb = Backend::default(); crate::assert_binary_exists(&bb); bb } @@ -24,21 +31,24 @@ fn assert_binary_exists(backend: &Backend) -> PathBuf { binary_path } -#[derive(Debug, Default)] -pub struct Backend {} +#[derive(Debug)] +pub struct Backend { + name: String, +} + +impl Default for Backend { + fn default() -> Self { + Self { name: "acvm-backend-barretenberg".to_string() } + } +} impl Backend { - pub fn new() -> Backend { - Backend::default() + pub fn new(name: String) -> Backend { + Backend { name } } fn backend_directory(&self) -> PathBuf { - const BACKENDS_DIR: &str = ".nargo/backends"; - const BACKEND_NAME: &str = "acvm-backend-barretenberg"; - - let home_directory = dirs::home_dir().unwrap(); - - home_directory.join(BACKENDS_DIR).join(BACKEND_NAME) + backends_directory().join(&self.name) } fn binary_path(&self) -> PathBuf { diff --git a/crates/nargo_cli/src/backends.rs b/crates/nargo_cli/src/backends.rs index feaded3971d..10e6d380da0 100644 --- a/crates/nargo_cli/src/backends.rs +++ b/crates/nargo_cli/src/backends.rs @@ -1 +1,28 @@ +use std::path::PathBuf; + +use acvm_backend_barretenberg::backends_directory; pub(crate) use acvm_backend_barretenberg::Backend; + +fn active_backend_file_path() -> PathBuf { + backends_directory().join(".selected_backend") +} + +pub(crate) fn set_active_backend(backend_name: &str) { + std::fs::create_dir_all( + active_backend_file_path().parent().expect("active backend file should have parent"), + ) + .unwrap(); + std::fs::write(active_backend_file_path(), backend_name.as_bytes()).unwrap(); +} + +pub(crate) fn get_active_backend() -> String { + let active_backend_file = active_backend_file_path(); + + if !active_backend_file.is_file() { + let barretenberg = "acvm-backend-barretenberg"; + set_active_backend(barretenberg); + return barretenberg.to_string(); + } + + std::fs::read_to_string(active_backend_file).unwrap() +} diff --git a/crates/nargo_cli/src/cli/backend_cmd/ls_cmd.rs b/crates/nargo_cli/src/cli/backend_cmd/ls_cmd.rs new file mode 100644 index 00000000000..5a3d07e065a --- /dev/null +++ b/crates/nargo_cli/src/cli/backend_cmd/ls_cmd.rs @@ -0,0 +1,32 @@ +use acvm_backend_barretenberg::backends_directory; +use clap::Args; + +use crate::errors::CliError; + +/// Prints the list of available backends +#[derive(Debug, Clone, Args)] +pub(crate) struct LsCommand; + +pub(crate) fn run(_args: LsCommand) -> Result<(), CliError> { + for backend in get_available_backends() { + println!("{}", backend); + } + + Ok(()) +} + +pub(super) fn get_available_backends() -> Vec { + let backend_directory_contents = std::fs::read_dir(backends_directory()).unwrap(); + + backend_directory_contents + .into_iter() + .filter_map(|entry| { + let path = entry.ok()?.path(); + if path.is_dir() { + path.file_name().map(|name| name.to_string_lossy().to_string()) + } else { + None + } + }) + .collect() +} diff --git a/crates/nargo_cli/src/cli/backend_cmd/mod.rs b/crates/nargo_cli/src/cli/backend_cmd/mod.rs new file mode 100644 index 00000000000..23f6e0c2491 --- /dev/null +++ b/crates/nargo_cli/src/cli/backend_cmd/mod.rs @@ -0,0 +1,31 @@ +use clap::{Args, Subcommand}; + +use crate::errors::CliError; + +mod ls_cmd; +mod use_cmd; + +#[non_exhaustive] +#[derive(Args, Clone, Debug)] +pub(crate) struct BackendCommand { + #[command(subcommand)] + command: BackendCommands, +} + +#[non_exhaustive] +#[derive(Subcommand, Clone, Debug)] +pub(crate) enum BackendCommands { + Ls(ls_cmd::LsCommand), + Use(use_cmd::UseCommand), +} + +pub(crate) fn run(cmd: BackendCommand) -> Result<(), CliError> { + let BackendCommand { command } = cmd; + + match command { + BackendCommands::Ls(args) => ls_cmd::run(args), + BackendCommands::Use(args) => use_cmd::run(args), + }?; + + Ok(()) +} diff --git a/crates/nargo_cli/src/cli/backend_cmd/use_cmd.rs b/crates/nargo_cli/src/cli/backend_cmd/use_cmd.rs new file mode 100644 index 00000000000..a21e45956fe --- /dev/null +++ b/crates/nargo_cli/src/cli/backend_cmd/use_cmd.rs @@ -0,0 +1,21 @@ +use clap::Args; + +use crate::{backends::set_active_backend, errors::CliError}; + +use super::ls_cmd::get_available_backends; + +/// Select the currently active backend +#[derive(Debug, Clone, Args)] +pub(crate) struct UseCommand { + backend: String, +} + +pub(crate) fn run(args: UseCommand) -> Result<(), CliError> { + let backends = get_available_backends(); + + assert!(backends.contains(&args.backend), "backend doesn't exist"); + + set_active_backend(&args.backend); + + Ok(()) +} diff --git a/crates/nargo_cli/src/cli/mod.rs b/crates/nargo_cli/src/cli/mod.rs index 0a1fc059ff4..e33ae21cea7 100644 --- a/crates/nargo_cli/src/cli/mod.rs +++ b/crates/nargo_cli/src/cli/mod.rs @@ -5,8 +5,11 @@ use std::path::PathBuf; use color_eyre::eyre; +use crate::backends::get_active_backend; + mod fs; +mod backend_cmd; mod check_cmd; mod codegen_verifier_cmd; mod compile_cmd; @@ -47,6 +50,8 @@ pub(crate) struct NargoConfig { #[non_exhaustive] #[derive(Subcommand, Clone, Debug)] enum NargoCommand { + #[command(hide = true)] // Hidden while dynamic backends feature is being built out. + Backend(backend_cmd::BackendCommand), Check(check_cmd::CheckCommand), CodegenVerifier(codegen_verifier_cmd::CodegenVerifierCommand), #[command(alias = "build")] @@ -70,11 +75,18 @@ pub(crate) fn start_cli() -> eyre::Result<()> { } // Search through parent directories to find package root if necessary. - if !matches!(command, NargoCommand::New(_) | NargoCommand::Init(_) | NargoCommand::Lsp(_)) { + if !matches!( + command, + NargoCommand::New(_) + | NargoCommand::Init(_) + | NargoCommand::Lsp(_) + | NargoCommand::Backend(_) + ) { config.program_dir = find_package_root(&config.program_dir)?; } - let backend = crate::backends::Backend::default(); + let active_backend = get_active_backend(); + let backend = crate::backends::Backend::new(active_backend); match command { NargoCommand::New(args) => new_cmd::run(&backend, args, config), @@ -87,6 +99,7 @@ pub(crate) fn start_cli() -> eyre::Result<()> { NargoCommand::Test(args) => test_cmd::run(&backend, args, config), NargoCommand::Info(args) => info_cmd::run(&backend, args, config), NargoCommand::CodegenVerifier(args) => codegen_verifier_cmd::run(&backend, args, config), + NargoCommand::Backend(args) => backend_cmd::run(args), NargoCommand::Lsp(args) => lsp_cmd::run(&backend, args, config), }?;