leo_lang/cli/commands/
add.rs1use super::*;
18use leo_package::{Dependency, Location, Manifest};
19use std::path::PathBuf;
20
21#[derive(Parser, Debug)]
23#[clap(name = "leo", author = "The Leo Team <leo@provable.com>", version)]
24pub struct LeoAdd {
25 #[clap(name = "NAME", help = "The dependency name. Ex: `credits.aleo` or `credits`.")]
26 pub(crate) name: String,
27
28 #[clap(flatten)]
29 pub(crate) source: DependencySource,
30
31 #[clap(short = 'c', long, help = "Clear all previous dependencies.", default_value = "false")]
32 pub(crate) clear: bool,
33
34 #[clap(long, help = "This is a development dependency.", default_value = "false")]
35 pub(crate) dev: bool,
36}
37
38#[derive(Parser, Debug)]
39#[group(required = true, multiple = false)]
40pub struct DependencySource {
41 #[clap(short = 'l', long, help = "Whether the dependency is local to the machine.", group = "source")]
42 pub(crate) local: Option<PathBuf>,
43
44 #[clap(short = 'n', long, help = "Whether the dependency is on a live network.", group = "source")]
45 pub(crate) network: bool,
46}
47
48impl Command for LeoAdd {
49 type Input = ();
50 type Output = ();
51
52 fn log_span(&self) -> Span {
53 tracing::span!(tracing::Level::INFO, "Leo")
54 }
55
56 fn prelude(&self, _: Context) -> Result<Self::Input> {
57 Ok(())
58 }
59
60 fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
61 let path = context.dir()?;
62
63 let manifest_path = path.join(leo_package::MANIFEST_FILENAME);
64 let mut manifest = Manifest::read_from_file(&manifest_path)?;
65
66 let name = if self.name.ends_with(".aleo") { self.name.clone() } else { format!("{}.aleo", self.name) };
69
70 if !leo_package::is_valid_aleo_name(&name) {
71 return Err(CliError::invalid_program_name(name).into());
72 }
73
74 let new_dependency = Dependency {
75 name: name.clone(),
76 location: if self.source.local.is_some() { Location::Local } else { Location::Network },
77 path: self.source.local.clone(),
78 };
79
80 let deps = if self.dev { &mut manifest.dev_dependencies } else { &mut manifest.dependencies };
81
82 if let Some(matched_dep) = deps.get_or_insert_default().iter_mut().find(|dep| dep.name == new_dependency.name) {
83 if let Some(path) = &matched_dep.path {
84 tracing::warn!(
85 "⚠️ Program `{name}` already exists as a local dependency at `{}`. Overwriting.",
86 path.display()
87 );
88 } else {
89 tracing::warn!("⚠️ Program `{name}` already exists as a network dependency. Overwriting.");
90 }
91 *matched_dep = new_dependency;
92 } else {
93 deps.as_mut().unwrap().push(new_dependency);
94 if let Some(path) = self.source.local.as_ref() {
95 tracing::info!("✅ Added local dependency to program `{name}` at path `{}`.", path.display());
96 } else {
97 tracing::info!("✅ Added network dependency `{name}` from network `{}`.", self.source.network);
98 }
99 }
100
101 manifest.write_to_file(manifest_path)?;
102
103 Ok(())
104 }
105}