Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ they are included in their respective sets.
| `--no-attrs` | Skip metadata comparison (type, size, direction, attributes) |
| `--set1 <FILE>` | File(s) for set 1; may be specified multiple times |
| `--set2 <FILE>` | File(s) for set 2; may be specified multiple times |
| `-f, --filter <PATTERN>` | Filter signals by glob pattern; may be repeated or space-separated |

### Exit codes

Expand Down Expand Up @@ -226,6 +227,14 @@ Skip metadata comparison (only compare signal values):
wavediff --no-attrs golden.fst test.fst
```

Restrict the comparison to a subset of signals with a glob filter:

```
wavediff --filter '*.clk' golden.fst test.fst
wavediff --filter '*.clk *.cyc' golden.fst test.fst
wavediff --filter '*.clk' --filter '*.cyc' golden.fst test.fst
```

## Supported formats

### FST
Expand Down
29 changes: 3 additions & 26 deletions src/bin/wavecat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
//------------------------------------------------------------------------------

use clap::Parser;
use glob::Pattern;
use wavetools::{
names_only, open_wave_files, write_attrs, write_names, write_signals_wave_multi, NameOptions,
SignalOutputOptions, WaveFormat, WaveHierarchy,
apply_filter, names_only, open_wave_files, parse_filter_patterns, write_attrs, write_names,
write_signals_wave_multi, NameOptions, SignalOutputOptions, WaveFormat,
};
use std::path::PathBuf;
use std::process;
Expand Down Expand Up @@ -87,28 +86,6 @@ fn parse_format(s: &str) -> Result<WaveFormat, String> {
}
}

fn parse_filter_patterns(filter: &[String]) -> Result<Vec<Pattern>, String> {
filter
.iter()
.flat_map(|s| s.split_whitespace())
.map(|p| Pattern::new(p).map_err(|e| format!("Invalid glob pattern '{}': {}", p, e)))
.collect()
}

fn apply_filters(hier: &mut WaveHierarchy, patterns: &[Pattern]) {
if patterns.is_empty() {
return;
}
let tree = &hier.names;
hier.signal_map.retain(|_, info| {
info.vars.retain(|v| {
let name = tree.format_path(v.name);
patterns.iter().any(|p| p.matches(&name))
});
!info.vars.is_empty()
});
}

fn main() {
let args = Args::parse();

Expand All @@ -133,7 +110,7 @@ fn process_wave_file(args: &Args) -> Result<(), String> {
let paths: Vec<&std::path::Path> = args.file.iter().map(std::path::PathBuf::as_path).collect();
let (readers, mut hierarchy, offsets) = open_wave_files(&paths, &name_options, args.format)?;

apply_filters(&mut hierarchy, &patterns);
apply_filter(&mut hierarchy, &patterns);

if args.attrs {
let mut stdout = std::io::stdout();
Expand Down
14 changes: 11 additions & 3 deletions src/bin/wavediff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use clap::Parser;
use std::io::Write;
use std::path::PathBuf;
use wavetools::{
compare_signal_meta, compare_signal_names, diff_wave_sets, open_and_read_wave_sets,
DiffOptions, NameOptions, WaveHierarchy,
apply_filter, compare_signal_meta, compare_signal_names, diff_wave_sets,
open_and_read_wave_sets, parse_filter_patterns, DiffOptions, NameOptions, WaveHierarchy,
};

const VERSION: &str = concat!(
Expand Down Expand Up @@ -71,6 +71,11 @@ struct Args {
/// File(s) for set 2; may be specified multiple times
#[arg(long, action = clap::ArgAction::Append)]
set2: Vec<PathBuf>,

/// Filter signals by glob pattern(s); may be specified multiple times or as a
/// space-separated list (e.g. --filter "*.foo *.bar" or --filter "*.foo" --filter "*.bar")
#[arg(short, long, action = clap::ArgAction::Append)]
filter: Vec<String>,
}

fn main() {
Expand Down Expand Up @@ -171,10 +176,13 @@ fn run(args: Args) -> Result<bool, String> {
set2_paths.extend(args.set2.iter().cloned());

let name_options = NameOptions::default();
let patterns = parse_filter_patterns(&args.filter)?;
let paths1: Vec<&std::path::Path> = set1_paths.iter().map(PathBuf::as_path).collect();
let paths2: Vec<&std::path::Path> = set2_paths.iter().map(PathBuf::as_path).collect();

let sets = open_and_read_wave_sets(&paths1, &paths2, &name_options)?;
let mut sets = open_and_read_wave_sets(&paths1, &paths2, &name_options)?;
apply_filter(&mut sets.hier1, &patterns);
apply_filter(&mut sets.hier2, &patterns);

// For name-mismatch reporting, use FILE1/FILE2 if given, else first --set file
let label1 = args.file1.as_deref().unwrap_or(set1_paths[0].as_path());
Expand Down
14 changes: 12 additions & 2 deletions src/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,14 @@ fn compare_signal_channels<W: Write>(
}

// Anything still in the buffer was in file2 but never matched by file1.
// Drop entries whose handles were filtered out of hier2 -- the streaming
// reader still emits them but they're not part of the comparison set.
// Sort rows before printing so diff output does not depend on HashMap
// iteration order.
let owned: Vec<((u64, usize), OwnedSignalValue)> = buffered2.drain().collect();
let owned: Vec<((u64, usize), OwnedSignalValue)> = buffered2
.drain()
.filter(|((_t, h), _)| hier2.signal_map.contains_key(h))
.collect();
if !owned.is_empty() {
has_differences = true;
}
Expand All @@ -390,10 +395,15 @@ fn compare_signal_channels<W: Write>(
}

// Drain any remaining file2 batches we never read from the channel.
// Only changes for handles still in hier2 count -- filtered-out handles
// are streamed by the reader but excluded from the comparison set.
if !source2_ended {
for batch2 in &rx2 {
has_differences = true;
for change2 in &batch2.changes {
if !hier2.signal_map.contains_key(&change2.handle) {
continue;
}
has_differences = true;
for name in format_handle_names(change2.handle, &hier2.signal_map, &hier2.names) {
writeln!(
writer,
Expand Down
26 changes: 26 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,32 @@ pub fn names_only(map: &SignalMap, tree: &NameTree) -> SignalNames {
.collect()
}

/// Parse a list of filter strings (each may contain whitespace-separated
/// glob patterns) into compiled `glob::Pattern`s.
pub fn parse_filter_patterns(filter: &[String]) -> Result<Vec<glob::Pattern>, String> {
filter
.iter()
.flat_map(|s| s.split_whitespace())
.map(|p| glob::Pattern::new(p).map_err(|e| format!("Invalid glob pattern '{}': {}", p, e)))
.collect()
}

/// Drop entries from `hier.signal_map` whose fully-qualified names do not match
/// any of the provided glob patterns. No-op when `patterns` is empty.
pub fn apply_filter(hier: &mut WaveHierarchy, patterns: &[glob::Pattern]) {
if patterns.is_empty() {
return;
}
let tree = &hier.names;
hier.signal_map.retain(|_, info| {
info.vars.retain(|v| {
let name = tree.format_path(v.name);
patterns.iter().any(|p| p.matches(&name))
});
!info.vars.is_empty()
});
}

/// An FST reader over a buffered file
pub(crate) type FstFileReader = FstReader<BufReader<File>>;

Expand Down
Loading
Loading