leo_package/
env.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 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 contents = std::fs::read_to_string(&path)
44            .map_err(|e| PackageError::failed_to_read_file(path.as_ref().display(), e))?;
45        let mut network: Option<String> = None;
46        let mut private_key: Option<String> = None;
47        let mut endpoint: Option<String> = None;
48
49        for line in contents.lines() {
50            if let Some((lhs, rhs)) = line.split_once('=') {
51                match lhs.trim() {
52                    "NETWORK" => network = Some(rhs.to_string()),
53                    "PRIVATE_KEY" => private_key = Some(rhs.to_string()),
54                    "ENDPOINT" => endpoint = Some(rhs.to_string()),
55                    _ => {}
56                }
57            }
58        }
59
60        for (variable, name) in
61            [(&mut network, "NETWORK"), (&mut private_key, "PRIVATE_KEY"), (&mut endpoint, "ENDPOINT")]
62        {
63            if let Ok(env_var_value) = std::env::var(name) {
64                if !env_var_value.is_empty() {
65                    *variable = Some(env_var_value);
66                }
67            }
68        }
69
70        let network: Option<NetworkName> = network.and_then(|net| net.parse().ok());
71
72        match (network, private_key, endpoint) {
73            (Some(network), Some(private_key), Some(endpoint)) => Ok(Env { network, private_key, endpoint }),
74            (None, _, _) => Err(CliError::failed_to_get_network_from_env().into()),
75            (_, None, _) => Err(CliError::failed_to_get_private_key_from_env().into()),
76            (_, _, None) => Err(CliError::failed_to_get_endpoint_from_env().into()),
77        }
78    }
79}
80
81impl fmt::Display for Env {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "NETWORK={}\nPRIVATE_KEY={}\nENDPOINT={}\n", self.network, self.private_key, self.endpoint)
84    }
85}