leo_lang/cli/helpers/
context.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use aleo_std;
18use leo_errors::{CliError, Result};
19use leo_package::Manifest;
20
21use aleo_std::aleo_dir;
22use snarkvm::prelude::{Network, PrivateKey};
23use std::{env::current_dir, path::PathBuf, str::FromStr};
24
25/// Project context, manifest, current directory etc
26/// All the info that is relevant in most of the commands
27// TODO: Make `path` and `home` not pub, to prevent misuse through direct access.
28#[derive(Clone)]
29pub struct Context {
30    /// Path at which the command is called, None when default
31    pub path: Option<PathBuf>,
32    /// Path to use for the Aleo registry, None when default
33    pub home: Option<PathBuf>,
34    /// Recursive flag.
35    // TODO: Shift from callee to caller by including display method
36    pub recursive: bool,
37}
38
39impl Context {
40    pub fn new(path: Option<PathBuf>, home: Option<PathBuf>, recursive: bool) -> Result<Context> {
41        Ok(Context { path, home, recursive })
42    }
43
44    /// Returns the path of the parent directory to the Leo package.
45    pub fn parent_dir(&self) -> Result<PathBuf> {
46        match &self.path {
47            Some(path) => {
48                let mut path = path.clone();
49                path.pop();
50                Ok(path)
51            }
52            None => Ok(current_dir().map_err(CliError::cli_io_error)?),
53        }
54    }
55
56    /// Returns the path to the Leo package.
57    pub fn dir(&self) -> Result<PathBuf> {
58        match &self.path {
59            Some(path) => Ok(path.clone()),
60            None => Ok(current_dir().map_err(CliError::cli_io_error)?),
61        }
62    }
63
64    /// Returns the path to the Aleo registry directory.
65    pub fn home(&self) -> Result<PathBuf> {
66        match &self.home {
67            Some(path) => Ok(path.clone()),
68            None => Ok(aleo_dir()),
69        }
70    }
71
72    /// Opens the manifest file `program.json`.
73    pub fn open_manifest(&self) -> Result<Manifest> {
74        let path = self.dir()?;
75        let manifest_path = path.join(leo_package::MANIFEST_FILENAME);
76        let manifest = Manifest::read_from_file(manifest_path)?;
77        Ok(manifest)
78    }
79
80    /// Returns the private key from the .env file specified in the directory.
81    pub fn dotenv_private_key<N: Network>(&self) -> Result<PrivateKey<N>> {
82        dotenvy::from_path(self.dir()?.join(".env")).map_err(|_| CliError::failed_to_get_private_key_from_env())?;
83        // Load the private key from the environment.
84        let private_key = dotenvy::var("PRIVATE_KEY").map_err(|_| CliError::failed_to_get_private_key_from_env())?;
85        // Parse the private key.
86        Ok(PrivateKey::<N>::from_str(&private_key)?)
87    }
88
89    /// Returns the endpoint from the .env file specified in the directory.
90    pub fn dotenv_endpoint(&self) -> Result<String> {
91        dotenvy::from_path(self.dir()?.join(".env")).map_err(|_| CliError::failed_to_get_endpoint_from_env())?;
92        // Load the endpoint from the environment.
93        Ok(dotenvy::var("ENDPOINT").map_err(|_| CliError::failed_to_get_endpoint_from_env())?)
94    }
95
96    /// Returns the network from the .env file specified in the directory.
97    pub fn dotenv_network(&self) -> Result<String> {
98        dotenvy::from_path(self.dir()?.join(".env")).map_err(|_| CliError::failed_to_get_network_from_env())?;
99        // Load the network from the environment.
100        Ok(dotenvy::var("NETWORK").map_err(|_| CliError::failed_to_get_network_from_env())?)
101    }
102
103    /// Returns the endpoint to interact with the network.
104    /// If the `--endpoint` options is not provided, it will default to the one in the `.env` file.
105    pub fn get_endpoint(&self, endpoint: &Option<String>) -> Result<String> {
106        match endpoint {
107            Some(endpoint) => Ok(endpoint.clone()),
108            None => Ok(self.dotenv_endpoint()?),
109        }
110    }
111
112    /// Returns the network name.
113    /// If the `--network` options is not provided, it will default to the one in the `.env` file.
114    pub fn get_network(&self, network: &Option<String>) -> Result<String> {
115        match network {
116            Some(network) => Ok(network.clone()),
117            None => Ok(self.dotenv_network()?),
118        }
119    }
120
121    /// Returns the private key.
122    /// If the `--private-key` options is not provided, it will default to the one in the `.env` file.
123    pub fn get_private_key<N: Network>(&self, private_key: &Option<String>) -> Result<PrivateKey<N>> {
124        match private_key {
125            Some(private_key) => Ok(PrivateKey::<N>::from_str(private_key)?),
126            None => self.dotenv_private_key(),
127        }
128    }
129}