coliru

A minimal, flexible, dotfile installer
git clone https://git.ashermorgan.net/coliru/
Log | Files | Refs | README

commit d72aa87bff67a9856d2fc725c37886d8e0087eea
parent f8aa11827fb1a8b20887e19b459ca55400299172
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sat,  7 Sep 2024 14:06:11 -0700

Move tags_match function to manifest module

Diffstat:
Msrc/core.rs | 6+++---
Msrc/main.rs | 1-
Msrc/manifest.rs | 182++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Dsrc/tags.rs | 168-------------------------------------------------------------------------------
4 files changed, 175 insertions(+), 182 deletions(-)

diff --git a/src/core.rs b/src/core.rs @@ -4,8 +4,8 @@ use anyhow::{Context, Result}; use colored::{Colorize, ColoredString}; use std::env::set_current_dir; use std::path::Path; -use super::manifest::{Manifest, CopyLinkOptions, RunOptions, get_tags}; -use super::tags::tags_match; +use super::manifest::{Manifest, CopyLinkOptions, RunOptions, get_manifest_tags, + tags_match}; use super::local::{copy_file, link_file, run_command}; use super::ssh::{resolve_path, send_command, send_staged_files, stage_file}; use tempfile::tempdir; @@ -39,7 +39,7 @@ fn handle_error(result: Result<()>) -> bool { /// Prints the available tags in a manifest pub fn list_tags(manifest: Manifest) { - for tag in get_tags(manifest) { + for tag in get_manifest_tags(manifest) { println!("{}", tag); } } diff --git a/src/main.rs b/src/main.rs @@ -5,7 +5,6 @@ mod core; mod local; mod manifest; mod ssh; -mod tags; #[cfg(test)] #[path = "../tests/test_utils/mod.rs"] diff --git a/src/manifest.rs b/src/manifest.rs @@ -1,4 +1,4 @@ -//! Coliru manifest parsing +//! Coliru manifest parsing and tag matching use anyhow::Result; use serde::Deserialize; @@ -70,6 +70,37 @@ pub struct Manifest { pub base_dir: PathBuf, } +/// Checks if a list of tags matches a list of tag rules +/// +/// ``` +/// let rules = ["linux,macos", "system", "^work"]; +/// let tags_1 = ["macos", "system", "user"]; +/// let tags_2 = ["linux", "system", "work"]; +/// assert_eq!(tags_match(&rules, &tags_1), true); +/// assert_eq!(tags_match(&rules, &tags_2), false); +/// ``` +pub fn tags_match<S: AsRef<str>>(rules: &[S], tags: &[S]) -> bool { + for rule in rules.iter() { + let mut _rule = rule.as_ref(); + let is_negated = _rule.chars().nth(0) == Some('^'); + if is_negated { + _rule = &_rule[1..]; // Strip leading '^' + } + + let tag_found = _rule.split(",").any(|subrule| { + tags.iter().any(|tag| { + tag.as_ref() == subrule + }) + }); + + if tag_found == is_negated { + return false + } + } + + true +} + /// Parse a coliru YAML manifest file /// /// ``` @@ -90,7 +121,7 @@ pub fn parse_manifest_file(path: &Path) -> Result<Manifest> { } /// Returns a sorted, de-duplicated vector of all tags in a manifest -pub fn get_tags(manifest: Manifest) -> Vec<String> { +pub fn get_manifest_tags(manifest: Manifest) -> Vec<String> { let mut tag_set: HashSet<String> = HashSet::new(); for step in manifest.steps { @@ -109,8 +140,139 @@ mod tests { use super::*; #[test] + fn test_manifest_tags_match_empty_parameters() { + let tags_1 = []; + let tags_2 = ["linux", "user"]; + assert_eq!(tags_match(&tags_1, &tags_1), true); + assert_eq!(tags_match(&tags_1, &tags_2), true); + assert_eq!(tags_match(&tags_2, &tags_1), false); + } + + #[test] + fn test_manifest_tags_match_one_match() { + let tags_1 = ["linux"]; + let tags_2 = ["linux", "windows"]; + + assert_eq!(tags_match(&tags_1.clone(), &tags_1.clone()), true); + assert_eq!(tags_match(&tags_1.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&tags_2.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&tags_2.clone(), &tags_2.clone()), true); + } + + #[test] + fn test_manifest_tags_match_two_matches() { + let tags_1 = ["linux", "user"]; + let tags_2 = ["linux", "user", "windows"]; + + assert_eq!(tags_match(&tags_1.clone(), &tags_1.clone()), true); + assert_eq!(tags_match(&tags_1.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&tags_2.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&tags_2.clone(), &tags_2.clone()), true); + } + + #[test] + fn test_manifest_tags_match_negated() { + let rules = ["^linux"]; + let tags_1 = ["linux"]; + let tags_2 = ["windows"]; + let tags_3 = ["macos"]; + let tags_4 = ["linux", "macos"]; + + assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), false); + } + + #[test] + fn test_manifest_tags_match_negated_two_rules() { + let rules_1 = ["^linux", "^user"]; + let rules_2 = ["^linux", "user"]; + let tags_1 = ["linux", "system"]; + let tags_2 = ["windows", "user"]; + let tags_3 = ["macos", "system"]; + let tags_4 = ["linux", "macos", "user"]; + + assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), false); + assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules_1.clone(), &tags_4.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_4.clone()), false); + } + + #[test] + fn test_manifest_tags_match_union() { + let rules = ["linux,macos"]; + let tags_1 = ["linux"]; + let tags_2 = ["macos"]; + let tags_3 = ["linux", "macos"]; + let tags_4 = ["windows"]; + + assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), true); + assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), false); + } + + #[test] + fn test_manifest_tags_match_union_two_rules() { + let rules_1 = ["linux,macos", "user,system"]; + let rules_2 = ["linux,macos", "user"]; + let tags_1 = ["user", "linux"]; + let tags_2 = ["system", "macos"]; + let tags_3 = ["user", "linux", "macos"]; + let tags_4 = ["system", "windows"]; + + assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), true); + assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules_1.clone(), &tags_4.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), true); + assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules_2.clone(), &tags_4.clone()), false); + } + + #[test] + fn test_manifest_tags_match_union_negated() { + let rules = ["^linux,macos"]; + let tags_1 = ["linux"]; + let tags_2 = ["macos"]; + let tags_3 = ["linux", "macos"]; + let tags_4 = ["windows"]; + + assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), false); + assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), false); + assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), true); + } + + #[test] + fn test_manifest_tags_match_union_negated_two_rules() { + let rules_1 = ["^linux,macos", "^user"]; + let rules_2 = ["^linux,macos", "user,system"]; + let rules_3 = ["^linux,macos", "user"]; + let tags_1 = ["linux", "macos", "system"]; + let tags_2 = ["windows", "user"]; + let tags_3 = ["windows", "system"]; + + assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), false); + assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), true); + assert_eq!(tags_match(&rules_3.clone(), &tags_1.clone()), false); + assert_eq!(tags_match(&rules_3.clone(), &tags_2.clone()), true); + assert_eq!(tags_match(&rules_3.clone(), &tags_3.clone()), false); + } + + #[test] #[cfg(target_family = "unix")] - fn parse_manifest_file_missing() { + fn test_manifest_parse_manifest_file_missing() { let manifest_path = Path::new("examples/test/missing.yml"); let expected = "No such file or directory (os error 2)"; let actual = parse_manifest_file(manifest_path); @@ -120,7 +282,7 @@ mod tests { #[test] #[cfg(target_family = "windows")] - fn parse_manifest_file_missing() { + fn test_manifest_parse_manifest_file_missing() { let manifest_path = Path::new("examples/test/missing.yml"); let exp = "The system cannot find the file specified. (os error 2)"; let actual = parse_manifest_file(manifest_path); @@ -129,7 +291,7 @@ mod tests { } #[test] - fn parse_manifest_file_invalid() { + fn test_manifest_parse_manifest_file_invalid() { let manifest_path = Path::new("examples/test/invalid.yml"); let exp = "steps[0].copy[0]: missing field `src` at line 5 column 7"; let actual = parse_manifest_file(manifest_path); @@ -138,7 +300,7 @@ mod tests { } #[test] - fn parse_manifest_file_valid() { + fn test_manifest_parse_manifest_file_valid() { let manifest_path = Path::new("examples/test/manifest.yml"); let expected = Manifest { steps: vec![ @@ -214,7 +376,7 @@ mod tests { } #[test] - fn get_tags_basic() { + fn test_manifest_get_manifest_tags_basic() { let manifest_path = Path::new("examples/test/manifest.yml"); let manifest = parse_manifest_file(manifest_path).unwrap(); let expected = vec![ @@ -222,18 +384,18 @@ mod tests { String::from("macos"), String::from("windows"), ]; - let actual = get_tags(manifest); + let actual = get_manifest_tags(manifest); assert_eq!(actual, expected); } #[test] - fn get_tags_empty() { + fn test_manifest_get_manifest_tags_empty() { let manifest = Manifest { steps: vec![], base_dir: PathBuf::from("examples/test/empty.yml"), }; let expected: Vec<String> = vec![]; - let actual = get_tags(manifest); + let actual = get_manifest_tags(manifest); assert_eq!(actual, expected); } } diff --git a/src/tags.rs b/src/tags.rs @@ -1,168 +0,0 @@ -//! Tag rule matching functionality - -/// Checks if a list of tags matches a list of tag rules -/// -/// ``` -/// let rules = ["linux,macos", "system", "^work"]; -/// let tags_1 = ["macos", "system", "user"]; -/// let tags_2 = ["linux", "system", "work"]; -/// assert_eq!(tags_match(&rules, &tags_1), true); -/// assert_eq!(tags_match(&rules, &tags_2), false); -/// ``` -pub fn tags_match<S: AsRef<str>>(rules: &[S], tags: &[S]) -> bool { - for rule in rules.iter() { - let mut _rule = rule.as_ref(); - let is_negated = _rule.chars().nth(0) == Some('^'); - if is_negated { - _rule = &_rule[1..]; // Strip leading '^' - } - - let tag_found = _rule.split(",").any(|subrule| { - tags.iter().any(|tag| { - tag.as_ref() == subrule - }) - }); - - if tag_found == is_negated { - return false - } - } - - true -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn tags_match_empty_parameters() { - let tags_1 = []; - let tags_2 = ["linux", "user"]; - assert_eq!(tags_match(&tags_1, &tags_1), true); - assert_eq!(tags_match(&tags_1, &tags_2), true); - assert_eq!(tags_match(&tags_2, &tags_1), false); - } - - #[test] - fn tags_match_one_match() { - let tags_1 = ["linux"]; - let tags_2 = ["linux", "windows"]; - - assert_eq!(tags_match(&tags_1.clone(), &tags_1.clone()), true); - assert_eq!(tags_match(&tags_1.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&tags_2.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&tags_2.clone(), &tags_2.clone()), true); - } - - #[test] - fn tags_match_two_matches() { - let tags_1 = ["linux", "user"]; - let tags_2 = ["linux", "user", "windows"]; - - assert_eq!(tags_match(&tags_1.clone(), &tags_1.clone()), true); - assert_eq!(tags_match(&tags_1.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&tags_2.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&tags_2.clone(), &tags_2.clone()), true); - } - - #[test] - fn tags_match_negated() { - let rules = ["^linux"]; - let tags_1 = ["linux"]; - let tags_2 = ["windows"]; - let tags_3 = ["macos"]; - let tags_4 = ["linux", "macos"]; - - assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), false); - } - - #[test] - fn tags_match_negated_two_rules() { - let rules_1 = ["^linux", "^user"]; - let rules_2 = ["^linux", "user"]; - let tags_1 = ["linux", "system"]; - let tags_2 = ["windows", "user"]; - let tags_3 = ["macos", "system"]; - let tags_4 = ["linux", "macos", "user"]; - - assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), false); - assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules_1.clone(), &tags_4.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_4.clone()), false); - } - - #[test] - fn tags_match_union() { - let rules = ["linux,macos"]; - let tags_1 = ["linux"]; - let tags_2 = ["macos"]; - let tags_3 = ["linux", "macos"]; - let tags_4 = ["windows"]; - - assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), true); - assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), false); - } - - #[test] - fn tags_match_union_two_rules() { - let rules_1 = ["linux,macos", "user,system"]; - let rules_2 = ["linux,macos", "user"]; - let tags_1 = ["user", "linux"]; - let tags_2 = ["system", "macos"]; - let tags_3 = ["user", "linux", "macos"]; - let tags_4 = ["system", "windows"]; - - assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), true); - assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules_1.clone(), &tags_4.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), true); - assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules_2.clone(), &tags_4.clone()), false); - } - - #[test] - fn tags_match_union_negated() { - let rules = ["^linux,macos"]; - let tags_1 = ["linux"]; - let tags_2 = ["macos"]; - let tags_3 = ["linux", "macos"]; - let tags_4 = ["windows"]; - - assert_eq!(tags_match(&rules.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules.clone(), &tags_2.clone()), false); - assert_eq!(tags_match(&rules.clone(), &tags_3.clone()), false); - assert_eq!(tags_match(&rules.clone(), &tags_4.clone()), true); - } - - #[test] - fn tags_match_union_negated_two_rules() { - let rules_1 = ["^linux,macos", "^user"]; - let rules_2 = ["^linux,macos", "user,system"]; - let rules_3 = ["^linux,macos", "user"]; - let tags_1 = ["linux", "macos", "system"]; - let tags_2 = ["windows", "user"]; - let tags_3 = ["windows", "system"]; - - assert_eq!(tags_match(&rules_1.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules_1.clone(), &tags_2.clone()), false); - assert_eq!(tags_match(&rules_1.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules_2.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules_2.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules_2.clone(), &tags_3.clone()), true); - assert_eq!(tags_match(&rules_3.clone(), &tags_1.clone()), false); - assert_eq!(tags_match(&rules_3.clone(), &tags_2.clone()), true); - assert_eq!(tags_match(&rules_3.clone(), &tags_3.clone()), false); - } -}