28 个版本
0.6.1 | 2024 年 6 月 5 日 |
---|---|
0.5.4 | 2024 年 3 月 18 日 |
0.5.2 | 2023 年 12 月 15 日 |
0.5.1 | 2023 年 11 月 12 日 |
0.1.4-RC2 | 2022 年 11 月 25 日 |
#60 在 文件系统 中
714 每月下载量
205KB
5.5K SLoC
Havocompare - 文件夹比较工具
贡献者
快速入门
0. 安装 havocompare
你有 rust 吗?太棒了!尝试: cargo install havocompare
你只想获取二进制文件:请检查我们的 GitHub 页面的二进制下载
1. 创建配置文件
Havocompare 是基于几个设计目标开发的。我们希望有一个易于阅读和组合的配置文件格式。经过几次尝试,我们最终得到了当前的格式,即 yaml 文件中的一系列规则。请看以下示例 config.yaml
rules:
- name: "Numerical results csv"
# you can have multiple includes and excludes
pattern_include:
- "**/export_*.csv"
# excludes are optional
pattern_exclude:
- "**/export_1337.csv"
CSV:
comparison_modes:
- Relative: 0.1
- Absolute: 1.0
它创建一个名为 rule 的新规则,包括所有匹配 "export_*.csv" 的所有子文件夹中的文件,但排除 " export_1337.csv"。字符串单元格将被检查为完全相同,数字(包括带单位的数字)将被检查为相对偏差小于 0.1
AND 绝对偏差小于 1.0
。
比较规则
- 相对意味着有效性检查如下:
|nominal - actual| / |nominal| < 容差
- 绝对意味着有效性检查如下:
|nominal - actual| < 容差
- "nan" 和 "nan" 相等
0
与0
名义值的差对于任何相对差异都是有效的
2. 运行比较
运行比较非常简单,只需提供标称值、实际值和配置文件:./havocompare compare nominal_dir actual_dir config.yaml
比较报告将写入 ./report
文件夹内。差异也会打印到终端。此外,如果发现差异,返回码将是 1
,如果没有发现差异,将是 0
,这使得将 havocompare 集成到 CI 系统变得非常容易。
关于配置的详细信息
验证方案
在不使用自动完成的情况下编写有效的配置文件可能会出错。我们建议使用 json schema 来验证您的 yaml,甚至可以在 pycharm 等 IDE 中启用自动完成。要生成 schema,可以调用:./havocompare schema > config_scheme.json
并将生成的 schema 导入您的 IDE。
比较选项
CSV
比较模式 comparison_modes
是必需的,类型为 'list'。它可以包含相对数值 ('Relative') 最大偏差或最大偏差 ('Absolute')。您可以指定小数分隔符和字段分隔符。如果没有指定,havocompare 将尝试从每个 csv 文件中猜测它。注意:如果分隔符未指定,即使标称值和实际值之间的分隔符不同,只要所有偏差都在范围内,也接受不同的分隔符。要忽略特定单元格,可以指定一个排除的正则表达式。
预处理步骤是在使用给定的分隔符(或猜测)解析文件之后以及执行其他任何操作之前完成的。处理顺序按列表中编写。在下面的示例中,将从 csv 输入文件中提取标题,然后删除标题为 "Column to delete" 的列。如果任何预处理步骤失败,havocompare 将立即退出并显示错误,因此请谨慎使用。
以下是一个设置所有可选参数的示例
rules:
- name: "CSV - Demo all options"
# what files to include - use as many as make sense to reduce duplication in your rules
pattern_include:
- "**/*.csv"
# optional: of all included files, remove the ones matching any exclude pattern
pattern_exclude:
- "**/ignored.csv"
CSV:
# delimiters are optional, if not given, they will be auto-detected.
# auto-detection allows different delimiters for nominal and actual
decimal_separator: '.'
field_delimiter: ';'
# can have Absolute or Relative or both
comparison_modes:
- Absolute: 1.0
- Relative: 0.1
# optional: exclude fields matching the regex from comparison
exclude_field_regex: "Excluded"
# optional: preprocessing of the csv files
preprocessing:
# extracts the headers to the header-fields, makes reports more legible and allows for further processing "ByName".
# While it may fail, there's no penalty for it, as long as you don't rely on it.
- ExtractHeaders
# Sort the table by column 0, beware that the column must only contain numbers / quantities
- SortByColumnNumber: 0
# Delete a column by name, needs `ExtractHeaders` first - delete sets all values to 'DELETED'
- DeleteColumnByName: "Vertex_Position_Y"
- DeleteColumnByNumber: 1
# Sorts are stable, so a second sort will keep the first sort as sub-order.
- SortByColumnName: "Vertex_Position_X"
# Deletes the first row by setting all values to 'DELETED' - meaning that numbering stays constant
- DeleteRowByNumber: 0
# Deletes rows having any element matching the given regex (may delete different lines in nom / act)!
- DeleteRowByRegex: "Vertex_Count"
# Deletes the cell (column, row) by setting the value to 'DELETED'
- DeleteCellByNumber:
column: 0
row: 0
# Deletes the cell (column name, row) by setting the value to 'DELETED'. This needs `ExtractHeaders`
- DeleteCellByName:
column: "Column to delete"
row: 0
图像比较
图像比较使用 image compare
crate 完成。在这里指定许多选项,然后根据阈值进行过滤。
rules:
- name: "JPG comparison"
pattern_include:
- "**/*.jpg"
# exclude can of course also be specified!
Image:
# Compare images in RGBA-mode, can also be RGB and Gray
# Comparison mode set to Hybrid means we want MSSIM on the Y channel and 2 dim vec diff on UV for color information
RGBA: Hybrid
threshold: 0.9
纯文本比较
对于纯文本比较,文件将逐行读取和比较。对于每一行,使用 strsim
crate 的归一化 Damerau-Levenshtein 距离。您可以指定任意数量的忽略行,以忽略已知不同的行。
rules:
- name: "HTML-Compare strict"
pattern_exclude:
- "**/*_changed.html"
pattern_include:
- "**/*.html"
PlainText:
# Normalized Damerau-Levenshtein distance
threshold: 1.0
# All lines matching any regex below will be ignored
ignore_lines:
- "stylesheet"
- "next_ignore"
- "[A-Z]*[0-9]"
PDF 文本比较
对于 PDF 文本比较,将提取文本并写入临时文件。然后使用纯文本比较比较这些文件。
rules:
- name: "PDF-Text-Compare"
pattern_exclude:
- "**/*_changed.pdf"
pattern_include:
- "**/*.pdf"
PDFText:
# Normalized Damerau-Levenshtein distance
threshold: 1.0
# All lines matching any regex below will be ignored
ignore_lines:
- "stylesheet"
- "next_ignore"
- "[A-Z]*[0-9]"
哈希比较
对于无法以其他方式检查的二进制文件,我们还可以执行简单的哈希比较。目前,我们仅支持 SHA-256,但可以轻松添加更多检查。
rules:
- name: "Hash comparison strict"
pattern_exclude:
- "**/*.bin"
Hash:
# Currently we only have Sha256
function: Sha256
文件元数据比较
对于仅存在或某些元数据已经足够的情况。
rules:
- name: "Metadata comparison"
pattern_exclude:
- "**/*.bin"
FileProperties:
# nom/act file paths must not contain whitespace
forbid_name_regex: "[\\s]"
# files must have their modification timestamp within 3600 seconds
modification_date_tolerance_secs: 3600
# files sizes must be within 1 kb
file_size_tolerance_bytes: 1024
运行外部比较工具
如果您想运行外部比较工具,可以使用此选项
rules:
- name: "External checker"
pattern_include:
- "*.pdf"
External:
# this config will call `/usr/bin/pdf-diff --only-images nominal.pdf actual.pdf`
# return code will decide on comparison result
executable: "/usr/bin/pdf-diff"
# optional: add as many extra params as
extra_params:
- "--only-images"
JSON 比较器
比较 JSON 文件中的不同键和值中的不匹配。 ignore_keys
是一个正则表达式列表,它将匹配单个键名称,如果正则表达式匹配,则排除键值对。值不受此影响。
rules:
- name: "Compare JSON files"
pattern_include:
- "**/*.json"
Json:
ignore_keys:
# drop "ignore_this_key" and "ignore_this_keys" with this regex :)
- "ignore_this_key(s?)"
在单元测试中使用 HavoCompare
- 将 havocompare 添加到您的 dev-dependencies
[dev-dependencies] havocompare = "0.5"
- 在单元测试中使用它,例如
#[test] // works in 0.5 series fn integ_test_dirs() { let result_dir = process_whatever_test_data(); // just write the usual yaml file let result = havocompare::compare_folders("../tests/data/nominal/integ_test/case", &result_dir, "../tests/data/config.yaml", "../tests/out_report").unwrap; assert!(result); } #[test] // works starting with 0.5.3 only fn integ_test_file() { let result_file = process_generate_image(); // see docs for all options let compare_mode = ComparisonMode::Image(ImageCompareConfig{threshold: 0.97}); let result = havocompare::compare_files("../tests/data/nominal.png", &result_file, &compare_mode).unwrap; assert!(result); }
变更日志
0.6.1
- 添加 json-diff 的新版本,具有更好的 API 和更好的过滤选项
0.6.0
- 为图像比较模块添加新选项(很多选项!)
- 将 json-compare 升级到新版本,修复正则表达式字段排除和排序的错误
0.5.4
- 添加从 CLI 运行单文件模式的选项
0.5.3
- 添加排序JSON数组的功能(包括深度排序)
- 将单个文件比较函数改为公开API
- 更新依赖项,修复与空格相关的损坏PDF导入
0.5.2
- 在CSV和PDF报告中保留空格,而不是由HTML折叠
- 在报告索引中添加加号和减号符号
- 如果比较的文件名不同,则在报告索引中显示组合文件名
0.5.1
- 修复JSON检查中的潜在崩溃
0.5.0
- 添加JSON检查
0.4.0
- 将报告逻辑与比较逻辑分开
- 实现机器可读的JSON报告
0.3.2
- 在比较后通过
--open
直接打开报告 - 运行
compare
时的解析失败现在会传播到终端
0.3.1
- 修复哈希和文本比较中的实际和名义值交换
0.3.0
- 允许RGBA图像比较
- 添加文件元数据比较
- 添加外部检查
- 为文件元数据比较和外部检查添加和调整报告
- 添加CSV标题比较。之前,报告仅标记差异但不返回任何错误。
- 添加配置yaml验证命令,用于检查文件是否可以加载
0.2.4
- 检查两个比较的CSV文件的行数,如果不相等则抛出错误
- 添加按单元格删除
- 简化报告子文件夹创建:子文件夹现在在临时文件夹中临时创建,而不是在当前工作文件夹中
- 将报告行编号更改为始终从0开始,以便行删除更容易理解
- 修复不可显示的diff值的浮点值比较
0.2.3
- 将pdf-extract crate升级到0.6.4以修复"尝试离开未初始化的类型
linked_hash_map::Node<alloc::vec::Vec<u8>, object::Object>
"
0.2.2
- 将包含错误且无法进行比较的文件包含在报告中
- 修复了一个导致程序提前退出规则循环的bug,并且没有处理所有
0.2.0
- 删除列将不再真正删除它们,而是将每个值替换为"已删除"
- 将配置结构公开到库API
- 修复了关于多个空行处理不当的bug
- 重构CSV报告,使其具有交错和更紧凑的视图
- 在报告索引.html中显示比较文件的相对路径而不是文件名
- 使标题提取成为可失败的但不重要的操作 - 现在始终可以启用
- 编写了一个全新的csv解析器
- 尊重转义
- 允许包含未转义的字段分隔符的字符串字面量(field1, "field2, but as literal", field3)
- 允许包含引号的多行字符串字面量
- 现在将非矩形格式的CSV失败
0.1.4
- 添加多个包含和排除项 - 警告,这将破坏0.1.3及更早版本的rules-files
- 在库代码中移除所有
unwrap
和expect
,以换取正确的错误传播 - 为CSV文件添加预处理选项
- 精炼了readme.md
- 修复报告生成中的唯一键创建
- 添加PDF-Text比较
0.1.3:
- 添加可选的cli参数以配置存储报告的文件夹
0.1.2:
- 添加SHA-256比较模式
- 修复Windows上的CSV比较BOM
0.1.1:
- 在找不到文件夹时提供更好的错误消息
- 更好的测试覆盖率
- 修复Windows终端上的颜色
- 扩展CI到Windows和mac
依赖项
~35–48MB
~712K SLoC