leo_lang/cli/commands/
debug.rs1use leo_package::{Package, ProgramData};
18use leo_span::Symbol;
19
20use snarkvm::prelude::TestnetV0;
21
22use indexmap::IndexSet;
23use std::path::PathBuf;
24
25use super::*;
26
27#[derive(Parser, Debug)]
29pub struct LeoDebug {
30 #[arg(long, help = "Use these source files instead of finding source files through the project structure.", num_args = 1..)]
31 pub(crate) paths: Vec<String>,
32 #[arg(long, help = "The block height, accessible via block.height.", default_value = "0")]
33 pub(crate) block_height: u32,
34 #[arg(long, action, help = "Use the text user interface.")]
35 pub(crate) tui: bool,
36 #[clap(flatten)]
37 pub(crate) compiler_options: BuildOptions,
38 #[clap(flatten)]
39 pub(crate) env_override: EnvOptions,
40}
41
42impl Command for LeoDebug {
43 type Input = Option<Package>;
44 type Output = ();
45
46 fn log_span(&self) -> Span {
47 tracing::span!(tracing::Level::INFO, "Leo")
48 }
49
50 fn prelude(&self, context: Context) -> Result<Self::Input> {
51 if self.paths.is_empty() {
52 let package = LeoBuild { options: self.compiler_options.clone(), env_override: self.env_override.clone() }
53 .execute(context)?;
54 Ok(Some(package))
55 } else {
56 Ok(None)
57 }
58 }
59
60 fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output> {
61 handle_debug(&self, context, input)
62 }
63}
64
65fn handle_debug(command: &LeoDebug, context: Context, package: Option<Package>) -> Result<()> {
66 if command.paths.is_empty() {
67 let package = package.unwrap();
68
69 let private_key = context.get_private_key(&None)?;
71 let address = Address::try_from(&private_key)?;
72
73 let local_dependency_paths: Vec<PathBuf> = package
75 .programs
76 .iter()
77 .flat_map(|program| match &program.data {
78 ProgramData::SourcePath(path) => Some(path.clone()),
79 ProgramData::Bytecode(..) => None,
80 })
81 .collect();
82
83 let local_dependency_symbols: IndexSet<Symbol> = package
84 .programs
85 .iter()
86 .flat_map(|program| match &program.data {
87 ProgramData::SourcePath(..) => {
88 Some(program.name)
90 }
91 ProgramData::Bytecode(..) => {
92 None
94 }
95 })
96 .collect();
97
98 let imports_directory = package.imports_directory();
99
100 let aleo_paths: Vec<PathBuf> = imports_directory
102 .read_dir()
103 .ok()
104 .into_iter()
105 .flatten()
106 .flat_map(|maybe_filename| maybe_filename.ok())
107 .filter(|entry| entry.file_type().ok().map(|filetype| filetype.is_file()).unwrap_or(false))
108 .flat_map(|entry| {
109 let path = entry.path();
110 if let Some(filename) = leo_package::filename_no_aleo_extension(&path) {
111 let symbol = Symbol::intern(filename);
112 if local_dependency_symbols.contains(&symbol) { None } else { Some(path) }
113 } else {
114 None
115 }
116 })
117 .collect();
118
119 std::mem::drop(package);
121
122 leo_interpreter::interpret(&local_dependency_paths, &aleo_paths, address, command.block_height, command.tui)
123 } else {
124 let private_key: PrivateKey<TestnetV0> = PrivateKey::from_str(leo_package::TEST_PRIVATE_KEY)?;
125 let address = Address::try_from(&private_key)?;
126
127 let leo_paths: Vec<PathBuf> = command
128 .paths
129 .iter()
130 .filter(|path_str| path_str.ends_with(".leo"))
131 .map(|path_str| path_str.into())
132 .collect();
133 let aleo_paths: Vec<PathBuf> = command
134 .paths
135 .iter()
136 .filter(|path_str| !path_str.ends_with(".leo"))
137 .map(|path_str| path_str.into())
138 .collect();
139
140 leo_interpreter::interpret(&leo_paths, &aleo_paths, address, command.block_height, command.tui)
141 }
142}