97 lines
2.9 KiB
Rust
97 lines
2.9 KiB
Rust
use anyhow::{anyhow, Context, Result};
|
|
use regex::Regex;
|
|
use std::{path::PathBuf, pin::Pin};
|
|
use tokio::pin;
|
|
|
|
use futures_util::stream::StreamExt;
|
|
|
|
use crate::common::{read_file_by_lines, AppConfig, VarsMap};
|
|
|
|
pub(crate) struct VarsFile {
|
|
pub(crate) filepath: PathBuf,
|
|
pub(crate) vars: Option<VarsMap>,
|
|
pub(crate) encoding: String,
|
|
}
|
|
|
|
impl VarsFile {
|
|
async fn from_file(filepath: &PathBuf, encoding: String) -> Result<Self> {
|
|
let metadata = tokio::fs::metadata(&filepath).await.context(format!(
|
|
"file not found {}",
|
|
filepath.to_str().expect("str")
|
|
))?;
|
|
if !metadata.is_file() {
|
|
Err(anyhow!("{} is not a file", filepath.to_str().expect("str")))?
|
|
}
|
|
Ok(VarsFile {
|
|
filepath: filepath.to_path_buf(),
|
|
vars: None,
|
|
encoding,
|
|
})
|
|
}
|
|
|
|
async fn from_dir(dir: PathBuf, encoding: String) -> Result<Self> {
|
|
let filepath = dir.join("vars");
|
|
let err_context = format!(
|
|
"vars or vars.bat file not found in {}",
|
|
dir.to_str().expect("str")
|
|
);
|
|
|
|
match Self::from_file(&filepath, encoding.clone()).await {
|
|
Ok(res) => Ok(res),
|
|
Err(_) => Self::from_file(&filepath.with_extension("bat"), encoding.clone())
|
|
.await
|
|
.map_err(|e| e.context(err_context)),
|
|
}
|
|
}
|
|
|
|
pub(crate) async fn from_config(config: &AppConfig) -> Result<Self> {
|
|
Self::from_dir(
|
|
PathBuf::from(&config.base_directory),
|
|
config.encoding.clone(),
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub(crate) async fn parse(&mut self) -> Result<()> {
|
|
let mut result = VarsMap::new();
|
|
let lines = read_file_by_lines(&self.filepath, &self.encoding).await?;
|
|
let lines = Pin::from(lines);
|
|
pin!(lines);
|
|
|
|
let re_v2 =
|
|
Regex::new(r#"^(export|set)\s\b(?P<key>[\w\d_]+)\b=\s?"?(?P<value>[^\#]+?)"?$"#)
|
|
.context("regex v2")?;
|
|
let re_v3 = Regex::new(r"^set_var\s(?P<key1>[\w\d_]+)\s+(?P<value1>[^\#]+?)$")
|
|
.context("regex v3")?;
|
|
|
|
while let Some(line) = lines.next().await {
|
|
if let Some(caps) = re_v2.captures(line.as_str()) {
|
|
result.insert(caps["key"].to_string(), caps["value"].to_string());
|
|
continue;
|
|
}
|
|
|
|
if let Some(caps) = re_v3.captures(line.as_str()) {
|
|
result.insert(caps["key"].to_string(), caps["value"].to_string());
|
|
};
|
|
}
|
|
|
|
self.vars = Some(result);
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn apply(&self) -> Result<()> {
|
|
if let Some(vars) = self.vars.clone() {
|
|
for (key, value) in vars.iter() {
|
|
unsafe {
|
|
std::env::set_var(key, value);
|
|
}
|
|
}
|
|
} else {
|
|
Err(anyhow!("vars not parsed"))?
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|