Skip to content

Commit

Permalink
Merge branch 'main' into gix-clone
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Oct 14, 2022
2 parents e462bd5 + 375051f commit de4fe06
Show file tree
Hide file tree
Showing 31 changed files with 428 additions and 211 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions git-index/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ git-hash = { version = "^0.9.11", path = "../git-hash" }
git-bitmap = { version = "^0.1.2", path = "../git-bitmap" }
git-object = { version = "^0.22.0", path = "../git-object" }
git-traverse = { version = "^0.18.0", path = "../git-traverse" }
git-lock = { version = "2.1.1", path = "../git-lock" }

thiserror = "1.0.32"
memmap2 = "0.5.0"
Expand Down
5 changes: 5 additions & 0 deletions git-index/src/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ impl State {
self.version
}

/// Return the kind of hashes used in this instance.
pub fn object_hash(&self) -> git_hash::Kind {
self.object_hash
}

/// Return our entries
pub fn entries(&self) -> &[Entry] {
&self.entries
Expand Down
10 changes: 5 additions & 5 deletions git-index/src/decode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ use git_features::parallel::InOrderIter;
use crate::util::read_u32;

/// Options to define how to decode an index state [from bytes][State::from_bytes()].
#[derive(Default)]
#[derive(Default, Clone, Copy)]
pub struct Options {
/// The kind of object hash to assume when decoding object ids.
pub object_hash: git_hash::Kind,
/// If Some(_), we are allowed to use more than one thread. If Some(N), use no more than N threads. If Some(0)|None, use as many threads
/// as there are logical cores.
///
Expand All @@ -46,12 +44,13 @@ pub struct Options {
}

impl State {
/// Decode an index state from `data` and store `timestamp` in the resulting instance for pass-through.
/// Decode an index state from `data` and store `timestamp` in the resulting instance for pass-through, assuming `object_hash`
/// to be used through the file.
pub fn from_bytes(
data: &[u8],
timestamp: FileTime,
object_hash: git_hash::Kind,
Options {
object_hash,
thread_limit,
min_extension_block_in_bytes_for_threading,
}: Options,
Expand Down Expand Up @@ -210,6 +209,7 @@ impl State {

Ok((
State {
object_hash,
timestamp,
version,
entries,
Expand Down
23 changes: 19 additions & 4 deletions git-index/src/file/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pub use error::Error;

/// Initialization
impl File {
/// Open an index file at `path` with `options`.
pub fn at(path: impl Into<PathBuf>, options: decode::Options) -> Result<Self, Error> {
/// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file.
pub fn at(path: impl Into<PathBuf>, object_hash: git_hash::Kind, options: decode::Options) -> Result<Self, Error> {
let path = path.into();
let (data, mtime) = {
// SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file.
Expand All @@ -34,7 +34,22 @@ impl File {
(data, filetime::FileTime::from_last_modification_time(&file.metadata()?))
};

let (state, checksum) = State::from_bytes(&data, mtime, options)?;
Ok(File { state, path, checksum })
let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?;
Ok(File {
state,
path,
checksum: Some(checksum),
})
}

/// Consume `state` and pretend it was read from `path`, setting our checksum to `null`.
///
/// `File` instances created like that should be written to disk to set the correct checksum via `[File::write()]`.
pub fn from_state(state: crate::State, path: impl Into<PathBuf>) -> Self {
File {
state,
path: path.into(),
checksum: None,
}
}
}
33 changes: 33 additions & 0 deletions git-index/src/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@ mod impl_ {
}
}
}

mod access {
use crate::File;

/// Consumption
impl File {
/// Take the state and discard the rest.
pub fn into_state(self) -> crate::State {
self.state
}

/// Take all non-copy parts of the index.
pub fn into_parts(self) -> (crate::State, std::path::PathBuf) {
(self.state, self.path)
}
}

/// Access
impl File {
/// The path from which the index was read or to which it is supposed to be written when used with [`File::from_state()`].
pub fn path(&self) -> &std::path::Path {
&self.path
}

/// The checksum over the file that was read or written to disk, or `None` if the state in memory was never serialized.
///
/// Note that even if `Some`, it will only represent the state in memory right after reading or [writing][File::write()].
pub fn checksum(&self) -> Option<git_hash::ObjectId> {
self.checksum
}
}
}

///
pub mod init;
///
Expand Down
11 changes: 7 additions & 4 deletions git-index/src/file/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,28 @@ mod error {
actual: git_hash::ObjectId,
expected: git_hash::ObjectId,
},
#[error("Checksum of in-memory index wasn't computed yet")]
NoChecksum,
}
}
pub use error::Error;

impl File {
/// Verify the integrity of the index to assure its consistency.
pub fn verify_integrity(&self) -> Result<(), Error> {
let num_bytes_to_hash = self.path.metadata()?.len() - self.checksum.as_bytes().len() as u64;
let checksum = self.checksum.ok_or(Error::NoChecksum)?;
let num_bytes_to_hash = self.path.metadata()?.len() - checksum.as_bytes().len() as u64;
let should_interrupt = AtomicBool::new(false);
let actual = git_features::hash::bytes_of_file(
&self.path,
num_bytes_to_hash as usize,
self.checksum.kind(),
checksum.kind(),
&mut git_features::progress::Discard,
&should_interrupt,
)?;
(actual == self.checksum).then(|| ()).ok_or(Error::ChecksumMismatch {
(actual == checksum).then(|| ()).ok_or(Error::ChecksumMismatch {
actual,
expected: self.checksum,
expected: checksum,
})
}
}
41 changes: 38 additions & 3 deletions git-index/src/file/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,50 @@ use git_features::hash;

use crate::{write, File, Version};

/// The error produced by [`File::write()`].
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Could not acquire lock for index file")]
AcquireLock(#[from] git_lock::acquire::Error),
#[error("Could not commit lock for index file")]
CommitLock(#[from] git_lock::commit::Error<git_lock::File>),
}

impl File {
/// Write the index to `out` with `options`, to be readable by [`File::at()`], returning the version that was actually written
/// to retain all information of this index.
pub fn write_to(&self, mut out: impl std::io::Write, options: write::Options) -> std::io::Result<Version> {
let mut hasher = hash::Write::new(&mut out, options.hash_kind);
pub fn write_to(
&self,
mut out: impl std::io::Write,
options: write::Options,
) -> std::io::Result<(Version, git_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)
Ok((version, git_hash::ObjectId::from(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(git_lock::File::acquire_to_update_resource(
&self.path,
git_lock::acquire::Fail::Immediately,
None,
)?);
let (version, digest) = self.write_to(&mut lock, options)?;
match lock.into_inner() {
Ok(lock) => lock.commit()?,
Err(err) => return Err(err.into_error().into()),
};
self.state.version = version;
self.checksum = Some(digest);
Ok(())
}
}
Loading

0 comments on commit de4fe06

Please sign in to comment.