diff --git a/Cargo.lock b/Cargo.lock index be04a23..0e28f3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.5.0" @@ -126,8 +135,10 @@ dependencies = [ "clap", "clap_complete", "lazy_static", + "regex", "serde", "serde_json", + "serde_regex", "serde_yaml", "shellexpand", "shlex", @@ -213,6 +224,12 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + [[package]] name = "once_cell" version = "1.18.0" @@ -263,6 +280,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "ryu" version = "1.0.15" @@ -309,6 +355,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" +dependencies = [ + "regex", + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.25" diff --git a/Cargo.toml b/Cargo.toml index fbb9461..c677aad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,10 @@ edition = "2021" clap = { version = "4.2.4", features = ["derive", "cargo"] } clap_complete = "4.2.1" lazy_static = "1.4.0" +regex = "1.10.2" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" +serde_regex = "1.1.0" serde_yaml = "0.9.21" shellexpand = "3.1.0" shlex = "1.1.0" diff --git a/src/profiles/config.rs b/src/profiles/config.rs index f69f002..3acd2a8 100644 --- a/src/profiles/config.rs +++ b/src/profiles/config.rs @@ -1,6 +1,7 @@ use std::{fs::File, io::BufReader, path::Path}; use super::hooks::Hooks; +use super::mappings::Mapping; #[derive(Default, Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] @@ -32,6 +33,7 @@ pub struct DFMConfig { pub link: LinkMode, #[serde(default = "Vec::new")] pub modules: Vec, + pub mappings: Option>, } impl Default for DFMConfig { @@ -44,6 +46,7 @@ impl Default for DFMConfig { location: "".to_string(), hooks: Hooks::new(), modules: Vec::new(), + mappings: None, } } } diff --git a/src/profiles/mappings.rs b/src/profiles/mappings.rs new file mode 100644 index 0000000..98bdd7d --- /dev/null +++ b/src/profiles/mappings.rs @@ -0,0 +1,143 @@ +use regex::Regex; + +#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)] +pub enum TargetOS { + Darwin, + Linux, + Windows, + Vec(Vec), + #[default] + All, +} + +impl TargetOS { + #[cfg(target_os = "macos")] + fn current() -> TargetOS { + TargetOS::Darwin + } + + #[cfg(target_os = "linux")] + fn current() -> TargetOS { + TargetOS::Linux + } + + #[cfg(target_os = "windows")] + fn current() -> TargetOS { + TargetOS::Windows + } + + fn is_this_os(target: &TargetOS) -> bool { + match target { + &TargetOS::All => true, + TargetOS::Vec(targets) => targets + .into_iter() + .find(|t| TargetOS::is_this_os(*t)) + .is_some(), + desired => desired == &TargetOS::current(), + } + } +} + +fn default_off() -> bool { + false +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct Mapping { + #[serde(rename = "match", with = "serde_regex")] + term: Regex, + #[serde(default = "default_off")] + link_as_dir: bool, + #[serde(default = "default_off")] + skip: bool, + #[serde(default)] + target_os: TargetOS, + #[serde(default)] + dest: String, + #[serde(default)] + target_dir: String, +} + +impl Mapping { + fn new(term: &str) -> Mapping { + Mapping { + term: Regex::new(term).expect("Unable to compile regex!"), + link_as_dir: false, + skip: false, + target_os: TargetOS::All, + dest: "".to_string(), + target_dir: "".to_string(), + } + } + + fn skip(mut self) -> Mapping { + self.skip = true; + self + } + + fn link_as_dir(mut self) -> Mapping { + self.link_as_dir = true; + self + } + + fn dest(mut self, new_dest: String) -> Mapping { + self.dest = new_dest; + self + } + + fn target_os(mut self, new_target: TargetOS) -> Mapping { + self.target_os = new_target; + self + } + + fn does_match(&self, path: &str) -> bool { + if self.term.is_match(path) { + return TargetOS::is_this_os(&self.target_os); + } + + false + } +} + +pub struct Mapper { + mappings: Vec, +} + +pub enum MapAction { + NewDest(String), + NewTargetDir(String), + Skip, + None, +} + +impl From> for Mapper { + fn from(mappings: Vec) -> Mapper { + Mapper { mappings } + } +} + +impl From>> for Mapper { + fn from(mappings: Option>) -> Mapper { + let configured: Vec = match mappings { + Some(configured) => configured, + None => vec![ + Mapping::new("README.*").skip(), + Mapping::new("LICENSE").skip(), + ], + }; + + Mapper::from(configured) + } +} + +impl Mapper { + fn get_mapped_action(&self, relative_path: &str) -> MapAction { + for mapping in &self.mappings { + if !mapping.does_match(relative_path) { + continue; + } + } + + MapAction::None + } +} diff --git a/src/profiles/mod.rs b/src/profiles/mod.rs index ad872e7..e94639b 100644 --- a/src/profiles/mod.rs +++ b/src/profiles/mod.rs @@ -1,5 +1,6 @@ mod config; mod hooks; +mod mappings; mod profile; pub use profile::Profile;