spring_boot/config/
env.rs1use crate::error::{AppError, Result};
2use anyhow::Context;
3use std::{
4 env,
5 ffi::OsStr,
6 io::ErrorKind,
7 path::{Path, PathBuf},
8};
9
10#[derive(Debug)]
12pub enum Env {
13 Dev,
15 Test,
17 Prod,
19}
20
21impl Env {
22 pub fn from_env() -> Self {
23 match env::var("SPRING_ENV") {
24 Ok(var) => Self::from_string(var),
25 Err(_) => Self::Dev,
26 }
27 }
28
29 pub fn from_string<S: Into<String>>(str: S) -> Self {
30 match str.into() {
31 s if s.eq_ignore_ascii_case("dev") => Self::Dev,
32 s if s.eq_ignore_ascii_case("test") => Self::Test,
33 s if s.eq_ignore_ascii_case("prod") => Self::Prod,
34 _ => Self::Dev,
35 }
36 }
37
38 pub(crate) fn get_config_path(&self, path: &Path) -> Result<PathBuf> {
39 let stem = path.file_stem().and_then(OsStr::to_str).unwrap_or("");
40 let ext = path.extension().and_then(OsStr::to_str).unwrap_or("");
41 let canonicalize = path
42 .canonicalize()
43 .with_context(|| format!("canonicalize {:?} failed", path))?;
44 let parent = canonicalize
45 .parent()
46 .ok_or_else(|| AppError::from_io(ErrorKind::NotFound, "config file path not found"))?;
47 Ok(match self {
48 Self::Dev => parent.join(format!("{}-dev.{}", stem, ext)),
49 Self::Test => parent.join(format!("{}-test.{}", stem, ext)),
50 Self::Prod => parent.join(format!("{}-prod.{}", stem, ext)),
51 })
52 }
53}
54
55pub fn init() -> Result<Env> {
56 match dotenvy::dotenv() {
57 Ok(path) => log::debug!(
58 "Loaded the environment variable file under the path: \"{:?}\"",
59 path
60 ),
61 Err(e) => log::debug!("Environment variable file not found: {}", e),
62 }
63
64 Ok(Env::from_env())
65}
66
67mod tests {
68 #[allow(unused_imports)]
69 use super::Env;
70 use crate::error::Result;
71 use std::{fs, path::PathBuf};
72
73 #[test]
74 fn test_get_config_path() -> Result<()> {
75 let temp_dir = tempfile::tempdir()?;
76
77 let foo = temp_dir.path().join("foo.toml");
78 let _ = touch(&foo);
79
80 assert_eq!(
81 Env::from_string("dev").get_config_path(&foo.as_path())?,
82 temp_dir.path().join("foo-dev.toml")
83 );
84
85 assert_eq!(
86 Env::from_string("test").get_config_path(&foo.as_path())?,
87 temp_dir.path().join("foo-test.toml")
88 );
89
90 assert_eq!(
91 Env::from_string("prod").get_config_path(&foo.as_path())?,
92 temp_dir.path().join("foo-prod.toml")
93 );
94
95 assert_eq!(
96 Env::from_string("other").get_config_path(&foo.as_path())?,
97 temp_dir.path().join("foo-dev.toml")
98 );
99
100 Ok(())
101 }
102
103 #[test]
104 fn test_env() -> Result<()> {
105 let temp_dir = tempfile::tempdir()?;
106 let foo = temp_dir.path().join("foo.toml");
107 let _ = touch(&foo);
108
109 std::env::set_var("SPRING_ENV", "dev");
110 assert_eq!(
111 Env::from_env().get_config_path(&foo.as_path())?,
112 temp_dir.path().join("foo-dev.toml")
113 );
114
115 std::env::set_var("SPRING_ENV", "TEST");
116 assert_eq!(
117 Env::from_env().get_config_path(&foo.as_path())?,
118 temp_dir.path().join("foo-test.toml")
119 );
120
121 std::env::set_var("SPRING_ENV", "Prod");
122 assert_eq!(
123 Env::from_env().get_config_path(&foo.as_path())?,
124 temp_dir.path().join("foo-prod.toml")
125 );
126
127 std::env::set_var("SPRING_ENV", "Other");
128 assert_eq!(
129 Env::from_env().get_config_path(&foo.as_path())?,
130 temp_dir.path().join("foo-dev.toml")
131 );
132
133 Ok(())
134 }
135
136 #[allow(dead_code)]
137 fn touch(path: &PathBuf) -> Result<()> {
138 let _ = fs::OpenOptions::new()
139 .truncate(true)
140 .create(true)
141 .write(true)
142 .open(path)?;
143 Ok(())
144 }
145}