diff --git a/src/validators.rs b/src/validators.rs index c6a8f47..d706849 100644 --- a/src/validators.rs +++ b/src/validators.rs @@ -2,6 +2,7 @@ pub mod elf; pub mod indexed_package; +pub mod scripts; mod error; pub use error::*; @@ -27,12 +28,15 @@ pub struct ValidationResult { pub enum ValidatorAction<'a> { /// Perform an action on a `ELF` file ELF(elf::ELFAction<'a>), + /// Perform an action on a `Script` file + Script(scripts::ScriptAction<'a>), } impl<'a> std::fmt::Display for ValidatorAction<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ELF(action) => action.fmt(f), + Self::Script(action) => action.fmt(f), } } } diff --git a/src/validators/indexed_package.rs b/src/validators/indexed_package.rs index 8635ccd..f91f755 100644 --- a/src/validators/indexed_package.rs +++ b/src/validators/indexed_package.rs @@ -46,6 +46,23 @@ pub fn validate_indexed_package<'a>( }); } } + crate::util::fs::FSEntry::Script(script) => { + let path = path.to_path_buf().join(entry.name()); + let v_res = script.validate(input); + + // If there are some results, append them to the return value + if !(v_res.actions.is_empty() && v_res.errors.is_empty()) { + res.push(FileValidationResult { + path, + actions: v_res + .actions + .into_iter() + .map(ValidatorAction::Script) + .collect(), + errors: v_res.errors, + }); + } + } _ => {} } diff --git a/src/validators/scripts.rs b/src/validators/scripts.rs new file mode 100644 index 0000000..98a6807 --- /dev/null +++ b/src/validators/scripts.rs @@ -0,0 +1,82 @@ +//! Validators for `Script`s +use std::path::PathBuf; + +use crate::{ + error::{Error, Throwable}, + package::IndexedPackage, + util::fs::{ScriptFile, SearchType, ToPathBuf}, +}; + +use super::{ValidationError, ValidationInput, ValidationResult}; + +impl ScriptFile { + /// Validate an `Script`: + /// - Make sure the `interpreter` is linkable and modify the path for the correct location + /// # Arguments + /// * `input` - The `ValidationInput` to work correctly + pub fn validate<'a>(&self, input: &'a ValidationInput) -> ValidationResult> { + let mut actions: Vec = Vec::new(); + let mut errors: Vec = Vec::new(); + + // Validate the interpreter + if let Some(old_interpreter) = &self.interpreter { + if let Some(filename) = old_interpreter.0.file_name() { + if let Some(result) = input + .package_index + .find_fs_entry(&SearchType::ELF(filename)) + { + actions.push(ScriptAction::ReplaceInterpreter { + interpreter: (old_interpreter.0.clone(), result.0.to_path_buf()), + package: result.1, + }) + } else { + errors.push( + ValidationError::UnresolvedDependency { + filename: old_interpreter.0.as_os_str().to_owned(), + } + .throw("Resolving script interpreter".to_string()), + ) + } + } + } + + ValidationResult { actions, errors } + } +} + +/// An action to perform on a Script file +#[derive(Clone)] +pub enum ScriptAction<'a> { + /// Set the `interpreter` available in `package` + ReplaceInterpreter { + /// The old and the new interpreter + interpreter: (PathBuf, PathBuf), + /// The package holding the interpreter (the dependency) + package: &'a dyn IndexedPackage, + }, +} + +impl<'a> std::fmt::Display for ScriptAction<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ReplaceInterpreter { + interpreter, + package, + } => { + write!( + f, + "Replace SCRIPT interpreter '{}' with '{}' of package '{}' (args: '{}')", + interpreter.0.to_string_lossy(), + interpreter.1.to_string_lossy(), + package.get_full_name(), + interpreter + .1 + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::>() + .join(" "), + ) + } + } + } +}