diff --git a/src/config.rs b/src/config.rs index e1d52d2..6a67ddc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,5 +12,7 @@ pub struct Config<'a> { pub file_end_str: String, pub verbose: bool, pub dry_run: bool, + pub include_node_prefixes: Option<&'a [String]>, + pub exclude_node_prefixes: Option<&'a [String]>, pub include_hidden: bool, } diff --git a/src/exceptions.rs b/src/exceptions.rs index 34244e9..d21a5da 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -23,8 +23,8 @@ impl fmt::Display for TopCatError { Self::GraphMissing => write!(f, "Graph is None"), Self::InvalidFileHeader(x, s) => write!(f, "Invalid file header in {}: {}", x.display(), s), Self::NameClash(name, f1, f2) => write!(f, "Name {} found in both {} and {}", name, f1.display(), f2.display()), - Self::MissingExist(x, s) => write!(f, "MissingExist: {} expects {} to exist but it is not found", s, x), - Self::MissingDependency(x, s) => write!(f, "MissingDependency: {} depends on {} bit it is missing", s, x), + Self::MissingExist(x, s) => write!(f, "MissingExist: {} expects {} to exist but it is not found", x, s), + Self::MissingDependency(x, s) => write!(f, "MissingDependency: {} depends on {} but it is missing", x, s), Self::InvalidDependency(x, s) => write!(f, "InvalidDependency: {} is marked as prepend so it cannot depend on {} which isn't marked as prepend", s, x), Self::CyclicDependency(x) => { let mut error_message = "Cyclic dependency detected:\n".to_string(); diff --git a/src/file_dag.rs b/src/file_dag.rs index 889793c..7502eec 100644 --- a/src/file_dag.rs +++ b/src/file_dag.rs @@ -277,6 +277,8 @@ pub struct TCGraph { pub include_globs: Option>, pub include_extensions: Option>, pub exclude_extensions: Option>, + pub include_node_prefixes: Option>, + pub exclude_node_prefixes: Option>, normal_graph: DiGraph, prepend_graph: DiGraph, append_graph: DiGraph, @@ -301,6 +303,11 @@ impl TCGraph { string_slice_to_array(config.include_extensions); let exclude_extensions: Option> = string_slice_to_array(config.exclude_extensions); + let include_node_prefixes: Option> = + string_slice_to_array(config.include_node_prefixes); + let exclude_node_prefixes: Option> = + string_slice_to_array(config.exclude_node_prefixes); + TCGraph { comment_str: config.comment_str.clone(), file_dirs: config.input_dirs.clone(), @@ -308,6 +315,8 @@ impl TCGraph { include_globs, include_extensions, exclude_extensions, + include_node_prefixes, + exclude_node_prefixes, normal_graph: DiGraph::new(), prepend_graph: DiGraph::new(), append_graph: DiGraph::new(), @@ -439,7 +448,40 @@ impl TCGraph { None => return Err(TopCatError::UnknownError("Node not found".to_string())), }; trace!("{} node: {:?}", graph_type.as_str(), file_node.name); - sorted_files.push(file_node.path.clone()); + + // Apply prefix filtering + let should_include = + match (&self.include_node_prefixes, &self.exclude_node_prefixes) { + (Some(include_prefixes), Some(exclude_prefixes)) => { + // If both are specified, include nodes that match include prefixes but not exclude prefixes + include_prefixes + .iter() + .any(|prefix| file_node.name.starts_with(prefix)) + && !exclude_prefixes + .iter() + .any(|prefix| file_node.name.starts_with(prefix)) + } + (Some(include_prefixes), None) => { + // If include prefixes are specified, only include nodes with matching prefixes + include_prefixes + .iter() + .any(|prefix| file_node.name.starts_with(prefix)) + } + (None, Some(exclude_prefixes)) => { + // If exclude prefixes are specified, exclude nodes with matching prefixes + !exclude_prefixes + .iter() + .any(|prefix| file_node.name.starts_with(prefix)) + } + (None, None) => { + // If no prefix filters are specified, include all nodes + true + } + }; + + if should_include { + sorted_files.push(file_node.path.clone()); + } } } Ok(sorted_files) diff --git a/src/main.rs b/src/main.rs index c130003..d75b699 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,6 +101,20 @@ struct Opt { #[structopt(short = "v", long = "verbose", help = "Print debug information")] verbose: bool, + #[structopt( + long = "include-prefix", + help = "Only include nodes with the given prefixes in the output", + value_name = "PREFIXES" + )] + include_node_prefixes: Option>, + + #[structopt( + long = "exclude-prefix", + help = "Exclude nodes with the given prefixes from the output", + value_name = "PREFIXES" + )] + exclude_node_prefixes: Option>, + #[structopt( short = "d", long = "dry-run", @@ -128,6 +142,8 @@ fn main() -> Result<(), TopCatError> { file_end_str: opt.ensure_each_file_ends_with_str, include_hidden: opt.include_hidden_files_and_directories, verbose: opt.verbose, + include_node_prefixes: opt.include_node_prefixes.as_deref(), + exclude_node_prefixes: opt.exclude_node_prefixes.as_deref(), dry_run: opt.dry_run, };