diff --git a/etc/check-package-size.sh b/etc/check-package-size.sh index 0b9c48a5f94..1b9dff874ea 100755 --- a/etc/check-package-size.sh +++ b/etc/check-package-size.sh @@ -41,4 +41,4 @@ echo "in root: gitoxide CLI" (enter git-packetline && indent cargo diet -n --package-size-limit 35KB) (enter git-repository && indent cargo diet -n --package-size-limit 80KB) (enter git-transport && indent cargo diet -n --package-size-limit 50KB) -(enter gitoxide-core && indent cargo diet -n --package-size-limit 50KB) +(enter gitoxide-core && indent cargo diet -n --package-size-limit 60KB) diff --git a/git-worktree/tests/index/mod.rs b/git-worktree/tests/index/mod.rs index d365777f332..ce638a3b056 100644 --- a/git-worktree/tests/index/mod.rs +++ b/git-worktree/tests/index/mod.rs @@ -173,7 +173,14 @@ mod checkout { let odb = git_odb::at(git_dir.join("objects"))?; let destination = tempfile::tempdir()?; - let outcome = index::checkout(&mut index)?; + let outcome = index::checkout( + &mut index, + &destination, + move |oid, buf| odb.find_blob(oid, buf).ok(), + &mut progress::Discard, + &mut progress::Discard, + opts, + )?; Ok((source_tree, destination, index, outcome)) } diff --git a/gitoxide-core/src/index/mod.rs b/gitoxide-core/src/index/mod.rs index bd4f946807a..c7ac6291892 100644 --- a/gitoxide-core/src/index/mod.rs +++ b/gitoxide-core/src/index/mod.rs @@ -101,12 +101,23 @@ fn parse_file(index_path: impl AsRef, object_hash: git::hash::Kind) -> any .map_err(Into::into) } +pub mod checkout_exclusive { + pub struct Options { + pub index: super::Options, + /// If true, all files will be written with zero bytes despite having made an ODB lookup. + pub empty_files: bool, + } +} + pub fn checkout_exclusive( index_path: impl AsRef, dest_directory: impl AsRef, repo: Option, mut progress: impl Progress, - Options { object_hash, .. }: Options, + checkout_exclusive::Options { + index: Options { object_hash, .. }, + empty_files, + }: checkout_exclusive::Options, ) -> anyhow::Result<()> { let repo = repo .map(|dir| git_repository::discover(dir).map(|r| r.apply_environment())) @@ -124,7 +135,7 @@ pub fn checkout_exclusive( let mut index = parse_file(index_path, object_hash)?; let mut num_skipped = 0; - let maybe_symlink_mode = if repo.is_some() { + let maybe_symlink_mode = if !empty_files && repo.is_some() { git::index::entry::Mode::DIR } else { git::index::entry::Mode::SYMLINK @@ -161,7 +172,18 @@ pub fn checkout_exclusive( Some(repo) => git::worktree::index::checkout( &mut index, dest_directory, - |oid, buf| repo.objects.find_blob(oid, buf).ok(), + |oid, buf| { + repo.objects.find_blob(oid, buf).ok(); + if empty_files { + // We always want to query the ODB here… + repo.objects.find_blob(oid, buf).ok(); + buf.clear(); + // …but write nothing + Some(git::objs::BlobRef { data: buf }) + } else { + repo.objects.find_blob(oid, buf).ok() + } + }, &mut files, &mut bytes, opts, diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index c2300926628..22346e55660 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -78,7 +78,11 @@ pub fn main() -> Result<()> { index_path, cmd, }) => match cmd { - index::Subcommands::CheckoutExclusive { directory, repository } => prepare_and_run( + index::Subcommands::CheckoutExclusive { + directory, + empty_files, + repository, + } => prepare_and_run( "index-checkout", verbose, progress, @@ -90,7 +94,10 @@ pub fn main() -> Result<()> { directory, repository, progress, - core::index::Options { object_hash, format }, + core::index::checkout_exclusive::Options { + index: core::index::Options { object_hash, format }, + empty_files, + }, ) }, ), diff --git a/src/plumbing/options.rs b/src/plumbing/options.rs index 8d01894c3a1..43fda5ca779 100644 --- a/src/plumbing/options.rs +++ b/src/plumbing/options.rs @@ -373,6 +373,10 @@ pub mod index { /// in the index. Use this measure the impact on extracting objects on overall performance. #[clap(long, short = 'r')] repository: Option, + /// Enable to query the object database yet write only empty files. This is useful to measure the overhead of ODB query + /// compared to writing the bytes to disk. + #[clap(long, short = 'e', requires = "repository")] + empty_files: bool, /// The directory into which to write all index entries. directory: PathBuf, },