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:
| M | src/core.rs | | | 6 | +++--- |
| M | src/main.rs | | | 1 | - |
| M | src/manifest.rs | | | 182 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
| D | src/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);
- }
-}