Skip to content

Commit

Permalink
Merge pull request #27916 from AleoHQ/fix/leo-add
Browse files Browse the repository at this point in the history
[Feat] Better `leo add` and `leo build` UX
  • Loading branch information
d0cd authored May 14, 2024
2 parents f29b6b0 + 3c83d49 commit a0cdafc
Show file tree
Hide file tree
Showing 20 changed files with 1,244 additions and 312 deletions.
469 changes: 235 additions & 234 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ default = [ ]
ci_skip = [ "leo-compiler/ci_skip" ]
noconfig = [ ]

[dependencies]
ureq = "2.9.7"

[dependencies.leo-ast]
path = "./compiler/ast"
version = "=1.11.0"
Expand Down
22 changes: 18 additions & 4 deletions errors/src/errors/package/package_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,17 @@ create_messages!(
}

@backtraced
missing_on_chain_program_name {
args: (),
msg: "The name of the program to execute on-chain is missing.".to_string(),
help: Some("Either set `--local` to execute the local program on chain, or set `--program <PROGRAM>`.".to_string()),
invalid_file_name_dependency {
args: (name: impl Display),
msg: format!("The dependency program name `{name}` is invalid."),
help: Some("Aleo program names must only contain lower case letters, numbers and underscores.".to_string()),
}

@backtraced
dependency_not_found {
args: (name: impl Display),
msg: format!("The dependency program `{name}` was not found among the manifest's dependencies."),
help: None,
}

@backtraced
Expand All @@ -383,4 +390,11 @@ create_messages!(
msg: format!("Conflicting program names given to execute on chain: `{first}` and `{second}`."),
help: Some("Either set `--local` to execute the local program on chain, or set `--program <PROGRAM>`.".to_string()),
}

@backtraced
missing_on_chain_program_name {
args: (),
msg: "The name of the program to execute on-chain is missing.".to_string(),
help: Some("Either set `--local` to execute the local program on chain, or set `--program <PROGRAM>`.".to_string()),
}
);
46 changes: 44 additions & 2 deletions errors/src/errors/utils/util_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ create_messages!(

@formatted
failed_to_retrieve_from_endpoint {
args: (endpoint: impl Display, error: impl ErrorArg),
msg: format!("Failed to retrieve from endpoint `{endpoint}`. Error: {error}"),
args: (error: impl ErrorArg),
msg: format!("{error}"),
help: None,
}

Expand All @@ -151,4 +151,46 @@ create_messages!(
msg: format!("Compiled file at `{path}` does not exist, cannot compile parent."),
help: Some("If you were using the `--non-recursive` flag, remove it and try again.".to_string()),
}

@backtraced
invalid_input_id_len {
args: (input: impl Display, expected_type: impl Display),
msg: format!("Invalid input: {input}."),
help: Some(format!("Type `{expected_type}` must contain exactly 61 lowercase characters or numbers.")),
}

@backtraced
invalid_input_id {
args: (input: impl Display, expected_type: impl Display, expected_preface: impl Display),
msg: format!("Invalid input: {input}."),
help: Some(format!("Type `{expected_type}` must start with \"{expected_preface}\".")),
}

@backtraced
invalid_numerical_input {
args: (input: impl Display),
msg: format!("Invalid numerical input: {input}."),
help: Some("Input must be a valid u32.".to_string()),
}

@backtraced
invalid_range {
args: (),
msg: "The range must be less than or equal to 50 blocks.".to_string(),
help: None,
}

@backtraced
invalid_height_or_hash {
args: (input: impl Display),
msg: format!("Invalid input: {input}."),
help: Some("Input must be a valid height or hash. Valid hashes are 61 characters long, composed of only numbers and lower case letters, and be prefaced with \"ab1\".".to_string()),
}

@backtraced
invalid_field {
args: (field: impl Display),
msg: format!("Invalid field: {field}."),
help: Some("Field element must be numerical string with optional \"field\" suffix.".to_string()),
}
);
35 changes: 27 additions & 8 deletions leo/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ pub struct CLI {
#[clap(subcommand)]
command: Commands,

#[clap(long, global = true, help = "Optional path to Leo program root folder")]
#[clap(long, global = true, help = "Path to Leo program root folder")]
path: Option<PathBuf>,

#[clap(long, global = true, help = "Optional path to aleo program registry.")]
#[clap(long, global = true, help = "Path to aleo program registry")]
pub home: Option<PathBuf>,
}

Expand All @@ -48,11 +48,6 @@ enum Commands {
#[clap(subcommand)]
command: Account,
},
#[clap(about = "Add a new on-chain or local dependency to the current package.")]
Add {
#[clap(flatten)]
command: Add,
},
#[clap(about = "Create a new Leo package in a new directory")]
New {
#[clap(flatten)]
Expand All @@ -78,12 +73,26 @@ enum Commands {
#[clap(flatten)]
command: Deploy,
},

#[clap(about = "Query live data from the Aleo network")]
Query {
#[clap(flatten)]
command: Query,
},
#[clap(about = "Compile the current package as a program")]
Build {
#[clap(flatten)]
command: Build,
},
#[clap(about = "Add a new on-chain or local dependency to the current package.")]
Add {
#[clap(flatten)]
command: Add,
},
#[clap(about = "Remove a dependency from the current package.")]
Remove {
#[clap(flatten)]
command: Remove,
},
#[clap(about = "Clean the output directory")]
Clean {
#[clap(flatten)]
Expand Down Expand Up @@ -140,11 +149,13 @@ pub fn run_with_args(cli: CLI) -> Result<()> {

command.try_execute(context)
}
Commands::Query { command } => command.try_execute(context),
Commands::Clean { command } => command.try_execute(context),
Commands::Deploy { command } => command.try_execute(context),
Commands::Example { command } => command.try_execute(context),
Commands::Run { command } => command.try_execute(context),
Commands::Execute { command } => command.try_execute(context),
Commands::Remove { command } => command.try_execute(context),
Commands::Update { command } => command.try_execute(context),
}
}
Expand Down Expand Up @@ -401,6 +412,7 @@ function external_nested_function:
name: "nested_example_layer_0".to_string(),
local: None,
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(project_directory.clone()),
Expand Down Expand Up @@ -494,6 +506,7 @@ program child.aleo {
name: "parent".to_string(),
local: Some(parent_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(grandparent_directory.clone()),
Expand All @@ -508,6 +521,7 @@ program child.aleo {
name: "child".to_string(),
local: Some(child_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(grandparent_directory.clone()),
Expand All @@ -522,6 +536,7 @@ program child.aleo {
name: "child".to_string(),
local: Some(child_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(parent_directory.clone()),
Expand Down Expand Up @@ -645,6 +660,7 @@ program outer.aleo {
name: "inner_1".to_string(),
local: Some(inner_1_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(outer_directory.clone()),
Expand All @@ -659,6 +675,7 @@ program outer.aleo {
name: "inner_2".to_string(),
local: Some(inner_2_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(outer_directory.clone()),
Expand Down Expand Up @@ -812,6 +829,7 @@ program outer_2.aleo {
name: "inner_1".to_string(),
local: Some(inner_1_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(outer_directory.clone()),
Expand All @@ -826,6 +844,7 @@ program outer_2.aleo {
name: "inner_2".to_string(),
local: Some(inner_2_directory.clone()),
network: "testnet3".to_string(),
clear: false,
},
},
path: Some(outer_directory.clone()),
Expand Down
72 changes: 54 additions & 18 deletions leo/cli/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@ use super::*;
use leo_retriever::{Dependency, Location, Manifest, Network};
use std::path::PathBuf;

/// Clean outputs folder command
/// Add a new on-chain or local dependency to the current package.
#[derive(Parser, Debug)]
#[clap(name = "leo", author = "The Aleo Team <[email protected]>", version)]
pub struct Add {
#[clap(name = "NAME", help = "The dependency name")]
#[clap(name = "NAME", help = "The dependency name. Ex: `credits.aleo` or `credits`.")]
pub(crate) name: String,

#[clap(short = 'l', long, help = "Optional path to local dependency")]
#[clap(short = 'l', long, help = "Path to local dependency")]
pub(crate) local: Option<PathBuf>,

#[clap(short = 'n', long, help = "Optional name of the network to use", default_value = "testnet3")]
#[clap(short = 'n', long, help = "Name of the network to use", default_value = "testnet3")]
pub(crate) network: String,

#[clap(short = 'c', long, help = "Clear all previous dependencies.", default_value = "false")]
pub(crate) clear: bool,
}

impl Command for Add {
Expand All @@ -47,41 +50,74 @@ impl Command for Add {
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
let path = context.dir()?;

// Deserialize the manifest
// Deserialize the manifest.
let program_data: String = std::fs::read_to_string(path.join("program.json"))
.map_err(|err| PackageError::failed_to_read_file(path.to_str().unwrap(), err))?;
let manifest: Manifest = serde_json::from_str(&program_data)
.map_err(|err| PackageError::failed_to_deserialize_manifest_file(path.to_str().unwrap(), err))?;

// Allow both `credits.aleo` and `credits` syntax
let name = match self.name {
name if name.ends_with(".aleo") => name,
name => format!("{}.aleo", name),
// Make sure the program name is valid.
// Allow both `credits.aleo` and `credits` syntax.
let name: String = match &self.name {
name if name.ends_with(".aleo")
&& Package::<CurrentNetwork>::is_aleo_name_valid(&name[0..self.name.len() - 5]) =>
{
name.clone()
}
name if Package::<CurrentNetwork>::is_aleo_name_valid(name) => format!("{name}.aleo"),
name => return Err(PackageError::invalid_file_name_dependency(name).into()),
};

// Add dependency section to manifest if it doesn't exist
let mut dependencies = match manifest.dependencies() {
Some(ref dependencies) => dependencies
// Add dependency section to manifest if it doesn't exist.
let mut dependencies = match (self.clear, manifest.dependencies()) {
(false, Some(ref dependencies)) => dependencies
.iter()
.filter_map(|dependency| {
// Overwrite old dependencies of the same name.
if dependency.name() == &name {
println!("{} already exists as a dependency. Overwriting.", name);
let msg = match (dependency.path(), dependency.network()) {
(Some(local_path), _) => {
format!("local dependency at path `{}`", local_path.to_str().unwrap().replace('\"', ""))
}
(_, Some(network)) => {
format!("network dependency from `{}`", network)
}
_ => "git dependency".to_string(),
};
tracing::warn!("⚠️ Program `{name}` already exists as a {msg}. Overwriting.");
None
} else if self.local.is_some() && &self.local == dependency.path() {
// Overwrite old dependencies at the same local path.
tracing::warn!(
"⚠️ Path `{}` already exists as the location for local dependency `{}`. Overwriting.",
self.local.clone().unwrap().to_str().unwrap().replace('\"', ""),
dependency.name()
);
None
} else {
Some(dependency.clone())
}
})
.collect(),
None => Vec::new(),
_ => Vec::new(),
};

// Add new dependency to manifest
// Add new dependency to the manifest.
dependencies.push(match self.local {
Some(local_path) => Dependency::new(name, Location::Local, None, Some(local_path)),
None => Dependency::new(name, Location::Network, Some(Network::from(&self.network)), None),
Some(local_path) => {
tracing::info!(
"✅ Added local dependency to program `{name}` at path `{}`.",
local_path.to_str().unwrap().replace('\"', "")
);
Dependency::new(name, Location::Local, None, Some(local_path))
}
None => {
tracing::info!("✅ Added network dependency to program `{name}` from network `{}`.", self.network);
Dependency::new(name, Location::Network, Some(Network::from(&self.network)), None)
}
});

// Update manifest
// Update the manifest file.
let new_manifest = Manifest::new(
manifest.program(),
manifest.version(),
Expand Down
8 changes: 2 additions & 6 deletions leo/cli/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,6 @@ fn compile_leo_file(
options: BuildOptions,
stubs: IndexMap<Symbol, Stub>,
) -> Result<()> {
// Construct the Leo file name with extension `foo.leo`.
let file_name =
file_path.file_name().and_then(|name| name.to_str()).ok_or_else(PackageError::failed_to_get_file_name)?;

// Construct program name from the program_id found in `package.json`.
let program_name = program_id.name().to_string();

Expand All @@ -206,7 +202,7 @@ fn compile_leo_file(

// Create a new instance of the Leo compiler.
let mut compiler = Compiler::new(
program_name,
program_name.clone(),
program_id.network().to_string(),
handler,
file_path.clone(),
Expand All @@ -224,6 +220,6 @@ fn compile_leo_file(
.write_all(instructions.as_bytes())
.map_err(CliError::failed_to_load_instructions)?;

tracing::info!("✅ Compiled '{}' into Aleo instructions", file_name);
tracing::info!("✅ Compiled '{program_name}.aleo' into Aleo instructions");
Ok(())
}
6 changes: 6 additions & 0 deletions leo/cli/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,18 @@ pub use example::Example;
pub mod execute;
pub use execute::Execute;

pub mod query;
pub use query::Query;

pub mod new;
pub use new::New;

// pub mod node;
// pub use node::Node;

pub mod remove;
pub use remove::Remove;

pub mod run;
pub use run::Run;

Expand Down
Loading

0 comments on commit a0cdafc

Please sign in to comment.