at e1dfdc3
use std::collections::HashMap; use std::path::{Path, PathBuf}; use flate2::Compression; use flate2::write::GzEncoder; use miette::{IntoDiagnostic, Result}; /// Expands shell-style variables in a path string. /// /// This function takes a path containing variables in `$VAR` or `${VAR}` syntax /// and substitutes them with values from the provided iterator of key-value pairs. /// Any variables not found in the provided mappings are left unchanged. /// /// # Generic Parameters /// /// * `P` - A type that can be converted to a `Path` /// * `I` - An iterator-like type that produces `(S, S)` tuples /// * `S` - A type that can be read as `&str` /// /// # Arguments /// /// * `path` - The path string or `Path` object containing variables /// * `vars` - An iterator of `(key, value)` pairs for variable substitution /// /// # Returns /// /// A `PathBuf` with all variables substituted with their corresponding values. /// /// # Examples /// /// ``` /// use std::collections::HashMap; /// /// let mut vars = HashMap::new(); /// vars.insert("USER", "john"); /// vars.insert("PROJECT", "rust"); /// /// let expanded = expand_variables("/home/$USER/$PROJECT", vars); /// assert_eq!(expanded.to_string_lossy(), "/home/john/rust"); /// ``` /// /// With a vector: /// /// ``` /// let vars = vec![("USER", "john"), ("PROJECT", "rust")]; /// let expanded = expand_variables("/home/$USER/${PROJECT}", vars); /// assert_eq!(expanded.to_string_lossy(), "/home/john/rust"); /// ``` pub fn expand_variables<P, I, S>(path: P, vars: I) -> PathBuf where P: AsRef<Path>, I: IntoIterator<Item = (S, S)>, S: AsRef<str>, { let mut path_str = path.as_ref().to_string_lossy().to_string(); // Convert iterator into a HashMap for efficient lookup let var_map: HashMap<String, String> = vars .into_iter() .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())) .collect(); // Replace each variable for (key, value) in var_map { path_str = path_str.replace(&format!("${{{}}}", key), &value); path_str = path_str.replace(&format!("${}", key), &value); } PathBuf::from(path_str) } /// Pack `src` directory into a `.tar.gz` archive at `dest`. /// /// The top-level entry inside the archive is named after the source directory. pub(crate) fn archive_dir(src: &Path, dest: &Path) -> Result<()> { let dir_name = src .file_name() .map(|n| n.to_string_lossy().into_owned()) .unwrap_or_else(|| "docs".to_owned()); let file = std::fs::File::create(dest).into_diagnostic()?; let enc = GzEncoder::new(file, Compression::default()); let mut archive = tar::Builder::new(enc); archive.append_dir_all(&dir_name, src).into_diagnostic()?; archive .into_inner() .into_diagnostic()? .finish() .into_diagnostic()?; Ok(()) }