Make CI pass again
Unified · Split
| @@ -1924,6 +1924,8 @@ dependencies = [ · 1923 unmodified lines | |||
| 1924 | "bstr", | 1924 | "bstr", |
| 1925 | "cov-mark", | 1925 | "cov-mark", |
| 1926 | "expect-test", | 1926 | "expect-test", |
| 1927 | "gix-hash", | ||
| 1928 | "gix-object", | ||
| 1927 | "hashbrown 0.16.1", | 1929 | "hashbrown 0.16.1", |
| 1928 | "memchr", | 1930 | "memchr", |
| 1929 | ] | 1931 | ] |
| @@ -1,13 +1,16 @@ | |||
| 1 | # Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | # Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:Cargo.toml | ||
| 3 | |||
| 1 | [package] | 4 | [package] |
| 2 | name = "gix-imara-diff" | 5 | name = "gix-imara-diff" |
| 3 | version = "0.2.0" | 6 | version = "0.2.0" |
| 4 | edition = "2021" | 7 | edition = "2021" |
| 5 | authors = ["pascalkuthe <pascalkuthe@pm.me>"] | 8 | authors = ["pascalkuthe <pascalkuthe@pm.me>", "Sebastian Thiel <sebastian.thiel@icloud.com>"] |
| 6 | rust-version = "1.71" | 9 | rust-version = "1.71" |
| 7 | license = "Apache-2.0" | 10 | license = "Apache-2.0" |
| 8 | 11 | ||
| 9 | description = "A high performance library for computing diffs." | 12 | description = "A high performance library for computing diffs, maintained as a modified copy of upstream imara-diff for gitoxide." |
| 10 | repository = "https://github.com/pascalkuthe/imara-diff" | 13 | repository = "https://github.com/GitoxideLabs/gitoxide" |
| 11 | keywords = ["diff", "difference", "myers", "compare", "changes"] | 14 | keywords = ["diff", "difference", "myers", "compare", "changes"] |
| 12 | readme = "README.md" | 15 | readme = "README.md" |
| 13 | exclude = [ | 16 | exclude = [ |
| @@ -26,6 +29,8 @@ default = ["unified_diff"] · 12 unmodified lines | |||
| 26 | unified_diff = [] | 29 | unified_diff = [] |
| 27 | 30 | ||
| 28 | [dev-dependencies] | 31 | [dev-dependencies] |
| 32 | gix-hash = { version = "^0.23.0", path = "../gix-hash", features = ["sha1"] } | ||
| 33 | gix-object = { version = "^0.58.0", path = "../gix-object", features = ["sha1"] } | ||
| 29 | cov-mark = "2.1.0" | 34 | cov-mark = "2.1.0" |
| 30 | expect-test = "1.4.0" | 35 | expect-test = "1.4.0" |
| 31 | 36 | ||
| @@ -1,5 +1,8 @@ | |||
| 1 | # imara-diff | 1 | # imara-diff |
| 2 | 2 | ||
| 3 | > Modified for gitoxide from the upstream imara-diff crate. | ||
| 4 | > Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:README.md | ||
| 5 | |||
| 3 | [](https://crates.io/crates/imara-diff) | 6 | [](https://crates.io/crates/imara-diff) |
| 4 | [](https://docs.rs/imara-diff/latest/imara_diff/) | 7 | [](https://docs.rs/imara-diff/latest/imara_diff/) |
| 5 |  | 8 |  |
| @@ -0,0 +1,24 @@ | |||
| 1 | # upstream-repo: https://github.com/pascalkuthe/imara-diff | ||
| 2 | # upstream-branch: fix-timeout-window-0.2 | ||
| 3 | # upstream-commit: 32d1e45d3df061e6ccba6db7fdce92db29e345d8 | ||
| 4 | # columns: path<TAB>origin<TAB>status<TAB>upstream-blob<TAB>cat-file | ||
| 5 | .cargo_vcs_info.json generated generated - - | ||
| 6 | Cargo.lock generated generated - - | ||
| 7 | Cargo.toml upstream modified af703a238ed9f159d5c41e2bd5e86e0cc2031cf0 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:Cargo.toml | ||
| 8 | Cargo.toml.orig generated generated - - | ||
| 9 | LICENSE upstream unchanged 16fe87b06e802f094b3fbb0894b137bca2b16ef1 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:LICENSE | ||
| 10 | README.md upstream modified b1e722e2d0731797b708b56369ed8f1fbd742f09 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:README.md | ||
| 11 | src/histogram.rs upstream modified ff2cb0e341d18c28931e01fba01674f071827f2b git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram.rs | ||
| 12 | src/histogram/lcs.rs upstream modified 5a86e13fa324a589d9bc4ffb8ac38824a619ed18 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram/lcs.rs | ||
| 13 | src/histogram/list_pool.rs upstream modified 0f014216ac53750764a816b39929b892aa75097f git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram/list_pool.rs | ||
| 14 | src/intern.rs upstream modified f93fb54425a0d0f35eb1bb7071e34e94aede0750 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/intern.rs | ||
| 15 | src/lib.rs upstream modified 6a6eea650debc7897e6a58c9ced5b4c3454be711 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/lib.rs | ||
| 16 | src/myers.rs upstream modified 2ace530c0e282436c1b639e5ce89bcf3a1a6b901 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers.rs | ||
| 17 | src/myers/middle_snake.rs upstream modified a5cb5197c948821f5da2d377bdc729152745f9d4 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers/middle_snake.rs | ||
| 18 | src/myers/preprocess.rs upstream modified 2ef5debd763f5859bc73ad0c54b6d558b1db44ec git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers/preprocess.rs | ||
| 19 | src/myers/slice.rs upstream unchanged f266fa7e17f07eb4a8c6d61fa942607a4beca52b git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers/slice.rs | ||
| 20 | src/postprocess.rs upstream modified 651b12b3a49019a6e2238d51c38d137c09f3ba27 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/postprocess.rs | ||
| 21 | src/slider_heuristic.rs upstream modified f3f85914427df381dcee42e44d406cb54663f91c git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/slider_heuristic.rs | ||
| 22 | src/sources.rs upstream modified e8ddcfc592b0a8b287b1b6923408ac91e79dbe50 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/sources.rs | ||
| 23 | src/unified_diff.rs upstream modified 725331afc30774b0ecc0d85cca804a94b7751578 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/unified_diff.rs | ||
| 24 | src/util.rs upstream modified e85c3aa9ab46352d4d729acc7b86d4ac1be594d6 git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/util.rs | ||
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram.rs | ||
| 3 | |||
| 1 | use crate::histogram::lcs::find_lcs; | 4 | use crate::histogram::lcs::find_lcs; |
| 2 | use crate::histogram::list_pool::{ListHandle, ListPool}; | 5 | use crate::histogram::list_pool::{ListHandle, ListPool}; |
| 3 | use crate::intern::Token; | 6 | use crate::intern::Token; |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram/lcs.rs | ||
| 3 | |||
| 1 | use crate::histogram::{Histogram, MAX_CHAIN_LEN}; | 4 | use crate::histogram::{Histogram, MAX_CHAIN_LEN}; |
| 2 | use crate::intern::Token; | 5 | use crate::intern::Token; |
| 3 | 6 | ||
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/histogram/list_pool.rs | ||
| 3 | |||
| 1 | use crate::histogram::MAX_CHAIN_LEN; | 4 | use crate::histogram::MAX_CHAIN_LEN; |
| 2 | 5 | ||
| 3 | /// A small list of entity references allocated from a pool. | 6 | /// A small list of entity references allocated from a pool. |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/intern.rs | ||
| 3 | |||
| 1 | use std::hash::{BuildHasher as _, Hash}; | 4 | use std::hash::{BuildHasher as _, Hash}; |
| 2 | use std::ops::Index; | 5 | use std::ops::Index; |
| 3 | 6 | ||
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/lib.rs | ||
| 3 | |||
| 1 | #![deny(missing_docs)] | 4 | #![deny(missing_docs)] |
| 2 | //! Imara-diff is a solid (imara in Swahili) diff library for Rust. | 5 | //! Imara-diff is a solid (imara in Swahili) diff library for Rust. |
| 3 | //! Solid refers to the fact that imara-diff provides very good runtime performance even | 6 | //! Solid refers to the fact that imara-diff provides very good runtime performance even |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers.rs | ||
| 3 | |||
| 1 | use std::ptr::NonNull; | 4 | use std::ptr::NonNull; |
| 2 | 5 | ||
| 3 | use crate::intern::Token; | 6 | use crate::intern::Token; |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers/middle_snake.rs | ||
| 3 | |||
| 1 | use std::ptr::NonNull; | 4 | use std::ptr::NonNull; |
| 2 | 5 | ||
| 3 | use crate::myers::slice::FileSlice; | 6 | use crate::myers::slice::FileSlice; |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/myers/preprocess.rs | ||
| 3 | |||
| 1 | use crate::intern::Token; | 4 | use crate::intern::Token; |
| 2 | use crate::myers::sqrt; | 5 | use crate::myers::sqrt; |
| 3 | 6 | ||
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/postprocess.rs | ||
| 3 | |||
| 1 | use crate::intern::{InternedInput, Token}; | 4 | use crate::intern::{InternedInput, Token}; |
| 2 | use crate::slider_heuristic::SliderHeuristic; | 5 | use crate::slider_heuristic::SliderHeuristic; |
| 3 | use crate::util::{find_hunk_end, find_hunk_start}; | 6 | use crate::util::{find_hunk_end, find_hunk_start}; |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/slider_heuristic.rs | ||
| 3 | |||
| 1 | use std::cmp::Ordering; | 4 | use std::cmp::Ordering; |
| 2 | use std::hash::Hash; | 5 | use std::hash::Hash; |
| 3 | use std::ops::{Add, Range}; | 6 | use std::ops::{Add, Range}; |
| @@ -1,3 +1,6 @@ | |||
| 1 | //! Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | //! Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/sources.rs | ||
| 3 | //! | ||
| 1 | //! Utilities for creating token sources from common data types. | 4 | //! Utilities for creating token sources from common data types. |
| 2 | //! | 5 | //! |
| 3 | //! This module provides implementations of [`TokenSource`] for | 6 | //! This module provides implementations of [`TokenSource`] for |
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/unified_diff.rs | ||
| 3 | |||
| 1 | use std::fmt::{self, Display}; | 4 | use std::fmt::{self, Display}; |
| 2 | use std::hash::Hash; | 5 | use std::hash::Hash; |
| 3 | 6 | ||
| @@ -1,3 +1,6 @@ | |||
| 1 | // Modified for gitoxide from the upstream imara-diff crate. | ||
| 2 | // Upstream source: git cat-file -p 32d1e45d3df061e6ccba6db7fdce92db29e345d8:src/util.rs | ||
| 3 | |||
| 1 | use crate::intern::Token; | 4 | use crate::intern::Token; |
| 2 | use crate::Hunk; | 5 | use crate::Hunk; |
| 3 | 6 | ||
| @@ -0,0 +1,219 @@ | |||
| 1 | //! Verifies that the published `gix-imara-diff` package has explicit provenance metadata for every | ||
| 2 | //! packaged file, and that files tracked as upstream or modified still match the | ||
| 3 | //! `UPSTREAM-PROVENANCE.tsv` manifest. | ||
| 4 | |||
| 5 | use std::collections::{BTreeMap, BTreeSet}; | ||
| 6 | use std::env; | ||
| 7 | use std::fs; | ||
| 8 | use std::path::{Path, PathBuf}; | ||
| 9 | use std::process::Command; | ||
| 10 | |||
| 11 | #[derive(Debug)] | ||
| 12 | struct Provenance { | ||
| 13 | upstream_commit: String, | ||
| 14 | entries: BTreeMap<String, Entry>, | ||
| 15 | } | ||
| 16 | |||
| 17 | #[derive(Debug)] | ||
| 18 | struct Entry { | ||
| 19 | origin: String, | ||
| 20 | status: String, | ||
| 21 | upstream_blob: String, | ||
| 22 | cat_file: String, | ||
| 23 | } | ||
| 24 | |||
| 25 | /// Verifies the release-time provenance contract for the `gix-imara-diff` package. | ||
| 26 | /// | ||
| 27 | /// Specifically, it checks that: | ||
| 28 | /// - every file that would be included by `cargo package` has exactly one matching entry in | ||
| 29 | /// `UPSTREAM-PROVENANCE.tsv` | ||
| 30 | /// - upstream-derived files record the expected upstream commit and retrieval command | ||
| 31 | /// - upstream files marked `unchanged` still match the recorded upstream blob | ||
| 32 | /// - upstream files marked `modified` no longer match upstream and carry an in-file notice that | ||
| 33 | /// they were changed, along with the upstream retrieval command | ||
| 34 | /// - generated and local-only files do not claim an upstream blob or retrieval command | ||
| 35 | #[test] | ||
| 36 | #[cfg(unix)] | ||
| 37 | fn packaged_files_have_matching_provenance_and_modified_files_have_notices() { | ||
| 38 | let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
| 39 | let workspace_root = manifest_dir | ||
| 40 | .parent() | ||
| 41 | .expect("workspace root is the parent of the crate manifest directory"); | ||
| 42 | let provenance_path = manifest_dir.join("UPSTREAM-PROVENANCE.tsv"); | ||
| 43 | let provenance = parse_provenance(&provenance_path); | ||
| 44 | let packaged_files = cargo_package_list(workspace_root); | ||
| 45 | |||
| 46 | let packaged_set: BTreeSet<_> = packaged_files.into_iter().collect(); | ||
| 47 | let manifest_set: BTreeSet<_> = provenance.entries.keys().cloned().collect(); | ||
| 48 | assert_eq!( | ||
| 49 | manifest_set, packaged_set, | ||
| 50 | "package surface and provenance manifest diverged" | ||
| 51 | ); | ||
| 52 | |||
| 53 | for (path, entry) in &provenance.entries { | ||
| 54 | match entry.origin.as_str() { | ||
| 55 | "upstream" => { | ||
| 56 | assert_ne!( | ||
| 57 | entry.upstream_blob, "-", | ||
| 58 | "{path}: upstream files need an upstream blob id" | ||
| 59 | ); | ||
| 60 | let expected_cat_file = format!("git cat-file -p {}:{}", provenance.upstream_commit, path); | ||
| 61 | assert_eq!( | ||
| 62 | entry.cat_file, expected_cat_file, | ||
| 63 | "{path}: upstream retrieval command must point at the recorded upstream commit" | ||
| 64 | ); | ||
| 65 | |||
| 66 | let file_path = manifest_dir.join(path); | ||
| 67 | assert!( | ||
| 68 | file_path.is_file(), | ||
| 69 | "{path}: upstream-backed packaged files must exist on disk" | ||
| 70 | ); | ||
| 71 | |||
| 72 | let is_modified = is_modified_from_upstream(&file_path, &entry.upstream_blob); | ||
| 73 | match entry.status.as_str() { | ||
| 74 | "modified" => { | ||
| 75 | assert!( | ||
| 76 | is_modified, | ||
| 77 | "{path}: manifest says modified but current blob matches upstream" | ||
| 78 | ); | ||
| 79 | assert_has_notice(&file_path, &expected_cat_file); | ||
| 80 | } | ||
| 81 | "unchanged" => { | ||
| 82 | assert!( | ||
| 83 | !is_modified, | ||
| 84 | "{path}: manifest says unchanged but current blob no longer matches upstream" | ||
| 85 | ); | ||
| 86 | } | ||
| 87 | other => panic!("{path}: unexpected upstream status {other}"), | ||
| 88 | } | ||
| 89 | } | ||
| 90 | "generated" => { | ||
| 91 | assert_eq!( | ||
| 92 | entry.status, "generated", | ||
| 93 | "{path}: generated files must use generated status" | ||
| 94 | ); | ||
| 95 | assert_eq!( | ||
| 96 | entry.upstream_blob, "-", | ||
| 97 | "{path}: generated files must not have upstream blobs" | ||
| 98 | ); | ||
| 99 | assert_eq!( | ||
| 100 | entry.cat_file, "-", | ||
| 101 | "{path}: generated files must not have upstream cat-file commands" | ||
| 102 | ); | ||
| 103 | } | ||
| 104 | "local-only" => { | ||
| 105 | assert_eq!( | ||
| 106 | entry.status, "local-only", | ||
| 107 | "{path}: local-only files must use local-only status" | ||
| 108 | ); | ||
| 109 | assert_eq!( | ||
| 110 | entry.upstream_blob, "-", | ||
| 111 | "{path}: local-only files must not have upstream blobs" | ||
| 112 | ); | ||
| 113 | assert_eq!( | ||
| 114 | entry.cat_file, "-", | ||
| 115 | "{path}: local-only files must not have upstream cat-file commands" | ||
| 116 | ); | ||
| 117 | } | ||
| 118 | other => panic!("{path}: unknown origin {other}"), | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | fn parse_provenance(tsv_path: &Path) -> Provenance { | ||
| 124 | let mut upstream_commit = None; | ||
| 125 | let mut entries = BTreeMap::new(); | ||
| 126 | |||
| 127 | for line in fs::read_to_string(tsv_path) | ||
| 128 | .expect("provenance manifest to be readable") | ||
| 129 | .lines() | ||
| 130 | { | ||
| 131 | if line.is_empty() { | ||
| 132 | continue; | ||
| 133 | } | ||
| 134 | if let Some(rest) = line.strip_prefix("# upstream-commit: ") { | ||
| 135 | upstream_commit = Some(rest.to_owned()); | ||
| 136 | continue; | ||
| 137 | } | ||
| 138 | if line.starts_with('#') { | ||
| 139 | continue; | ||
| 140 | } | ||
| 141 | |||
| 142 | let mut fields = line.split('\t'); | ||
| 143 | let path = fields.next().expect("path").to_owned(); | ||
| 144 | let origin = fields.next().expect("origin").to_owned(); | ||
| 145 | let status = fields.next().expect("status").to_owned(); | ||
| 146 | let upstream_blob = fields.next().expect("blob").to_owned(); | ||
| 147 | let cat_file = fields.next().expect("cat-file").to_owned(); | ||
| 148 | assert!( | ||
| 149 | fields.next().is_none(), | ||
| 150 | "{path}: provenance entries must have exactly five tab-separated columns" | ||
| 151 | ); | ||
| 152 | let previous = entries.insert( | ||
| 153 | path.clone(), | ||
| 154 | Entry { | ||
| 155 | origin, | ||
| 156 | status, | ||
| 157 | upstream_blob, | ||
| 158 | cat_file, | ||
| 159 | }, | ||
| 160 | ); | ||
| 161 | assert!(previous.is_none(), "{path}: duplicate provenance entry"); | ||
| 162 | } | ||
| 163 | |||
| 164 | Provenance { | ||
| 165 | upstream_commit: upstream_commit.expect("provenance manifest to record upstream commit"), | ||
| 166 | entries, | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | fn cargo_package_list(workspace_root: &Path) -> Vec<String> { | ||
| 171 | let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_owned()); | ||
| 172 | let output = Command::new(cargo) | ||
| 173 | .arg("package") | ||
| 174 | .arg("-p") | ||
| 175 | .arg("gix-imara-diff") | ||
| 176 | .arg("--allow-dirty") | ||
| 177 | .arg("--list") | ||
| 178 | .current_dir(workspace_root) | ||
| 179 | .output() | ||
| 180 | .expect("cargo package --list to run"); | ||
| 181 | assert!( | ||
| 182 | output.status.success(), | ||
| 183 | "cargo package --list failed: {}", | ||
| 184 | String::from_utf8_lossy(&output.stderr) | ||
| 185 | ); | ||
| 186 | |||
| 187 | String::from_utf8(output.stdout) | ||
| 188 | .expect("cargo package --list output to be utf8") | ||
| 189 | .lines() | ||
| 190 | .filter(|line| !line.is_empty()) | ||
| 191 | .map(ToOwned::to_owned) | ||
| 192 | .collect() | ||
| 193 | } | ||
| 194 | |||
| 195 | fn is_modified_from_upstream(path: &Path, upstream_blob: &str) -> bool { | ||
| 196 | let current = fs::read(path).expect("file content to be readable"); | ||
| 197 | git_blob(¤t) != upstream_blob | ||
| 198 | } | ||
| 199 | |||
| 200 | fn git_blob(input: &[u8]) -> String { | ||
| 201 | gix_object::compute_hash(gix_hash::Kind::Sha1, gix_object::Kind::Blob, input) | ||
| 202 | .expect("blob hash to be computable") | ||
| 203 | .to_string() | ||
| 204 | } | ||
| 205 | |||
| 206 | fn assert_has_notice(path: &Path, cat_file: &str) { | ||
| 207 | let content = fs::read_to_string(path).expect("modified text file to be readable as utf8"); | ||
| 208 | assert!( | ||
| 209 | content.contains("Modified for gitoxide from the upstream imara-diff crate."), | ||
| 210 | "{}: modified upstream-derived files must carry a prominent modification notice", | ||
| 211 | path.display() | ||
| 212 | ); | ||
| 213 | let expected = format!("Upstream source: {cat_file}"); | ||
| 214 | assert!( | ||
| 215 | content.contains(&expected), | ||
| 216 | "{}: modified upstream-derived files must record the upstream retrieval command", | ||
| 217 | path.display() | ||
| 218 | ); | ||
| 219 | } | ||