Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): Run command on the package closest to the current directory #6752

Merged
merged 13 commits into from
Dec 10, 2024
Merged
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion docs/docs/noir/modules_packages_crates/workspaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ members = ["crates/a", "crates/b"]
default-member = "crates/a"
```

`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified.
`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified. The `--package` option can be used to limit
the scope of some commands to a specific member of the workspace; otherwise these commands run on the package nearest on the path to the
current directory where `nargo` was invoked.

`default-member` indicates which package various commands process by default.

Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml.

Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml.

Please note that nesting regular packages is not supported: certain commands work on the workspace level and will use the topmost Nargo.toml file they can find on the path; unless this is a workspace configuration with `members`, the command might run on some unintended package.
24 changes: 7 additions & 17 deletions tooling/nargo_cli/src/cli/check_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,25 @@ use clap::Args;
use fm::FileManager;
use iter_extended::btree_map;
use nargo::{
errors::CompileError,
insert_all_files_for_workspace_into_file_manager,
ops::report_errors,
package::{CrateName, Package},
parse_all, prepare_package,
errors::CompileError, insert_all_files_for_workspace_into_file_manager, ops::report_errors,
package::Package, parse_all, prepare_package,
};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME};
use noirc_driver::{
check_crate, compute_function_abi, CompileOptions, CrateId, NOIR_ARTIFACT_VERSION_STRING,
};
use noirc_frontend::hir::{Context, ParsedFiles};

use super::fs::write_to_file;
use super::NargoConfig;
use super::{fs::write_to_file, PackageOptions};

/// Checks the constraint system for errors
#[derive(Debug, Clone, Args)]
#[clap(visible_alias = "c")]
pub(crate) struct CheckCommand {
/// The name of the package to check
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Check all packages in the workspace
#[clap(long, conflicts_with = "package")]
workspace: bool,
#[clap(flatten)]
pub(super) package_options: PackageOptions,

/// Force overwrite of existing files
#[clap(long = "overwrite")]
Expand All @@ -42,9 +34,7 @@ pub(crate) struct CheckCommand {

pub(crate) fn run(args: CheckCommand, config: NargoConfig) -> Result<(), CliError> {
let toml_path = get_package_manifest(&config.program_dir)?;
let default_selection =
if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };
let selection = args.package.map_or(default_selection, PackageSelection::Selected);
let selection = args.package_options.package_selection();
let workspace = resolve_workspace_from_toml(
&toml_path,
selection,
Expand Down
18 changes: 5 additions & 13 deletions tooling/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use acvm::acir::circuit::ExpressionWidth;
use fm::FileManager;
use nargo::ops::{collect_errors, compile_contract, compile_program, report_errors};
use nargo::package::{CrateName, Package};
use nargo::package::Package;
use nargo::workspace::Workspace;
use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all};
use nargo_toml::{
Expand All @@ -23,19 +23,14 @@
use crate::errors::CliError;

use super::fs::program::{read_program_from_file, save_contract_to_file, save_program_to_file};
use super::NargoConfig;
use super::{NargoConfig, PackageOptions};
use rayon::prelude::*;

/// Compile the program and its secret execution trace into ACIR format
#[derive(Debug, Clone, Args)]
pub(crate) struct CompileCommand {
/// The name of the package to compile
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Compile all packages in the workspace.
#[clap(long, conflicts_with = "package")]
workspace: bool,
#[clap(flatten)]
pub(super) package_options: PackageOptions,

#[clap(flatten)]
compile_options: CompileOptions,
Expand All @@ -46,10 +41,7 @@
}

pub(crate) fn run(args: CompileCommand, config: NargoConfig) -> Result<(), CliError> {
let default_selection =
if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };
let selection = args.package.map_or(default_selection, PackageSelection::Selected);

let selection = args.package_options.package_selection();
let workspace = read_workspace(&config.program_dir, selection)?;

if args.watch {
Expand Down Expand Up @@ -82,7 +74,7 @@
fn watch_workspace(workspace: &Workspace, compile_options: &CompileOptions) -> notify::Result<()> {
let (tx, rx) = std::sync::mpsc::channel();

// No specific tickrate, max debounce time 1 seconds

Check warning on line 77 in tooling/nargo_cli/src/cli/compile_cmd.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (tickrate)
let mut debouncer = new_debouncer(Duration::from_secs(1), None, tx)?;

// Add a path to be watched. All files and directories at that path and
Expand All @@ -90,7 +82,7 @@
debouncer.watcher().watch(&workspace.root_dir, RecursiveMode::Recursive)?;

let mut screen = std::io::stdout();
write!(screen, "{}", termion::cursor::Save).unwrap();

Check warning on line 85 in tooling/nargo_cli/src/cli/compile_cmd.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (termion)
screen.flush().unwrap();
let _ = compile_workspace_full(workspace, compile_options);
for res in rx {
Expand All @@ -111,7 +103,7 @@
});

if noir_files_modified {
write!(screen, "{}{}", termion::cursor::Restore, termion::clear::AfterCursor).unwrap();

Check warning on line 106 in tooling/nargo_cli/src/cli/compile_cmd.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (termion)

Check warning on line 106 in tooling/nargo_cli/src/cli/compile_cmd.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (termion)
screen.flush().unwrap();
let _ = compile_workspace_full(workspace, compile_options);
}
Expand Down
2 changes: 1 addition & 1 deletion tooling/nargo_cli/src/cli/debug_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) struct DebugCommand {

/// The name of the package to execute
#[clap(long)]
package: Option<CrateName>,
pub(super) package: Option<CrateName>,

#[clap(flatten)]
compile_options: CompileOptions,
Expand Down
19 changes: 6 additions & 13 deletions tooling/nargo_cli/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ use clap::Args;
use nargo::constants::PROVER_INPUT_FILE;
use nargo::errors::try_to_diagnose_runtime_error;
use nargo::foreign_calls::DefaultForeignCallExecutor;
use nargo::package::{CrateName, Package};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use nargo::package::Package;
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::InputMap;
use noirc_artifacts::debug::DebugArtifact;
use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING};

use super::compile_cmd::compile_workspace_full;
use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir};
use super::NargoConfig;
use super::{NargoConfig, PackageOptions};
use crate::cli::fs::program::read_program_from_file;
use crate::errors::CliError;

Expand All @@ -34,13 +34,8 @@ pub(crate) struct ExecuteCommand {
#[clap(long, short, default_value = PROVER_INPUT_FILE)]
prover_name: String,

/// The name of the package to execute
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Execute all packages in the workspace
#[clap(long, conflicts_with = "package")]
workspace: bool,
#[clap(flatten)]
pub(super) package_options: PackageOptions,

#[clap(flatten)]
compile_options: CompileOptions,
Expand All @@ -52,9 +47,7 @@ pub(crate) struct ExecuteCommand {

pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliError> {
let toml_path = get_package_manifest(&config.program_dir)?;
let default_selection =
if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };
let selection = args.package.map_or(default_selection, PackageSelection::Selected);
let selection = args.package_options.package_selection();
let workspace = resolve_workspace_from_toml(
&toml_path,
selection,
Expand Down
20 changes: 5 additions & 15 deletions tooling/nargo_cli/src/cli/export_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,33 @@ use nargo::package::Package;
use nargo::prepare_package;
use nargo::workspace::Workspace;
use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_driver::{
compile_no_check, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING,
};

use noirc_frontend::graph::CrateName;

use clap::Args;

use crate::errors::CliError;

use super::check_cmd::check_crate_and_report_errors;

use super::fs::program::save_program_to_file;
use super::NargoConfig;
use super::{NargoConfig, PackageOptions};

/// Exports functions marked with #[export] attribute
#[derive(Debug, Clone, Args)]
pub(crate) struct ExportCommand {
/// The name of the package to compile
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Compile all packages in the workspace
#[clap(long, conflicts_with = "package")]
workspace: bool,
#[clap(flatten)]
pub(super) package_options: PackageOptions,

#[clap(flatten)]
compile_options: CompileOptions,
}

pub(crate) fn run(args: ExportCommand, config: NargoConfig) -> Result<(), CliError> {
let toml_path = get_package_manifest(&config.program_dir)?;
let default_selection =
if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };
let selection = args.package.map_or(default_selection, PackageSelection::Selected);

let selection = args.package_options.package_selection();
let workspace = resolve_workspace_from_toml(
&toml_path,
selection,
Expand Down
21 changes: 6 additions & 15 deletions tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ use bn254_blackbox_solver::Bn254BlackBoxSolver;
use clap::Args;
use iter_extended::vecmap;
use nargo::{
constants::PROVER_INPUT_FILE,
foreign_calls::DefaultForeignCallExecutor,
package::{CrateName, Package},
constants::PROVER_INPUT_FILE, foreign_calls::DefaultForeignCallExecutor, package::Package,
};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_abi::input_parser::Format;
use noirc_artifacts::program::ProgramArtifact;
use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING};
Expand All @@ -20,7 +18,7 @@ use crate::{cli::fs::inputs::read_inputs_from_file, errors::CliError};
use super::{
compile_cmd::{compile_workspace_full, get_target_width},
fs::program::read_program_from_file,
NargoConfig,
NargoConfig, PackageOptions,
};

/// Provides detailed information on each of a program's function (represented by a single circuit)
Expand All @@ -31,13 +29,8 @@ use super::{
#[derive(Debug, Clone, Args)]
#[clap(visible_alias = "i")]
pub(crate) struct InfoCommand {
/// The name of the package to detail
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Detail all packages in the workspace
#[clap(long, conflicts_with = "package")]
workspace: bool,
#[clap(flatten)]
pub(super) package_options: PackageOptions,

/// Output a JSON formatted report. Changes to this format are not currently considered breaking.
#[clap(long, hide = true)]
Expand All @@ -56,9 +49,7 @@ pub(crate) struct InfoCommand {

pub(crate) fn run(mut args: InfoCommand, config: NargoConfig) -> Result<(), CliError> {
let toml_path = get_package_manifest(&config.program_dir)?;
let default_selection =
if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };
let selection = args.package.map_or(default_selection, PackageSelection::Selected);
let selection = args.package_options.package_selection();
let workspace = resolve_workspace_from_toml(
&toml_path,
selection,
Expand Down
75 changes: 57 additions & 18 deletions tooling/nargo_cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::{Args, Parser, Subcommand};
use const_format::formatcp;
use nargo_toml::find_package_root;
use noirc_driver::NOIR_ARTIFACT_VERSION_STRING;
use nargo_toml::PackageSelection;
use noirc_driver::{CrateName, NOIR_ARTIFACT_VERSION_STRING};
use std::path::PathBuf;

use color_eyre::eyre;
Expand Down Expand Up @@ -52,6 +52,38 @@ pub(crate) struct NargoConfig {
program_dir: PathBuf,
}

/// Options for commands that work on either workspace or package scope.
#[derive(Args, Clone, Debug, Default)]
pub(crate) struct PackageOptions {
/// The name of the package to run the command on.
/// By default run on the first one found moving up along the ancestors of the current directory.
#[clap(long, conflicts_with = "workspace")]
package: Option<CrateName>,

/// Run on all packages in the workspace
#[clap(long, conflicts_with = "package")]
workspace: bool,
}

impl PackageOptions {
/// Decide which package to run the command on:
/// * `package` if non-empty
/// * all packages if `workspace` is `true`
/// * otherwise the default package
pub(crate) fn package_selection(&self) -> PackageSelection {
let default_selection =
if self.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll };

self.package.clone().map_or(default_selection, PackageSelection::Selected)
}

/// Whether we need to look for the package manifest at the workspace level.
/// If a package is specified, it might not be the current package.
fn is_workspace_rooted(&self) -> bool {
self.workspace || self.package.is_some()
}
}

#[non_exhaustive]
#[derive(Subcommand, Clone, Debug)]
enum NargoCommand {
Expand Down Expand Up @@ -83,22 +115,8 @@ pub(crate) fn start_cli() -> eyre::Result<()> {
}

// Search through parent directories to find package root if necessary.
match &command {
NargoCommand::Check(..)
| NargoCommand::Fmt(..)
| NargoCommand::Compile(..)
| NargoCommand::Execute(..)
| NargoCommand::Export(..)
| NargoCommand::Debug(..)
| NargoCommand::Test(..)
| NargoCommand::Info(..) => {
config.program_dir = find_package_root(&config.program_dir)?;
}
NargoCommand::New(..)
| NargoCommand::Init(..)
| NargoCommand::Lsp(..)
| NargoCommand::Dap(..)
| NargoCommand::GenerateCompletionScript(..) => (),
if let Some(workspace) = is_workspace_rooted(&command) {
config.program_dir = nargo_toml::find_root(&config.program_dir, workspace)?;
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
}

match command {
Expand Down Expand Up @@ -127,6 +145,27 @@ pub(crate) fn start_cli() -> eyre::Result<()> {
Ok(())
}

/// Some commands have package options, which we use here to decide whether to
/// alter `--program-dir` to point at a manifest, depending on whether we want
/// to work on a specific package or the entire workspace.
fn is_workspace_rooted(cmd: &NargoCommand) -> Option<bool> {
match &cmd {
NargoCommand::Check(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Compile(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Execute(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Export(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Test(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Info(cmd) => Some(cmd.package_options.is_workspace_rooted()),
NargoCommand::Debug(cmd) => Some(cmd.package.is_some()),
NargoCommand::Fmt(..) => Some(true),
aakoshh marked this conversation as resolved.
Show resolved Hide resolved
NargoCommand::New(..)
| NargoCommand::Init(..)
| NargoCommand::Lsp(..)
| NargoCommand::Dap(..)
| NargoCommand::GenerateCompletionScript(..) => None,
}
}

#[cfg(test)]
mod tests {
use clap::Parser;
Expand Down
Loading
Loading