Skip to content

Commit

Permalink
feat: add support for write::Options::skip_hash.
Browse files Browse the repository at this point in the history
With it, a hash will not be produced for indices.
  • Loading branch information
Byron committed Aug 27, 2023
1 parent d3ac691 commit 2f42132
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 14 deletions.
27 changes: 16 additions & 11 deletions gix-index/src/file/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,28 @@ impl File {
mut out: impl std::io::Write,
options: write::Options,
) -> std::io::Result<(Version, gix_hash::ObjectId)> {
let mut hasher = hash::Write::new(&mut out, self.state.object_hash);
let version = self.state.write_to(&mut hasher, options)?;

let hash = hasher.hash.digest();
out.write_all(&hash)?;
Ok((version, gix_hash::ObjectId::from(hash)))
let (version, hash) = if options.skip_hash {
let out: &mut dyn std::io::Write = &mut out;
let version = self.state.write_to(out, options)?;
(version, self.state.object_hash.null())
} else {
let mut hasher = hash::Write::new(&mut out, self.state.object_hash);
let out: &mut dyn std::io::Write = &mut hasher;
let version = self.state.write_to(out, options)?;
(version, gix_hash::ObjectId::from(hasher.hash.digest()))
};
out.write_all(hash.as_slice())?;
Ok((version, hash))
}

/// Write ourselves to the path we were read from after acquiring a lock, using `options`.
///
/// Note that the hash produced will be stored which is why we need to be mutable.
pub fn write(&mut self, options: write::Options) -> Result<(), Error> {
let mut lock = std::io::BufWriter::new(gix_lock::File::acquire_to_update_resource(
&self.path,
gix_lock::acquire::Fail::Immediately,
None,
)?);
let mut lock = std::io::BufWriter::with_capacity(
64 * 1024,
gix_lock::File::acquire_to_update_resource(&self.path, gix_lock::acquire::Fail::Immediately, None)?,
);
let (version, digest) = self.write_to(&mut lock, options)?;
match lock.into_inner() {
Ok(lock) => lock.commit()?,
Expand Down
17 changes: 15 additions & 2 deletions gix-index/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,26 @@ impl Extensions {
/// Note that default options write either index V2 or V3 depending on the content of the entries.
#[derive(Debug, Default, Clone, Copy)]
pub struct Options {
/// Configures which extensions to write
/// Configures which extensions to write.
pub extensions: Extensions,
/// Set the trailing hash of the produced index to all zeroes to save some time.
///
/// This value is typically controlled by `index.skipHash` and is respected when the index is written
/// via [`File::write()`](crate::File::write()) and [`File::write_to()`](crate::File::write_to()).
/// Note that
pub skip_hash: bool,
}

impl State {
/// Serialize this instance to `out` with [`options`][Options].
pub fn write_to(&self, out: impl std::io::Write, Options { extensions }: Options) -> std::io::Result<Version> {
pub fn write_to(
&self,
out: impl std::io::Write,
Options {
extensions,
skip_hash: _,
}: Options,
) -> std::io::Result<Version> {
let _span = gix_features::trace::detail!("gix_index::State::write()");
let version = self.detect_required_version();

Expand Down
37 changes: 36 additions & 1 deletion gix-index/tests/index/file/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@ fn roundtrips() -> crate::Result {
Ok(())
}

#[test]
fn skip_hash() -> crate::Result {
let tmp = gix_testtools::tempfile::TempDir::new()?;
let path = tmp.path().join("index");
let mut expected = Loose("conflicting-file").open();
assert!(expected.checksum().is_some());

expected.set_path(&path);
expected.write(Options {
extensions: Default::default(),
skip_hash: false,
})?;

let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?;
assert_eq!(
actual.checksum(),
expected.checksum(),
"a hash is written by default and it matches"
);

expected.write(Options {
extensions: Default::default(),
skip_hash: true,
})?;

let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?;
assert_eq!(actual.checksum(), None, "no hash is produced in this case");

Ok(())
}

#[test]
fn roundtrips_sparse_index() -> crate::Result {
// NOTE: I initially tried putting these fixtures into the main roundtrip test above,
Expand Down Expand Up @@ -253,9 +284,13 @@ fn only_tree_ext() -> Options {
end_of_index_entry: false,
tree_cache: true,
},
skip_hash: false,
}
}

fn options_with(extensions: write::Extensions) -> Options {
Options { extensions }
Options {
extensions,
skip_hash: false,
}
}

0 comments on commit 2f42132

Please sign in to comment.