image_optimizer/file_ops/output_manager.rs
1use anyhow::Result;
2use std::path::{Path, PathBuf};
3
4/// Ensures the output directory structure exists and returns the output file path.
5///
6/// This function creates the necessary directory structure in the output directory
7/// to mirror the input directory structure, then returns the full path where the
8/// optimized file should be written.
9///
10/// # Arguments
11///
12/// * `output_path` - Base output directory path
13/// * `input_path` - Base input directory path (used to calculate relative paths)
14/// * `file_path` - Path to the specific file being processed
15///
16/// # Returns
17///
18/// Returns the full `PathBuf` where the optimized file should be written.
19///
20/// # Errors
21///
22/// Returns an error if:
23/// - Path stripping fails (`file_path` is not under `input_path`)
24/// - Directory creation fails due to permissions or I/O errors
25///
26/// # Examples
27///
28/// ```rust
29/// use std::path::Path;
30/// use image_optimizer::file_ops::ensure_output_dir;
31///
32/// # fn example() -> anyhow::Result<()> {
33/// let output_dir = Path::new("./optimized");
34/// let input_dir = Path::new("./photos");
35/// let file_path = Path::new("./photos/subfolder/image.jpg");
36///
37/// let output_file = ensure_output_dir(output_dir, input_dir, file_path)?;
38/// // Returns: "./optimized/subfolder/image.jpg"
39/// # Ok(())
40/// # }
41/// ```
42pub fn ensure_output_dir(
43 output_path: &Path,
44 input_path: &Path,
45 file_path: &Path,
46) -> Result<PathBuf> {
47 let relative_path = file_path.strip_prefix(input_path)?;
48 let output_file_path = output_path.join(relative_path);
49
50 if let Some(parent) = output_file_path.parent() {
51 std::fs::create_dir_all(parent)?;
52 }
53
54 Ok(output_file_path)
55}