diff --git a/src/commands/pipeline.rs b/src/commands/pipeline.rs index 3d27ac69a68973adb17e15f004e90975b5189809..bf86883d9e24491bb658efc41a1c4923712ff274 100644 --- a/src/commands/pipeline.rs +++ b/src/commands/pipeline.rs @@ -7,6 +7,7 @@ use thiserror::Error; use crate::cli_args::CrunchCommand; use crate::format::make_paths; +use crate::utils::normalize_path; use crate::{commands, load_image}; #[derive(Error, Debug)] @@ -59,7 +60,7 @@ pub fn execute_pipeline<IN: ToString, OUT: ToString>( Err(PipelineError::FormatDetection)?; } - let file_contents = std::fs::read(path)?; + let file_contents = std::fs::read(&path)?; log::debug!("Found correct file type and read bytes, trying to parse"); let pipeline_data: PipelineFile = if path_string.ends_with(".toml") { @@ -69,188 +70,216 @@ pub fn execute_pipeline<IN: ToString, OUT: ToString>( }; log::debug!("Expanding pipeline file into targets"); - get_targets(&pipeline_data).for_each(|(input_path, output_path, actions)| { - match make_paths(&output_path) { - Ok(_) => {} - Err(e) => { - log::error!("Failed to create target directory {}; {}", &output_path, e); - return; - } - } - - if actions.is_empty() { - match std::fs::copy(&input_path, &output_path) { + let base_path = PathBuf::from(path.parent().unwrap()); + get_targets(base_path.clone(), &pipeline_data).for_each( + |(input_path, output_path, actions)| { + match make_paths(&output_path) { Ok(_) => {} Err(e) => { - log::error!("Failed to copy {} to {}; {}", input_path, output_path, e); + log::error!("Failed to create target directory {}; {}", &output_path, e); + return; } - }; - return; - } + } - let mut file = match load_image(&input_path, None) { - Ok(image) => image, - Err(e) => { - log::error!("Error loading {}; {:?}", &input_path, e); + if actions.is_empty() { + match std::fs::copy(&input_path, &output_path) { + Ok(_) => {} + Err(e) => { + log::error!("Failed to copy {} to {}; {}", input_path, output_path, e); + } + }; return; } - }; - log::debug!( - "Loaded {}, Executing {} actions", - &input_path, - actions.len() - ); - let mut count = 1; - for step in actions { - match step { - CrunchCommand::Extrude { - tile_size, - space_y, - space_x, - pad_y, - pad_x, - extrude, - } => { - file = match commands::extrude( - file, tile_size, pad_x, pad_y, space_x, space_y, extrude, - ) { - Ok(f) => f, - Err(e) => { - log::error!( - "Failed to extrude {} at step {}; {}", - input_path, - count, - e - ); - return; - } - }; + let mut file = match load_image(&input_path, None) { + Ok(image) => image, + Err(e) => { + log::error!("Error loading {}; {:?}", &input_path, e); + return; } - CrunchCommand::Remap { palette_file } => { - let palette_data = match load_image(&palette_file, None) { - Ok(p) => p, - Err(e) => { - log::error!("Failed to load {} at step {}; {:?}", input_path, count, e); - return; - } - }; + }; - let image_palette = match commands::palette(&file) { - Ok(ip) => ip, - Err(e) => { - log::error!( - "Failed to extract palette from {} at step {}; {}", - input_path, - count, - e - ); - return; - } - }; + log::debug!( + "Loaded {}, Executing {} actions", + &input_path, + actions.len() + ); + let mut count = 1; + for step in actions { + match step { + CrunchCommand::Extrude { + tile_size, + space_y, + space_x, + pad_y, + pad_x, + extrude, + } => { + file = match commands::extrude( + file, tile_size, pad_x, pad_y, space_x, space_y, extrude, + ) { + Ok(f) => f, + Err(e) => { + log::error!( + "Failed to extrude {} at step {}; {}", + input_path, + count, + e + ); + return; + } + }; + } + CrunchCommand::Remap { palette_file } => { + let palette_data = match load_image(join(&base_path, &palette_file), None) { + Ok(p) => p, + Err(e) => { + log::error!( + "Failed to load palette {} at step {}; {:?}", + &palette_file, + count, + e + ); + return; + } + }; - let target_palette = match commands::palette(&palette_data) { - Ok(tp) => tp, - Err(e) => { - log::error!( - "Failed to extract palette from {} at step {}; {}", - &palette_file, - count, - e - ); - return; - } - }; + let image_palette = match commands::palette(&file) { + Ok(ip) => ip, + Err(e) => { + log::error!( + "Failed to extract palette from {} at step {}; {}", + input_path, + count, + e + ); + return; + } + }; - let mappings = commands::calculate_mapping(&image_palette, &target_palette); - file = match commands::remap_image(file, mappings) { - Ok(f) => f, - Err(e) => { - log::error!("Failed to remap {} at step {}; {}", input_path, count, e); - return; - } - }; - } - CrunchCommand::Scale { factor } => { - file = match commands::rescale(&file, factor) { - Ok(f) => f, - Err(e) => { - log::error!("Failed to scale {} at step {}; {}", input_path, count, e); - return; - } - }; - } - CrunchCommand::Rotate { amount } => { - file = match commands::rotate(&file, amount) { - Ok(f) => f, - Err(e) => { - log::error!( - "Failed to rotate {} by {:?} step(s); {}", - input_path, - amount, - e - ); - return; - } - }; - } - CrunchCommand::Flip { direction } => { - file = match commands::flip(&file, direction) { - Ok(f) => f, - Err(e) => { - log::error!( - "Failed to flip {} in the following direction: {:?}; {}", - input_path, - direction, - e - ); - return; - } - }; + let target_palette = match commands::palette(&palette_data) { + Ok(tp) => tp, + Err(e) => { + log::error!( + "Failed to extract palette from {} at step {}; {}", + &palette_file, + count, + e + ); + return; + } + }; + + let mappings = commands::calculate_mapping(&image_palette, &target_palette); + file = match commands::remap_image(file, mappings) { + Ok(f) => f, + Err(e) => { + log::error!( + "Failed to remap {} at step {}; {}", + input_path, + count, + e + ); + return; + } + }; + } + CrunchCommand::Scale { factor } => { + file = match commands::rescale(&file, factor) { + Ok(f) => f, + Err(e) => { + log::error!( + "Failed to scale {} at step {}; {}", + input_path, + count, + e + ); + return; + } + }; + } + CrunchCommand::Rotate { amount } => { + file = match commands::rotate(&file, amount) { + Ok(f) => f, + Err(e) => { + log::error!( + "Failed to rotate {} by {:?} step(s); {}", + input_path, + amount, + e + ); + return; + } + }; + } + CrunchCommand::Flip { direction } => { + file = match commands::flip(&file, direction) { + Ok(f) => f, + Err(e) => { + log::error!( + "Failed to flip {} in the following direction: {:?}; {}", + input_path, + direction, + e + ); + return; + } + }; + } + CrunchCommand::Palette { .. } | CrunchCommand::Pipeline => continue, } - CrunchCommand::Palette { .. } | CrunchCommand::Pipeline => continue, - } - count += 1; - } + count += 1; + } - let mut outer_target_path = PathBuf::from(&output_path); - outer_target_path.pop(); + let mut outer_target_path = PathBuf::from(&output_path); + outer_target_path.pop(); - if let Err(e) = std::fs::create_dir(&outer_target_path) { - match e.kind() { - std::io::ErrorKind::AlreadyExists => { /* This is fine */ } - _ => log::error!( - "Failed to create containing directory {}; {}", - outer_target_path.to_string_lossy(), - e - ), + if let Err(e) = std::fs::create_dir(&outer_target_path) { + match e.kind() { + std::io::ErrorKind::AlreadyExists => { /* This is fine */ } + _ => log::error!( + "Failed to create containing directory {}; {}", + outer_target_path.to_string_lossy(), + e + ), + } } - } - match file.save(&output_path) { - Ok(_) => {} - Err(e) => { - log::error!("Failed to save to {}; {}", output_path, e); + match file.save(&output_path) { + Ok(_) => {} + Err(e) => { + log::error!("Failed to save to {}; {}", output_path, e); + } } - } - }); + }, + ); Ok(()) } +fn join<T: AsRef<Path>>(root: &Path, rest: &T) -> String { + let path = normalize_path(root.join(rest)); + format!("{}", path.display()) +} + fn get_targets( + base_path: PathBuf, pipeline_data: &PipelineFile, ) -> impl ParallelIterator<Item = (String, String, Vec<CrunchCommand>)> + '_ { pipeline_data .pipelines .par_iter() - .flat_map(|pipe| match pipe { + .flat_map(move |pipe| match pipe { PipelineType::Pipeline { input_path, output_path, actions, - } => vec![(input_path.clone(), output_path.clone(), actions.clone())], + } => vec![( + join(&base_path, &input_path), + join(&base_path, &output_path), + actions.clone(), + )], PipelineType::Ref { input_path, output_path, @@ -261,8 +290,8 @@ fn get_targets( .iter() .map(|value| { ( - input_path.clone(), - output_path.clone(), + join(&base_path, &input_path), + join(&base_path, &output_path), (*value).actions.clone(), ) }) @@ -278,8 +307,10 @@ fn get_targets( .map(|value| (*value).actions.clone()) .flat_map(|actions| { let mut paths = Vec::new(); - log::debug!("Mapping glob paths for '{}'", pattern.as_str()); - for entry in glob::glob(pattern.as_str()).unwrap() { + let target_path = join(&base_path, pattern); + + log::debug!("Mapping glob paths for '{}'", &target_path); + for entry in glob::glob(target_path.as_str()).unwrap() { log::debug!("Found a glob match: [{:?}]", entry); paths.push((actions.clone(), entry)); } @@ -292,8 +323,8 @@ fn get_targets( let output_path = output_path.join(filename); Some(( - format!("{}", path.display()), - format!("{}", output_path.display()), + join(&base_path, &path), + join(&base_path, &output_path), actions, )) } else { diff --git a/src/utils.rs b/src/utils.rs index 6048aa40bbe4a50e9e481825846f48ebc73bea46..deff07c28e32d587d03e3bd9466699afb73ba3b1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,5 @@ use std::fmt::{Formatter, LowerHex, UpperHex}; +use std::path::{Component, Path, PathBuf}; use deltae::LabValue; use glam::Vec3; @@ -249,3 +250,31 @@ pub struct Pipeline { pub output_path: String, pub actions: Vec<crate::cli_args::CrunchCommand>, } + +pub fn normalize_path<T: AsRef<Path>>(path: T) -> PathBuf { + let path = path.as_ref(); + let mut components = path.components().peekable(); + let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + components.next(); + PathBuf::from(c.as_os_str()) + } else { + PathBuf::new() + }; + + for component in components { + match component { + Component::Prefix(..) => unreachable!(), + Component::RootDir => { + ret.push(component.as_os_str()); + } + Component::CurDir => {} + Component::ParentDir => { + ret.pop(); + } + Component::Normal(c) => { + ret.push(c); + } + } + } + ret +}