Skip to content

Commit 011316e

Browse files
codexByron
andcommitted
feat: Add SHA-256 support for object-format parsing.
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
1 parent 04c894e commit 011316e

23 files changed

Lines changed: 441 additions & 170 deletions

File tree

gix/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ document-features = { version = "0.2.0", optional = true }
426426
[dev-dependencies]
427427
# For additional features that aren't enabled by default due to MSRV
428428
gix = { path = ".", default-features = false, features = [
429-
"need-more-recent-msrv", "tree-error", "sha1"
429+
"need-more-recent-msrv", "tree-error", "sha1", "sha256"
430430
] }
431431
gix-hash = { version = "^0.25.0", path = "../gix-hash" }
432432
pretty_assertions = "1.4.0"

gix/src/config/tree/sections/extensions.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ mod object_format {
2626
&'static self,
2727
value: Cow<'_, BStr>,
2828
) -> Result<gix_hash::Kind, config::key::GenericErrorWithValue> {
29+
#[cfg(feature = "sha1")]
2930
if value.as_ref().eq_ignore_ascii_case(b"sha1") {
30-
Ok(gix_hash::Kind::Sha1)
31-
} else {
32-
Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned()))
31+
return Ok(gix_hash::Kind::Sha1);
3332
}
33+
34+
#[cfg(feature = "sha256")]
35+
if value.as_ref().eq_ignore_ascii_case(b"sha256") {
36+
return Ok(gix_hash::Kind::Sha256);
37+
}
38+
39+
Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned()))
3440
}
3541
}
3642
}
Binary file not shown.
Binary file not shown.

gix/tests/fixtures/make_rev_parse_repo.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/env bash
22
set -eu -o pipefail
33

4+
# This fixture embeds historical SHA-1 reflog entries verbatim.
5+
export GIT_DEFAULT_HASH=sha1
6+
47
git init -q
58
touch new && git add new && git commit -m "init"
69

@@ -593,4 +596,4 @@ ca54b8c67eb6c81b7175f62ee74a0d5aab6f52cc 000000000000000000000000000000000000000
593596
ca54b8c67eb6c81b7175f62ee74a0d5aab6f52cc 0000000000000000000000000000000000000000 Sebastian Thiel <sebastian.thiel@icloud.com> 1734789302 +0100 Branch: renamed refs/heads/reflog-parseing to refs/heads/reflog-parsing
594597
0000000000000000000000000000000000000000 ca54b8c67eb6c81b7175f62ee74a0d5aab6f52cc Sebastian Thiel <sebastian.thiel@icloud.com> 1734789302 +0100 Branch: renamed refs/heads/reflog-parseing to refs/heads/reflog-parsing
595598
87b0acf0e9cac2781312bd478df0ae72ec6d194b 4d4a9b6e372b3f6d8beabc82a6bf63d5b3f84e21 Sebastian Thiel <sebastian.thiel@icloud.com> 1734789364 +0100 checkout: moving from reflog-parsing to refloglookup-date
596-
EOF
599+
EOF

gix/tests/fixtures/make_rev_spec_parse_repos.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/env bash
22
set -eu -o pipefail
33

4+
# This fixture is based on Git's SHA-1 disambiguation tests and relies on
5+
# exact SHA-1 prefixes in object names, refs, and expected messages.
6+
export GIT_DEFAULT_HASH=sha1
47

58
function baseline() {
69
local spec=${1:?first argument is the spec to test}

gix/tests/gix/config/tree.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -692,23 +692,39 @@ mod extensions {
692692

693693
#[test]
694694
fn object_format() -> crate::Result {
695-
assert_eq!(
696-
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("sha1"))?,
697-
gix_hash::Kind::Sha1
698-
);
699-
assert_eq!(
700-
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("SHA1"))?,
701-
gix_hash::Kind::Sha1,
702-
"case-insensitive"
703-
);
695+
#[cfg(feature = "sha1")]
696+
{
697+
assert_eq!(
698+
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("sha1"))?,
699+
gix_hash::Kind::Sha1
700+
);
701+
assert_eq!(
702+
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("SHA1"))?,
703+
gix_hash::Kind::Sha1,
704+
"case-insensitive"
705+
);
706+
assert!(Extensions::OBJECT_FORMAT.validate("sha1".into()).is_ok());
707+
}
708+
#[cfg(feature = "sha256")]
709+
{
710+
assert_eq!(
711+
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("sha256"))?,
712+
gix_hash::Kind::Sha256
713+
);
714+
assert_eq!(
715+
Extensions::OBJECT_FORMAT.try_into_object_format(bcow("SHA256"))?,
716+
gix_hash::Kind::Sha256,
717+
"case-insensitive"
718+
);
719+
assert!(Extensions::OBJECT_FORMAT.validate("sha256".into()).is_ok());
720+
}
704721
assert_eq!(
705722
Extensions::OBJECT_FORMAT
706723
.try_into_object_format(bcow("invalid"))
707724
.unwrap_err()
708725
.to_string(),
709726
"The key \"extensions.objectFormat=invalid\" was invalid"
710727
);
711-
assert!(Extensions::OBJECT_FORMAT.validate("sha1".into()).is_ok());
712728
assert!(Extensions::OBJECT_FORMAT.validate("invalid".into()).is_err());
713729
Ok(())
714730
}

gix/tests/gix/id.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
use std::cmp::Ordering;
22

3+
use crate::util::hex_to_id;
34
use gix::{
45
config::tree::{Core, Key},
56
prelude::ObjectIdExt,
67
};
78
use gix_object::bstr::BString;
89

9-
/// Convert a hexadecimal hash into its corresponding `ObjectId` or _panic_.
10-
fn hex_to_id(hex: &str) -> gix_hash::ObjectId {
11-
gix_hash::ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex")
12-
}
13-
1410
#[test]
1511
fn prefix() -> crate::Result {
1612
let repo = crate::repo("make_repo_with_fork_and_dates.sh")?.to_thread_local();
@@ -59,15 +55,17 @@ fn prefix() -> crate::Result {
5955
fn display_and_debug() -> crate::Result {
6056
let repo = crate::basic_repo()?;
6157
let id = repo.head_id()?;
62-
assert_eq!(
63-
format!("{id} {id:?}"),
64-
"3189cd3cb0af8586c39a838aa3e54fd72a872a41 Sha1(3189cd3cb0af8586c39a838aa3e54fd72a872a41)"
65-
);
58+
let kind = match id.kind() {
59+
gix_hash::Kind::Sha1 => "Sha1",
60+
gix_hash::Kind::Sha256 => "Sha256",
61+
_ => unimplemented!(),
62+
};
63+
assert_eq!(format!("{id} {id:?}"), format!("{id} {kind}({id})"));
6664
Ok(())
6765
}
6866

6967
mod ancestors {
70-
use crate::id::hex_to_id;
68+
use crate::util::hex_to_id;
7169

7270
#[test]
7371
fn all() -> crate::Result {

gix/tests/gix/object/commit.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
use std::cmp::Ordering;
22

3-
/// Convert a hexadecimal hash into its corresponding `ObjectId` or _panic_.
4-
fn hex_to_id(hex: &str) -> gix_hash::ObjectId {
5-
gix_hash::ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex")
6-
}
7-
8-
use crate::basic_repo;
3+
use crate::{basic_repo, util::hex_to_id};
94

105
#[test]
116
fn short_id() -> crate::Result {

gix/tests/gix/object/tree/diff.rs

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -81,31 +81,59 @@ fn changes_against_tree_modified() -> crate::Result {
8181
assert_eq!(i, 3);
8282

8383
let actual = repo.diff_tree_to_tree(&from, &to, None)?;
84-
insta::assert_debug_snapshot!(actual, @r#"
85-
[
86-
Modification {
87-
location: "a",
88-
previous_entry_mode: EntryMode(0o100644),
89-
previous_id: Sha1(78981922613b2afb6025042ff6bd878ac1994e85),
90-
entry_mode: EntryMode(0o100644),
91-
id: Sha1(b4f17b61de71d9b2e54ac9e62b1629ae2d97a6a7),
92-
},
93-
Modification {
94-
location: "dir",
95-
previous_entry_mode: EntryMode(0o40000),
96-
previous_id: Sha1(e5c63aefe4327cb1c780c71966b678ce8e4225da),
97-
entry_mode: EntryMode(0o40000),
98-
id: Sha1(c7ac5f82f536976f3561c9999b5f11e5893358be),
99-
},
100-
Modification {
101-
location: "dir/c",
102-
previous_entry_mode: EntryMode(0o100644),
103-
previous_id: Sha1(6695780ceb14b05e076a99bbd2babf34723b3464),
104-
entry_mode: EntryMode(0o100644),
105-
id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
106-
},
107-
]
108-
"#);
84+
match repo.object_hash() {
85+
gix::hash::Kind::Sha1 => insta::assert_debug_snapshot!(actual, @r#"
86+
[
87+
Modification {
88+
location: "a",
89+
previous_entry_mode: EntryMode(0o100644),
90+
previous_id: Sha1(78981922613b2afb6025042ff6bd878ac1994e85),
91+
entry_mode: EntryMode(0o100644),
92+
id: Sha1(b4f17b61de71d9b2e54ac9e62b1629ae2d97a6a7),
93+
},
94+
Modification {
95+
location: "dir",
96+
previous_entry_mode: EntryMode(0o40000),
97+
previous_id: Sha1(e5c63aefe4327cb1c780c71966b678ce8e4225da),
98+
entry_mode: EntryMode(0o40000),
99+
id: Sha1(c7ac5f82f536976f3561c9999b5f11e5893358be),
100+
},
101+
Modification {
102+
location: "dir/c",
103+
previous_entry_mode: EntryMode(0o100644),
104+
previous_id: Sha1(6695780ceb14b05e076a99bbd2babf34723b3464),
105+
entry_mode: EntryMode(0o100644),
106+
id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
107+
},
108+
]
109+
"#),
110+
gix::hash::Kind::Sha256 => insta::assert_debug_snapshot!(actual, @r#"
111+
[
112+
Modification {
113+
location: "a",
114+
previous_entry_mode: EntryMode(0o100644),
115+
previous_id: Sha256(f8625e43f9e04f24291f77cdbe4c71b3c2a3b0003f60419b3ed06a058d766c8b),
116+
entry_mode: EntryMode(0o100644),
117+
id: Sha256(6eba3a291223ebd59db7f157409b70bb1f929be92ed8df0fba98cb81852ff378),
118+
},
119+
Modification {
120+
location: "dir",
121+
previous_entry_mode: EntryMode(0o40000),
122+
previous_id: Sha256(0d8c11bd683002c6f7c29c94e952cc3ebe2e0e10bd781846285998a509ebd746),
123+
entry_mode: EntryMode(0o40000),
124+
id: Sha256(730477dc62b02d7046105a95e8c37dc204943f24c70da12d33a88012ac7d2613),
125+
},
126+
Modification {
127+
location: "dir/c",
128+
previous_entry_mode: EntryMode(0o100644),
129+
previous_id: Sha256(b7bb7be9f73f0d01719f57dcb697689692e2ae9737f4bb59216902b9a0e2adb1),
130+
entry_mode: EntryMode(0o100644),
131+
id: Sha256(8cf8e3576bb1c632c9f2e1196d2aa6b1ae36c6f651d7619dca4894b784065819),
132+
},
133+
]
134+
"#),
135+
_ => unreachable!(),
136+
}
109137

110138
assert_eq!(
111139
from.changes()?.stats(&to)?,
@@ -140,6 +168,11 @@ mod track_rewrites {
140168
ignore = "Fails on some Window systems, like the fixture doesn't get set up correctly."
141169
)]
142170
fn jj_realistic_needs_to_be_more_clever() -> crate::Result {
171+
// The test case only works (and is only needed) for SHA-1.
172+
// Ideally this can be ported to SHA-256 once rename tracking is par with Git.
173+
if gix_testtools::object_hash() == gix::hash::Kind::Sha256 {
174+
return Ok(());
175+
}
143176
let repo = named_subrepo_opts("make_diff_repos.sh", "jj-trackcopy-1", gix::open::Options::isolated())?;
144177

145178
let mut expected = HashMap::<&BStr, (&BStr, u32)>::new();
@@ -419,6 +452,11 @@ mod track_rewrites {
419452
ignore = "Fails on some Window systems, like the fixture doesn't get set up correctly."
420453
)]
421454
fn jj_realistic_directory_rename() -> crate::Result {
455+
// The test case only works (and is only needed) for SHA-1.
456+
// Ideally this can be ported to SHA-256 once rename tracking is par with Git.
457+
if gix_testtools::object_hash() == gix::hash::Kind::Sha256 {
458+
return Ok(());
459+
}
422460
let repo = named_subrepo_opts("make_diff_repos.sh", "jj-trackcopy-1", gix::open::Options::isolated())?;
423461

424462
let from = tree_named(&repo, "@~1");

0 commit comments

Comments
 (0)