quartz_cli/
env.rs

1use std::{
2    collections::HashMap,
3    fmt::Display,
4    io::Write,
5    ops::{Deref, DerefMut},
6    path::PathBuf,
7};
8
9use serde::{Deserialize, Serialize};
10
11use crate::{cookie::CookieJar, endpoint::Headers, Ctx, PairMap};
12
13#[derive(Default, Debug, Clone, Serialize, Deserialize)]
14pub struct Variables(pub HashMap<String, String>);
15
16impl Deref for Variables {
17    type Target = HashMap<String, String>;
18
19    fn deref(&self) -> &Self::Target {
20        &self.0
21    }
22}
23
24impl DerefMut for Variables {
25    fn deref_mut(&mut self) -> &mut Self::Target {
26        &mut self.0
27    }
28}
29
30impl Display for Variables {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        for (key, value) in self.iter() {
33            writeln!(f, "{key}={value}")?;
34        }
35
36        Ok(())
37    }
38}
39
40impl PairMap<'_> for Variables {
41    const NAME: &'static str = "variable";
42
43    fn map(&mut self) -> &mut HashMap<String, String> {
44        &mut self.0
45    }
46}
47
48impl Variables {
49    pub fn parse(file_content: &str) -> Self {
50        let mut variables = Variables::default();
51
52        for var in file_content.split('\n').filter(|line| !line.is_empty()) {
53            variables.set(var);
54        }
55
56        variables
57    }
58}
59
60#[derive(Clone, Serialize, Deserialize)]
61pub struct Env {
62    pub name: String,
63    pub variables: Variables,
64    pub headers: Headers,
65}
66
67impl Default for Env {
68    fn default() -> Self {
69        Self {
70            name: String::from("default"),
71            variables: Variables::default(),
72            headers: Headers::default(),
73        }
74    }
75}
76
77impl Env {
78    pub fn new(name: &str) -> Self {
79        Self {
80            name: name.to_string(),
81            ..Default::default()
82        }
83    }
84
85    pub fn dir(&self, ctx: &Ctx) -> PathBuf {
86        ctx.path().join("env").join(&self.name)
87    }
88
89    pub fn write(&self, ctx: &Ctx) -> Result<(), Box<dyn std::error::Error>> {
90        let dir = self.dir(ctx);
91
92        std::fs::create_dir(dir)?;
93
94        self.update(ctx)?;
95
96        Ok(())
97    }
98
99    pub fn update(&self, ctx: &Ctx) -> Result<(), Box<dyn std::error::Error>> {
100        let mut var_file = std::fs::OpenOptions::new()
101            .create(true)
102            .write(true)
103            .truncate(true)
104            .open(self.dir(ctx).join("variables"))?;
105        let mut headers_file = std::fs::OpenOptions::new()
106            .create(true)
107            .write(true)
108            .truncate(true)
109            .open(self.dir(ctx).join("headers"))?;
110
111        if !self.variables.is_empty() {
112            var_file.write_all(format!("{}", self.variables).as_bytes())?;
113        }
114        if !self.headers.0.is_empty() {
115            headers_file.write_all(format!("{}", self.headers).as_bytes())?;
116        }
117
118        Ok(())
119    }
120
121    /// Returns `true` if this environment already exists on the quartz project.
122    pub fn exists(&self, ctx: &Ctx) -> bool {
123        self.dir(ctx).exists()
124    }
125
126    pub fn parse(ctx: &Ctx, name: &str) -> Result<Self, Box<dyn std::error::Error>> {
127        let mut env = Self::new(name);
128
129        if let Ok(var_contents) = std::fs::read_to_string(env.dir(ctx).join("variables")) {
130            env.variables = Variables::parse(&var_contents);
131        }
132        if let Ok(header_contents) = std::fs::read_to_string(env.dir(ctx).join("headers")) {
133            env.headers = Headers::parse(&header_contents);
134        }
135
136        Ok(env)
137    }
138
139    pub fn cookie_jar(&self, ctx: &Ctx) -> CookieJar {
140        let path = self.dir(ctx).join(CookieJar::FILENAME);
141        let mut jar = CookieJar::read(&path).unwrap_or_default();
142
143        jar.path = path;
144
145        jar
146    }
147}