1use crate::NetworkName;
18
19use leo_errors::{CliError, PackageError, Result};
20
21use std::{fmt, fs, path::Path};
22
23pub const ENV_FILENAME: &str = ".env";
24
25#[derive(Clone, Debug)]
26pub struct Env {
27 pub network: NetworkName,
28 pub private_key: String,
29 pub endpoint: String,
30}
31
32impl Env {
33 pub fn new(network: NetworkName, private_key: String, endpoint: String) -> Self {
34 Env { network, private_key, endpoint }
35 }
36
37 pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), PackageError> {
38 let contents = self.to_string();
39 fs::write(path, contents).map_err(PackageError::io_error_env_file)
40 }
41
42 pub fn read_from_file_or_environment<P: AsRef<Path>>(path: P) -> Result<Self> {
43 let path = path.as_ref().to_path_buf();
47 let mut contents = String::new();
48 let mut current_path = path;
49 while current_path.exists() {
50 let env_path = current_path.join(ENV_FILENAME);
51 if env_path.exists() {
52 contents = fs::read_to_string(env_path).map_err(PackageError::io_error_env_file)?;
53 break;
54 }
55 current_path = match current_path.parent() {
56 Some(parent) => parent.to_path_buf(),
57 None => break,
58 };
59 }
60
61 let mut network: Option<String> = None;
62 let mut private_key: Option<String> = None;
63 let mut endpoint: Option<String> = None;
64
65 for line in contents.lines() {
66 if let Some((lhs, rhs)) = line.split_once('=') {
67 match lhs.trim() {
68 "NETWORK" => network = Some(rhs.to_string()),
69 "PRIVATE_KEY" => private_key = Some(rhs.to_string()),
70 "ENDPOINT" => endpoint = Some(rhs.to_string()),
71 _ => {}
72 }
73 }
74 }
75
76 for (variable, name) in
77 [(&mut network, "NETWORK"), (&mut private_key, "PRIVATE_KEY"), (&mut endpoint, "ENDPOINT")]
78 {
79 if let Ok(env_var_value) = std::env::var(name) {
80 if !env_var_value.is_empty() {
81 *variable = Some(env_var_value);
82 }
83 }
84 }
85
86 let network: Option<NetworkName> = network.and_then(|net| net.parse().ok());
87
88 match (network, private_key, endpoint) {
89 (Some(network), Some(private_key), Some(endpoint)) => Ok(Env { network, private_key, endpoint }),
90 (None, _, _) => Err(CliError::failed_to_get_network_from_env().into()),
91 (_, None, _) => Err(CliError::failed_to_get_private_key_from_env().into()),
92 (_, _, None) => Err(CliError::failed_to_get_endpoint_from_env().into()),
93 }
94 }
95}
96
97impl fmt::Display for Env {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 write!(f, "NETWORK={}\nPRIVATE_KEY={}\nENDPOINT={}\n", self.network, self.private_key, self.endpoint)
100 }
101}