diff --git a/Cargo.lock b/Cargo.lock index c55c9e62035..48e8e4da16c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1240,6 +1240,7 @@ dependencies = [ "gix-utils 0.1.5", "gix-validate 0.8.0", "gix-worktree 0.24.0", + "gix-worktree-state", "gix-worktree-stream", "is_ci", "log", @@ -1497,6 +1498,7 @@ dependencies = [ name = "gix-diff" version = "0.34.0" dependencies = [ + "document-features", "getrandom", "gix-hash 0.11.4", "gix-object 0.34.0", @@ -2215,6 +2217,22 @@ dependencies = [ name = "gix-sequencer" version = "0.0.0" +[[package]] +name = "gix-status" +version = "0.1.0" +dependencies = [ + "bstr", + "filetime", + "gix-features 0.32.1", + "gix-fs 0.4.1", + "gix-hash 0.11.4", + "gix-index 0.22.0", + "gix-object 0.34.0", + "gix-path 0.8.4", + "gix-testtools", + "thiserror", +] + [[package]] name = "gix-submodule" version = "0.1.0" @@ -2449,10 +2467,8 @@ version = "0.24.0" dependencies = [ "bstr", "document-features", - "filetime", "gix-attributes 0.16.0", "gix-features 0.32.1", - "gix-filter", "gix-fs 0.4.1", "gix-glob 0.10.2", "gix-hash 0.11.4", @@ -2462,11 +2478,29 @@ dependencies = [ "gix-odb", "gix-path 0.8.4", "gix-testtools", + "serde", + "symlink", +] + +[[package]] +name = "gix-worktree-state" +version = "0.1.0" +dependencies = [ + "bstr", + "gix-features 0.32.1", + "gix-filter", + "gix-fs 0.4.1", + "gix-glob 0.10.2", + "gix-hash 0.11.4", + "gix-index 0.22.0", + "gix-object 0.34.0", + "gix-odb", + "gix-path 0.8.4", + "gix-testtools", + "gix-worktree 0.24.0", "io-close", "once_cell", - "serde", "symlink", - "tempfile", "thiserror", "walkdir", ] diff --git a/Cargo.toml b/Cargo.toml index 9c4ab23793a..6fb4b758a4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -235,6 +235,8 @@ members = [ "gix-index", "gix-bitmap", "gix-worktree", + "gix-worktree-state", + "gix-status", "gix-revision", "gix-packetline", "gix-packetline-blocking", diff --git a/README.md b/README.md index 7b969ad4374..aa3bca6523b 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ is usable to some extent. * [gix-worktree-stream](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-worktree-stream) * [gix-archive](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-archive) * [gix-submodule](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-submodule) + * [gix-status](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-status) + * [gix-worktree-state](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-worktree-state) * `gitoxide-core` * **very early** _(possibly without any documentation and many rough edges)_ * [gix-date](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-date) diff --git a/crate-status.md b/crate-status.md index 89ce8574805..3079e063507 100644 --- a/crate-status.md +++ b/crate-status.md @@ -453,28 +453,36 @@ Make it the best-performing implementation and the most convenient one. ### gix-glob * [x] parse pattern * [x] a type for pattern matching of paths and non-paths, optionally case-insensitively. - -### gix-worktree + +### gix-status +* [x] differences between index and worktree to turn index into worktree +* [ ] differences between tree and index to turn tree into index +* [ ] untracked files +* [ ] fast answer to 'is it dirty'. +* +### gix-worktree-state * handle the working **tree/checkout** - - [x] checkout an index of files, executables and symlinks just as fast as git - - [x] forbid symlinks in directories - - [ ] handle submodules - - [ ] handle sparse directories - - [ ] handle sparse index - - [x] linear scaling with multi-threading up to IO saturation - - supported attributes to affect working tree and index contents - - [ ] eol - - [ ] working-tree-encoding - - …more - - **filtering** - - [ ] `text` - - [ ] `ident` - - [ ] filter processes - - [ ] single-invocation clean/smudge filters -* manage multiple worktrees + - [x] checkout an index of files, executables and symlinks just as fast as git + - [x] forbid symlinks in directories + - [ ] handle submodules + - [ ] handle sparse directories + - [ ] handle sparse index + - [x] linear scaling with multi-threading up to IO saturation + - supported attributes to affect working tree and index contents + - [x] eol + - [x] working-tree-encoding + - …more + - **filtering** + - [x] `text` + - [x] `ident` + - [x] filter processes + - [x] single-invocation clean/smudge filters * access to per-path information, like `.gitignore` and `.gitattributes` in a manner well suited for efficient lookups - * [x] _exclude_ information - * [ ] attributes + * [x] _exclude_ information + * [x] attributes + +### gix-worktree +* [x] A stack to to efficiently generate attribute lists for matching paths against. ### gix-revision * [x] `describe()` (similar to `git name-rev`) diff --git a/etc/gix-components.monopic b/etc/gix-components.monopic new file mode 100644 index 00000000000..d81ae6d00c6 Binary files /dev/null and b/etc/gix-components.monopic differ diff --git a/etc/gix-components.txt b/etc/gix-components.txt new file mode 100644 index 00000000000..6a107dc7bf3 --- /dev/null +++ b/etc/gix-components.txt @@ -0,0 +1,3 @@ +╔════════════════╗ +║ gix-submodule ║ +╚════════════════╝ \ No newline at end of file diff --git a/gitoxide-core/src/hours/core.rs b/gitoxide-core/src/hours/core.rs index ddc6c4dbb28..eb033f954aa 100644 --- a/gitoxide-core/src/hours/core.rs +++ b/gitoxide-core/src/hours/core.rs @@ -101,8 +101,8 @@ pub fn spawn_tree_delta_threads<'scope>( repo.index_or_load_from_head().map_err(Into::into).and_then(|index| { repo.attributes( &index, - gix::worktree::cache::state::attributes::Source::IdMapping, - gix::worktree::cache::state::ignore::Source::IdMapping, + gix::worktree::stack::state::attributes::Source::IdMapping, + gix::worktree::stack::state::ignore::Source::IdMapping, None, ) .map_err(Into::into) diff --git a/gitoxide-core/src/index/checkout.rs b/gitoxide-core/src/index/checkout.rs index d28423e485b..bdfaa3235f0 100644 --- a/gitoxide-core/src/index/checkout.rs +++ b/gitoxide-core/src/index/checkout.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::bail; -use gix::{odb::FindExt, worktree::checkout, Progress}; +use gix::{odb::FindExt, worktree::state::checkout, Progress}; use crate::{ index, @@ -55,7 +55,7 @@ pub fn checkout_exclusive( progress.info(format!("Skipping {num_skipped} DIR/SYMLINK/COMMIT entries")); } - let opts = gix::worktree::checkout::Options { + let opts = gix::worktree::state::checkout::Options { fs: gix::fs::Capabilities::probe(dest_directory), destination_is_initially_empty: true, @@ -86,7 +86,7 @@ pub fn checkout_exclusive( delayed_paths_unknown, delayed_paths_unprocessed, } = match repo { - Some(repo) => gix::worktree::checkout( + Some(repo) => gix::worktree::state::checkout( &mut index, dest_directory, { @@ -109,7 +109,7 @@ pub fn checkout_exclusive( should_interrupt, opts, ), - None => gix::worktree::checkout( + None => gix::worktree::state::checkout( &mut index, dest_directory, |_, buf| { diff --git a/gitoxide-core/src/repository/attributes/query.rs b/gitoxide-core/src/repository/attributes/query.rs index bb90aeccff3..ec777183ee7 100644 --- a/gitoxide-core/src/repository/attributes/query.rs +++ b/gitoxide-core/src/repository/attributes/query.rs @@ -89,16 +89,16 @@ pub(crate) mod function { pub(crate) fn attributes_cache( repo: &gix::Repository, -) -> anyhow::Result<(gix::worktree::Cache, IndexPersistedOrInMemory)> { +) -> anyhow::Result<(gix::worktree::Stack, IndexPersistedOrInMemory)> { let index = repo.index_or_load_from_head()?; let cache = repo.attributes( &index, if repo.is_bare() { - gix::worktree::cache::state::attributes::Source::IdMapping + gix::worktree::stack::state::attributes::Source::IdMapping } else { - gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping + gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping }, - gix::worktree::cache::state::ignore::Source::IdMapping, + gix::worktree::stack::state::ignore::Source::IdMapping, None, )?; Ok((cache, index)) diff --git a/gitoxide-core/src/repository/clone.rs b/gitoxide-core/src/repository/clone.rs index 7e0530ef899..6fec5801335 100644 --- a/gitoxide-core/src/repository/clone.rs +++ b/gitoxide-core/src/repository/clone.rs @@ -111,7 +111,7 @@ pub(crate) mod function { } }; - if let Some(gix::worktree::checkout::Outcome { collisions, errors, .. }) = outcome { + if let Some(gix::worktree::state::checkout::Outcome { collisions, errors, .. }) = outcome { if !(collisions.is_empty() && errors.is_empty()) { let mut messages = Vec::new(); if !errors.is_empty() { diff --git a/gitoxide-core/src/repository/index/entries.rs b/gitoxide-core/src/repository/index/entries.rs index 5b808db085d..9a0a2825d0d 100644 --- a/gitoxide-core/src/repository/index/entries.rs +++ b/gitoxide-core/src/repository/index/entries.rs @@ -56,22 +56,22 @@ pub(crate) mod function { match attrs { Attributes::WorktreeAndIndex => { if repo.is_bare() { - gix::worktree::cache::state::attributes::Source::IdMapping + gix::worktree::stack::state::attributes::Source::IdMapping } else { - gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping + gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping } } - Attributes::Index => gix::worktree::cache::state::attributes::Source::IdMapping, + Attributes::Index => gix::worktree::stack::state::attributes::Source::IdMapping, }, match attrs { Attributes::WorktreeAndIndex => { if repo.is_bare() { - gix::worktree::cache::state::ignore::Source::IdMapping + gix::worktree::stack::state::ignore::Source::IdMapping } else { - gix::worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped + gix::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped } } - Attributes::Index => gix::worktree::cache::state::ignore::Source::IdMapping, + Attributes::Index => gix::worktree::stack::state::ignore::Source::IdMapping, }, None, ) @@ -203,7 +203,7 @@ pub(crate) mod function { pub excluded: usize, pub with_attributes: usize, pub max_attributes_per_path: usize, - pub cache: Option, + pub cache: Option, } #[cfg(feature = "serde")] diff --git a/gix-archive/tests/archive.rs b/gix-archive/tests/archive.rs index 1a91937ddc6..3eff24c7570 100644 --- a/gix-archive/tests/archive.rs +++ b/gix-archive/tests/archive.rs @@ -11,7 +11,7 @@ mod from_tree { use gix_object::tree::EntryMode; use gix_odb::FindExt; use gix_testtools::bstr::ByteSlice; - use gix_worktree::cache::state::attributes::Source; + use gix_worktree::stack::state::attributes::Source; use crate::hex_to_id; @@ -284,7 +284,7 @@ mod from_tree { Ok(()) } - fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Cache)> { + fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Stack)> { let dir = gix_testtools::scripted_fixture_read_only("basic.sh")?; let head = { @@ -295,14 +295,14 @@ mod from_tree { let mut collection = Default::default(); let mut buf = Default::default(); - let attributes = gix_worktree::cache::state::Attributes::new( + let attributes = gix_worktree::stack::state::Attributes::new( gix_attributes::Search::new_globals(None::, &mut buf, &mut collection)?, None, Source::WorktreeThenIdMapping, collection, ); - let state = gix_worktree::cache::State::AttributesStack(attributes); - let cache = gix_worktree::Cache::new(&dir, state, Case::Sensitive, Default::default(), Default::default()); + let state = gix_worktree::stack::State::AttributesStack(attributes); + let cache = gix_worktree::Stack::new(&dir, state, Case::Sensitive, Default::default(), Default::default()); Ok((dir, head, odb.into_arc()?, cache)) } diff --git a/gix-diff/Cargo.toml b/gix-diff/Cargo.toml index 43fbc0123c1..04cfeb9906c 100644 --- a/gix-diff/Cargo.toml +++ b/gix-diff/Cargo.toml @@ -11,6 +11,9 @@ rust-version = "1.65" autotests = false [features] +default = ["blob"] +## Enable diffing of blobs using imara-diff. +blob = ["dep:imara-diff"] ## Data structures implement `serde::Serialize` and `serde::Deserialize`. serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"] ## Make it possible to compile to the `wasm32-unknown-unknown` target. @@ -23,6 +26,13 @@ doctest = false gix-hash = { version = "^0.11.4", path = "../gix-hash" } gix-object = { version = "^0.34.0", path = "../gix-object" } thiserror = "1.0.32" -imara-diff = "0.1.3" +imara-diff = { version = "0.1.3", optional = true } serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} getrandom = { version = "0.2.8", optional = true, default-features = false, features = ["js"] } + +document-features = { version = "0.2.0", optional = true } + +[package.metadata.docs.rs] +all-features = true +features = ["document-features"] +rustdoc-args = ["--cfg", "docsrs"] diff --git a/gix-diff/src/lib.rs b/gix-diff/src/lib.rs index a60f7bc04ee..6d94a75919f 100644 --- a/gix-diff/src/lib.rs +++ b/gix-diff/src/lib.rs @@ -1,4 +1,10 @@ //! Algorithms for diffing various git object types and for generating patches, highly optimized for performance. +//! ## Feature Flags +#![cfg_attr( +feature = "document-features", +cfg_attr(doc, doc = ::document_features::document_features!()) +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![deny(missing_docs, rust_2018_idioms)] #![forbid(unsafe_code)] @@ -6,4 +12,5 @@ pub mod tree; /// +#[cfg(feature = "blob")] pub mod blob; diff --git a/gix-filter/tests/pipeline/mod.rs b/gix-filter/tests/pipeline/mod.rs index ba683564f4d..7db3224357d 100644 --- a/gix-filter/tests/pipeline/mod.rs +++ b/gix-filter/tests/pipeline/mod.rs @@ -17,22 +17,22 @@ fn default() -> crate::Result { Ok(()) } -fn attribute_cache(name: &str) -> gix_testtools::Result { +fn attribute_cache(name: &str) -> gix_testtools::Result { let dir = gix_testtools::scripted_fixture_read_only("pipeline_repos.sh")?.join(name); - Ok(gix_worktree::Cache::new( + Ok(gix_worktree::Stack::new( dir, - gix_worktree::cache::State::for_add( - gix_worktree::cache::state::Attributes::new( + gix_worktree::stack::State::for_add( + gix_worktree::stack::state::Attributes::new( Default::default(), None, - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, Default::default(), ), - gix_worktree::cache::state::Ignore::new( + gix_worktree::stack::state::Ignore::new( Default::default(), Default::default(), None, - gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, + gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, ), ), Case::Sensitive, @@ -49,7 +49,7 @@ fn pipeline( gix_filter::pipeline::CrlfRoundTripCheck, eol::Configuration, ), -) -> gix_testtools::Result<(gix_worktree::Cache, gix_filter::Pipeline)> { +) -> gix_testtools::Result<(gix_worktree::Stack, gix_filter::Pipeline)> { let cache = attribute_cache(name)?; let (drivers, encodings_with_roundtrip_check, crlf_roundtrip_check, eol_config) = init(); let pipe = gix_filter::Pipeline::new( diff --git a/gix-worktree/CHANGELOG.md b/gix-status/CHANGELOG.md similarity index 100% rename from gix-worktree/CHANGELOG.md rename to gix-status/CHANGELOG.md diff --git a/gix-status/Cargo.toml b/gix-status/Cargo.toml new file mode 100644 index 00000000000..b89dd3fa7fc --- /dev/null +++ b/gix-status/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "gix-status" +version = "0.1.0" +repository = "https://github.com/Byron/gitoxide" +license = "MIT OR Apache-2.0" +description = "A crate of the gitoxide project dealing with 'git status'-like functionality" +authors = ["Sebastian Thiel ", "Pascal Kuthe "] +edition = "2021" +include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] +rust-version = "1.65" + +[lib] +doctest = false + +[[test]] +name = "multi-threaded" +path = "tests/status-multi-threaded.rs" +required-features = ["internal-testing-gix-features-parallel"] + +[features] +internal-testing-gix-features-parallel = ["gix-features/parallel"] + +[dependencies] +gix-index = { version = "^0.22.0", path = "../gix-index" } +gix-fs = { version = "^0.4.1", path = "../gix-fs" } +gix-hash = { version = "^0.11.4", path = "../gix-hash" } +gix-object = { version = "^0.34.0", path = "../gix-object" } +gix-path = { version = "^0.8.4", path = "../gix-path" } +gix-features = { version = "^0.32.1", path = "../gix-features" } + +thiserror = "1.0.26" +filetime = "0.2.15" +bstr = { version = "1.3.0", default-features = false } + +[dev-dependencies] +gix-testtools = { path = "../tests/tools" } + diff --git a/gix-status/LICENSE-APACHE b/gix-status/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/gix-status/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/gix-status/LICENSE-MIT b/gix-status/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/gix-status/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/gix-worktree/src/status/content.rs b/gix-status/src/index_as_worktree/content.rs similarity index 100% rename from gix-worktree/src/status/content.rs rename to gix-status/src/index_as_worktree/content.rs diff --git a/gix-worktree/src/status/function.rs b/gix-status/src/index_as_worktree/function.rs similarity index 99% rename from gix-worktree/src/status/function.rs rename to gix-status/src/index_as_worktree/function.rs index 5e01628b416..be2572013c6 100644 --- a/gix-worktree/src/status/function.rs +++ b/gix-status/src/index_as_worktree/function.rs @@ -5,13 +5,13 @@ use filetime::FileTime; use gix_features::parallel::{in_parallel_if, Reduce}; use crate::{ - read, - status::{ + index_as_worktree::{ content, content::CompareBlobs, types::{Error, Options}, Change, VisitEntry, }, + read, }; /// Calculates the changes that need to be applied to an `index` to match the state of the `worktree` and makes them @@ -24,7 +24,7 @@ use crate::{ /// Note that this isn't technically quite what this function does as this also provides some additional information, /// like whether a file has conflicts, and files that were added with `git add` are shown as a special /// changes despite not technically requiring a change to the index since `git add` already added the file to the index. -pub fn status<'index, T, Find, E>( +pub fn index_as_worktree<'index, T, Find, E>( index: &'index mut gix_index::State, worktree: &Path, collector: &mut impl VisitEntry<'index, ContentChange = T>, diff --git a/gix-worktree/src/status/mod.rs b/gix-status/src/index_as_worktree/mod.rs similarity index 100% rename from gix-worktree/src/status/mod.rs rename to gix-status/src/index_as_worktree/mod.rs diff --git a/gix-worktree/src/status/recorder.rs b/gix-status/src/index_as_worktree/recorder.rs similarity index 93% rename from gix-worktree/src/status/recorder.rs rename to gix-status/src/index_as_worktree/recorder.rs index ea10303ae60..48beb25a313 100644 --- a/gix-worktree/src/status/recorder.rs +++ b/gix-status/src/index_as_worktree/recorder.rs @@ -1,7 +1,7 @@ use bstr::BStr; use gix_index as index; -use crate::status::{Change, VisitEntry}; +use crate::index_as_worktree::{Change, VisitEntry}; /// Convenience implementation of [`VisitEntry`] that collects all non-trivial changes into a `Vec`. #[derive(Debug, Default)] diff --git a/gix-worktree/src/status/types.rs b/gix-status/src/index_as_worktree/types.rs similarity index 94% rename from gix-worktree/src/status/types.rs rename to gix-status/src/index_as_worktree/types.rs index 3d488d24ef4..10ff5c28d24 100644 --- a/gix-worktree/src/status/types.rs +++ b/gix-status/src/index_as_worktree/types.rs @@ -1,6 +1,6 @@ use bstr::BStr; -/// The error returned by [`status()`][crate::status()]. +/// The error returned by [`status()`](crate::index_as_worktree()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -40,7 +40,7 @@ pub enum Change { /// Indicates that one of the stat changes was an executable bit change /// which is a significant change itself. executable_bit_changed: bool, - /// The output of the [`CompareBlobs`][crate::status::content::CompareBlobs] run on this entry. + /// The output of the [`CompareBlobs`](crate::index_as_worktree::content::CompareBlobs) run on this entry. /// If there is no content change and only the executable bit /// changed than this is `None`. content_change: Option, diff --git a/gix-status/src/lib.rs b/gix-status/src/lib.rs new file mode 100644 index 00000000000..843eb6a20a5 --- /dev/null +++ b/gix-status/src/lib.rs @@ -0,0 +1,15 @@ +//! This crate includes the various diffs `git` can do between different representations +//! of the repository state, like comparisons between… +//! +//! * index and working tree +//! * index and tree +//! * find untracked files +//! +//! While also being able to check check if the working tree is dirty, quickly. +#![deny(missing_docs, rust_2018_idioms, unsafe_code)] + +/// +pub mod read; + +pub mod index_as_worktree; +pub use index_as_worktree::function::index_as_worktree; diff --git a/gix-worktree/src/read.rs b/gix-status/src/read.rs similarity index 96% rename from gix-worktree/src/read.rs rename to gix-status/src/read.rs index a54fc2c7611..fd336817525 100644 --- a/gix-worktree/src/read.rs +++ b/gix-status/src/read.rs @@ -10,7 +10,6 @@ use std::{ }; use gix_object::Blob; -use gix_path as path; // TODO: tests @@ -49,7 +48,7 @@ pub fn data_to_buf_with_meta<'a>( if is_symlink && capabilities.symlink { // conversion to bstr can never fail because symlinks are only used // on unix (by git) so no reason to use the try version here - let symlink_path = path::into_bstr(read_link(path)?); + let symlink_path = gix_path::into_bstr(read_link(path)?); buf.extend_from_slice(&symlink_path); // TODO: there is no reason this should be a clone // std isn't great about allowing users to avoid allocations but we could diff --git a/gix-status/tests/fixtures/generated-archives/.gitignore b/gix-status/tests/fixtures/generated-archives/.gitignore new file mode 100644 index 00000000000..ee165f3a1c5 --- /dev/null +++ b/gix-status/tests/fixtures/generated-archives/.gitignore @@ -0,0 +1,2 @@ +status_unchanged.tar.xz +status_changed.tar.xz diff --git a/gix-status/tests/fixtures/generated-archives/racy_git.tar.xz b/gix-status/tests/fixtures/generated-archives/racy_git.tar.xz new file mode 100644 index 00000000000..bb2ff2cd4a1 --- /dev/null +++ b/gix-status/tests/fixtures/generated-archives/racy_git.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c78c306d8a19ce7f09a4cdf284e761d9c7766a3491bfb83751b9e6f6bc8fc1c9 +size 9812 diff --git a/gix-status/tests/fixtures/generated-archives/status_conflict.tar.xz b/gix-status/tests/fixtures/generated-archives/status_conflict.tar.xz new file mode 100644 index 00000000000..a871be6f358 --- /dev/null +++ b/gix-status/tests/fixtures/generated-archives/status_conflict.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b64431478ff4ee4613d2e1fe0766b4da8aeac8f4dee2b42726efb6d2e87bc830 +size 11012 diff --git a/gix-status/tests/fixtures/generated-archives/status_intent_to_add.tar.xz b/gix-status/tests/fixtures/generated-archives/status_intent_to_add.tar.xz new file mode 100644 index 00000000000..289a58a1947 --- /dev/null +++ b/gix-status/tests/fixtures/generated-archives/status_intent_to_add.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8fa2e8085d464945eade89cfa9dadb89345c584b1d72a535d464859f02950a7 +size 9280 diff --git a/gix-status/tests/fixtures/generated-archives/status_removed.tar.xz b/gix-status/tests/fixtures/generated-archives/status_removed.tar.xz new file mode 100644 index 00000000000..c0179e3cd18 --- /dev/null +++ b/gix-status/tests/fixtures/generated-archives/status_removed.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbc72bb3b08e421928d4402b49100a4ac144b4cdcc84ab70e6b721ec5ce4546c +size 10568 diff --git a/gix-worktree/tests/fixtures/racy_git.sh b/gix-status/tests/fixtures/racy_git.sh similarity index 100% rename from gix-worktree/tests/fixtures/racy_git.sh rename to gix-status/tests/fixtures/racy_git.sh diff --git a/gix-worktree/tests/fixtures/status_changed.sh b/gix-status/tests/fixtures/status_changed.sh similarity index 100% rename from gix-worktree/tests/fixtures/status_changed.sh rename to gix-status/tests/fixtures/status_changed.sh diff --git a/gix-worktree/tests/fixtures/status_conflict.sh b/gix-status/tests/fixtures/status_conflict.sh similarity index 100% rename from gix-worktree/tests/fixtures/status_conflict.sh rename to gix-status/tests/fixtures/status_conflict.sh diff --git a/gix-worktree/tests/fixtures/status_intent_to_add.sh b/gix-status/tests/fixtures/status_intent_to_add.sh similarity index 100% rename from gix-worktree/tests/fixtures/status_intent_to_add.sh rename to gix-status/tests/fixtures/status_intent_to_add.sh diff --git a/gix-worktree/tests/fixtures/status_removed.sh b/gix-status/tests/fixtures/status_removed.sh similarity index 100% rename from gix-worktree/tests/fixtures/status_removed.sh rename to gix-status/tests/fixtures/status_removed.sh diff --git a/gix-worktree/tests/fixtures/status_unchanged.sh b/gix-status/tests/fixtures/status_unchanged.sh similarity index 100% rename from gix-worktree/tests/fixtures/status_unchanged.sh rename to gix-status/tests/fixtures/status_unchanged.sh diff --git a/gix-status/tests/status-multi-threaded.rs b/gix-status/tests/status-multi-threaded.rs new file mode 100644 index 00000000000..970eddcb034 --- /dev/null +++ b/gix-status/tests/status-multi-threaded.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "internal-testing-gix-features-parallel")] +mod status; +#[cfg(feature = "internal-testing-gix-features-parallel")] +use status::*; diff --git a/gix-status/tests/status-single-threaded.rs b/gix-status/tests/status-single-threaded.rs new file mode 100644 index 00000000000..54e0daf8929 --- /dev/null +++ b/gix-status/tests/status-single-threaded.rs @@ -0,0 +1,4 @@ +#[cfg(not(feature = "internal-testing-gix-features-parallel"))] +mod status; +#[cfg(not(feature = "internal-testing-gix-features-parallel"))] +use status::*; diff --git a/gix-worktree/tests/worktree/status.rs b/gix-status/tests/status/index_as_worktree.rs similarity index 98% rename from gix-worktree/tests/worktree/status.rs rename to gix-status/tests/status/index_as_worktree.rs index 11689b5f6e2..7a5f84f63b7 100644 --- a/gix-worktree/tests/worktree/status.rs +++ b/gix-status/tests/status/index_as_worktree.rs @@ -7,9 +7,9 @@ use bstr::BStr; use filetime::{set_file_mtime, FileTime}; use gix_index as index; use gix_index::Entry; -use gix_worktree::{ - status, - status::{ +use gix_status::{ + index_as_worktree, + index_as_worktree::{ content::{CompareBlobs, FastEq, ReadDataOnce}, Change, Options, Recorder, }, @@ -33,7 +33,7 @@ fn fixture(name: &str, expected_status: &[(&BStr, Option, bool)]) { let git_dir = worktree.join(".git"); let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default()).unwrap(); let mut recorder = Recorder::default(); - status( + index_as_worktree( &mut index, &worktree, &mut recorder, @@ -172,7 +172,7 @@ fn racy_git() { let count = Arc::new(AtomicUsize::new(0)); let counter = CountCalls(count.clone(), FastEq); - status( + index_as_worktree( &mut index, worktree, &mut recorder, @@ -193,7 +193,7 @@ fn racy_git() { // and cause proper output. index.set_timestamp(FileTime::from_unix_time(timestamp as i64, 0)); let mut recorder = Recorder::default(); - status( + index_as_worktree( &mut index, worktree, &mut recorder, diff --git a/gix-status/tests/status/mod.rs b/gix-status/tests/status/mod.rs new file mode 100644 index 00000000000..af50d26613a --- /dev/null +++ b/gix-status/tests/status/mod.rs @@ -0,0 +1,7 @@ +mod index_as_worktree; + +pub fn fixture_path(name: &str) -> std::path::PathBuf { + let dir = gix_testtools::scripted_fixture_read_only(std::path::Path::new(name).with_extension("sh")) + .expect("script works"); + dir +} diff --git a/gix-worktree-state/Cargo.toml b/gix-worktree-state/Cargo.toml new file mode 100644 index 00000000000..0e023ff638f --- /dev/null +++ b/gix-worktree-state/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "gix-worktree-state" +version = "0.1.0" +repository = "https://github.com/Byron/gitoxide" +license = "MIT OR Apache-2.0" +description = "A crate of the gitoxide project implementing setting the worktree to a particular state" +authors = ["Sebastian Thiel "] +edition = "2021" +include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] +rust-version = "1.65" + +[lib] +doctest = false + +[[test]] +name = "multi-threaded" +path = "tests/state-multi-threaded.rs" +required-features = ["internal-testing-gix-features-parallel"] + +[features] +internal-testing-gix-features-parallel = ["gix-features/parallel"] + +[dependencies] +gix-worktree = { version = "^0.24.0", path = "../gix-worktree" } +gix-index = { version = "^0.22.0", path = "../gix-index" } +gix-fs = { version = "^0.4.1", path = "../gix-fs" } +gix-hash = { version = "^0.11.4", path = "../gix-hash" } +gix-object = { version = "^0.34.0", path = "../gix-object" } +gix-glob = { version = "^0.10.2", path = "../gix-glob" } +gix-path = { version = "^0.8.4", path = "../gix-path" } +gix-features = { version = "^0.32.1", path = "../gix-features" } +gix-filter = { version = "^0.3.0", path = "../gix-filter" } + +io-close = "0.3.7" +thiserror = "1.0.26" +bstr = { version = "1.3.0", default-features = false } + +[dev-dependencies] +gix-testtools = { path = "../tests/tools" } +gix-odb = { path = "../gix-odb" } +symlink = "0.1.0" +once_cell = "1.18.0" + +walkdir = "2.3.2" diff --git a/gix-worktree-state/LICENSE-APACHE b/gix-worktree-state/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/gix-worktree-state/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/gix-worktree-state/LICENSE-MIT b/gix-worktree-state/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/gix-worktree-state/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/gix-worktree/src/checkout/chunk.rs b/gix-worktree-state/src/checkout/chunk.rs similarity index 99% rename from gix-worktree/src/checkout/chunk.rs rename to gix-worktree-state/src/checkout/chunk.rs index 13110e90004..46d09bac28c 100644 --- a/gix-worktree/src/checkout/chunk.rs +++ b/gix-worktree-state/src/checkout/chunk.rs @@ -6,7 +6,8 @@ use std::{ use bstr::{BStr, BString}; use gix_hash::oid; -use crate::{checkout, checkout::entry, Cache}; +use crate::{checkout, checkout::entry}; +use gix_worktree::Stack; mod reduce { use std::marker::PhantomData; @@ -91,7 +92,7 @@ pub struct Outcome<'a> { #[derive(Clone)] pub struct Context { pub find: Find, - pub path_cache: Cache, + pub path_cache: Stack, pub filters: gix_filter::Pipeline, pub buf: Vec, pub options: Options, diff --git a/gix-worktree/src/checkout/entry.rs b/gix-worktree-state/src/checkout/entry.rs similarity index 99% rename from gix-worktree/src/checkout/entry.rs rename to gix-worktree-state/src/checkout/entry.rs index 4744f5e16ce..68cb796aa54 100644 --- a/gix-worktree/src/checkout/entry.rs +++ b/gix-worktree-state/src/checkout/entry.rs @@ -10,11 +10,11 @@ use gix_hash::oid; use gix_index::{entry::Stat, Entry}; use io_close::Close; -use crate::Cache; +use gix_worktree::Stack; pub struct Context<'a, Find> { pub find: &'a mut Find, - pub path_cache: &'a mut Cache, + pub path_cache: &'a mut Stack, pub filters: &'a mut gix_filter::Pipeline, pub buf: &'a mut Vec, } diff --git a/gix-worktree/src/checkout/function.rs b/gix-worktree-state/src/checkout/function.rs similarity index 96% rename from gix-worktree/src/checkout/function.rs rename to gix-worktree-state/src/checkout/function.rs index e52299e3972..b29a6e69356 100644 --- a/gix-worktree/src/checkout/function.rs +++ b/gix-worktree-state/src/checkout/function.rs @@ -3,7 +3,8 @@ use std::sync::atomic::AtomicBool; use gix_features::{interrupt, parallel::in_parallel_with_finalize, progress::Progress}; use gix_hash::oid; -use crate::{cache, checkout::chunk, Cache}; +use crate::checkout::chunk; +use gix_worktree::{stack, Stack}; /// Checkout the entire `index` into `dir`, and resolve objects found in index entries with `find` to write their content to their /// respective path in `dir`. @@ -65,12 +66,12 @@ where None, ); - let state = cache::State::for_checkout(options.overwrite_existing, std::mem::take(&mut options.attributes)); + let state = stack::State::for_checkout(options.overwrite_existing, std::mem::take(&mut options.attributes)); let attribute_files = state.id_mappings_from_index(index, paths, case); let mut ctx = chunk::Context { buf: Vec::new(), options: (&options).into(), - path_cache: Cache::new(dir, state, case, Vec::with_capacity(512), attribute_files), + path_cache: Stack::new(dir, state, case, Vec::with_capacity(512), attribute_files), filters: options.filters, find, }; diff --git a/gix-worktree/src/checkout/mod.rs b/gix-worktree-state/src/checkout/mod.rs similarity index 98% rename from gix-worktree/src/checkout/mod.rs rename to gix-worktree-state/src/checkout/mod.rs index 4590b1f0373..70e46c84e2e 100644 --- a/gix-worktree/src/checkout/mod.rs +++ b/gix-worktree-state/src/checkout/mod.rs @@ -60,7 +60,7 @@ pub struct Options { /// Control how stat comparisons are made when checking if a file is fresh. pub stat_options: stat::Options, /// A stack of attributes to use with the filesystem cache to use as driver for filters. - pub attributes: crate::cache::state::Attributes, + pub attributes: gix_worktree::stack::state::Attributes, /// The filter pipeline to use for applying mandatory filters before writing to the worktree. pub filters: gix_filter::Pipeline, /// Control how long-running processes may use the 'delay' capability. diff --git a/gix-worktree-state/src/lib.rs b/gix-worktree-state/src/lib.rs new file mode 100644 index 00000000000..2c2cf67f64d --- /dev/null +++ b/gix-worktree-state/src/lib.rs @@ -0,0 +1,6 @@ +//! A crate to help setting the worktree to a particular state. +#![deny(missing_docs, rust_2018_idioms, unsafe_code)] + +/// +pub mod checkout; +pub use checkout::function::checkout; diff --git a/gix-worktree-state/tests/fixtures/generated-archives/.gitignore b/gix-worktree-state/tests/fixtures/generated-archives/.gitignore new file mode 100644 index 00000000000..ea20ce61c44 --- /dev/null +++ b/gix-worktree-state/tests/fixtures/generated-archives/.gitignore @@ -0,0 +1,5 @@ +make_ignore_and_attributes_setup.tar.xz +make_mixed_without_submodules.tar.xz +make_mixed_without_submodules_and_symlinks.tar.xz +make_attributes_baseline.tar.xz +make_dangerous_symlink.tar.xz diff --git a/gix-worktree/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz b/gix-worktree-state/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz similarity index 100% rename from gix-worktree/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz rename to gix-worktree-state/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz diff --git a/gix-worktree/tests/fixtures/make_dangerous_symlink.sh b/gix-worktree-state/tests/fixtures/make_dangerous_symlink.sh similarity index 100% rename from gix-worktree/tests/fixtures/make_dangerous_symlink.sh rename to gix-worktree-state/tests/fixtures/make_dangerous_symlink.sh diff --git a/gix-worktree/tests/fixtures/make_ignorecase_collisions.sh b/gix-worktree-state/tests/fixtures/make_ignorecase_collisions.sh similarity index 100% rename from gix-worktree/tests/fixtures/make_ignorecase_collisions.sh rename to gix-worktree-state/tests/fixtures/make_ignorecase_collisions.sh diff --git a/gix-worktree/tests/fixtures/make_mixed_without_submodules.sh b/gix-worktree-state/tests/fixtures/make_mixed_without_submodules.sh similarity index 100% rename from gix-worktree/tests/fixtures/make_mixed_without_submodules.sh rename to gix-worktree-state/tests/fixtures/make_mixed_without_submodules.sh diff --git a/gix-worktree/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh b/gix-worktree-state/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh similarity index 100% rename from gix-worktree/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh rename to gix-worktree-state/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh diff --git a/gix-worktree-state/tests/state-multi-threaded.rs b/gix-worktree-state/tests/state-multi-threaded.rs new file mode 100644 index 00000000000..41474d7ef08 --- /dev/null +++ b/gix-worktree-state/tests/state-multi-threaded.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "internal-testing-gix-features-parallel")] +mod state; +#[cfg(feature = "internal-testing-gix-features-parallel")] +use state::*; diff --git a/gix-worktree-state/tests/state-single-threaded.rs b/gix-worktree-state/tests/state-single-threaded.rs new file mode 100644 index 00000000000..3f4e78811e2 --- /dev/null +++ b/gix-worktree-state/tests/state-single-threaded.rs @@ -0,0 +1,4 @@ +#[cfg(not(feature = "internal-testing-gix-features-parallel"))] +mod state; +#[cfg(not(feature = "internal-testing-gix-features-parallel"))] +use state::*; diff --git a/gix-worktree/tests/worktree/checkout.rs b/gix-worktree-state/tests/state/checkout.rs similarity index 97% rename from gix-worktree/tests/worktree/checkout.rs rename to gix-worktree-state/tests/state/checkout.rs index db12d1fb4cc..ff06812b528 100644 --- a/gix-worktree/tests/worktree/checkout.rs +++ b/gix-worktree-state/tests/state/checkout.rs @@ -10,9 +10,9 @@ use std::{ use gix_features::progress; use gix_object::bstr::ByteSlice; use gix_odb::FindExt; -use gix_worktree::checkout::Collision; +use gix_testtools::tempfile::TempDir; +use gix_worktree_state::checkout::Collision; use once_cell::sync::Lazy; -use tempfile::TempDir; use crate::fixture_path; @@ -454,26 +454,26 @@ pub fn dir_structure>(path: P) -> Vec crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree::checkout::Outcome)> { +) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree_state::checkout::Outcome)> { checkout_index_in_tmp_dir_opts(opts, name, |_d| true, |_| Ok(())) } fn checkout_index_in_tmp_dir_opts( - opts: gix_worktree::checkout::Options, + opts: gix_worktree_state::checkout::Options, name: &str, mut allow_return_object: impl FnMut(&gix_hash::oid) -> bool + Send + Clone, prep_dest: impl Fn(&Path) -> std::io::Result<()>, -) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree::checkout::Outcome)> { +) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree_state::checkout::Outcome)> { let source_tree = fixture_path(name); let git_dir = source_tree.join(".git"); let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?; let odb = gix_odb::at(git_dir.join("objects"))?.into_inner().into_arc()?; - let destination = tempfile::tempdir_in(std::env::current_dir()?)?; + let destination = gix_testtools::tempfile::tempdir_in(std::env::current_dir()?)?; prep_dest(destination.path()).expect("preparation must succeed"); - let outcome = gix_worktree::checkout( + let outcome = gix_worktree_state::checkout( &mut index, destination.path(), move |oid, buf| { @@ -501,8 +501,8 @@ fn probe_gitoxide_dir() -> crate::Result { )) } -fn opts_from_probe() -> gix_worktree::checkout::Options { - gix_worktree::checkout::Options { +fn opts_from_probe() -> gix_worktree_state::checkout::Options { + gix_worktree_state::checkout::Options { fs: probe_gitoxide_dir().unwrap(), destination_is_initially_empty: true, thread_limit: gix_features::parallel::num_threads(None).into(), diff --git a/gix-worktree-state/tests/state/mod.rs b/gix-worktree-state/tests/state/mod.rs new file mode 100644 index 00000000000..82da2b9adf1 --- /dev/null +++ b/gix-worktree-state/tests/state/mod.rs @@ -0,0 +1,10 @@ +mod checkout; + +use std::path::{Path, PathBuf}; + +pub type Result = std::result::Result>; + +pub fn fixture_path(name: &str) -> PathBuf { + let dir = gix_testtools::scripted_fixture_read_only(Path::new(name).with_extension("sh")).expect("script works"); + dir +} diff --git a/gix-worktree-stream/tests/stream.rs b/gix-worktree-stream/tests/stream.rs index e70c5b11837..22561bb7076 100644 --- a/gix-worktree-stream/tests/stream.rs +++ b/gix-worktree-stream/tests/stream.rs @@ -15,7 +15,7 @@ mod from_tree { use gix_object::{bstr::ByteSlice, tree::EntryMode}; use gix_odb::FindExt; use gix_testtools::once_cell::sync::Lazy; - use gix_worktree::cache::state::attributes::Source; + use gix_worktree::stack::state::attributes::Source; use crate::hex_to_id; @@ -231,7 +231,7 @@ mod from_tree { Ok(()) } - fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Cache)> { + fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Stack)> { let dir = gix_testtools::scripted_fixture_read_only("basic.sh")?; let head = { @@ -242,14 +242,14 @@ mod from_tree { let mut collection = Default::default(); let mut buf = Default::default(); - let attributes = gix_worktree::cache::state::Attributes::new( + let attributes = gix_worktree::stack::state::Attributes::new( gix_attributes::Search::new_globals(None::, &mut buf, &mut collection)?, None, Source::WorktreeThenIdMapping, collection, ); - let state = gix_worktree::cache::State::AttributesStack(attributes); - let cache = gix_worktree::Cache::new(&dir, state, Case::Sensitive, Default::default(), Default::default()); + let state = gix_worktree::stack::State::AttributesStack(attributes); + let cache = gix_worktree::Stack::new(&dir, state, Case::Sensitive, Default::default(), Default::default()); Ok((dir, head, odb.into_arc()?, cache)) } diff --git a/gix-worktree/Cargo.toml b/gix-worktree/Cargo.toml index fbcb08fa1c5..2796485c024 100644 --- a/gix-worktree/Cargo.toml +++ b/gix-worktree/Cargo.toml @@ -3,7 +3,7 @@ name = "gix-worktree" version = "0.24.0" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" -description = "A crate of the gitoxide project dedicated implementing everything around working trees and git excludes" +description = "A crate of the gitoxide project for shared worktree related types and utilities." authors = ["Sebastian Thiel "] edition = "2021" include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] @@ -33,25 +33,17 @@ gix-path = { version = "^0.8.4", path = "../gix-path" } gix-attributes = { version = "^0.16.0", path = "../gix-attributes" } gix-ignore = { version = "^0.5.1", path = "../gix-ignore" } gix-features = { version = "^0.32.1", path = "../gix-features" } -gix-filter = { version = "^0.3.0", path = "../gix-filter" } serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} -thiserror = "1.0.26" -filetime = "0.2.15" bstr = { version = "1.3.0", default-features = false } document-features = { version = "0.2.0", optional = true } -io-close = "0.3.7" [dev-dependencies] gix-testtools = { path = "../tests/tools" } gix-odb = { path = "../gix-odb" } symlink = "0.1.0" -once_cell = "1.18.0" - -walkdir = "2.3.2" -tempfile = "3.2.0" [package.metadata.docs.rs] features = ["document-features", "serde"] diff --git a/gix-worktree/src/lib.rs b/gix-worktree/src/lib.rs index 20ae186877b..32d1d7c0e3b 100644 --- a/gix-worktree/src/lib.rs +++ b/gix-worktree/src/lib.rs @@ -1,4 +1,4 @@ -//! A crate with all index-centric functionality that is interacting with a worktree. +//! A crate with utility types for use by other crates that implement specifics. //! //! Unless specified differently, all operations need an index file (e.g. `.git/index`) as driver. //! @@ -11,9 +11,6 @@ #![deny(missing_docs, rust_2018_idioms, unsafe_code)] use bstr::BString; -/// -pub mod read; - /// A cache for efficiently executing operations on directories and files which are encountered in sorted order. /// That way, these operations can be re-used for subsequent invocations in the same directory. /// @@ -35,26 +32,20 @@ pub mod read; /// /// The caching is only useful if consecutive calls to create a directory are using a sorted list of entries. #[derive(Clone)] -pub struct Cache { +pub struct Stack { stack: gix_fs::Stack, /// tells us what to do as we change paths. - state: cache::State, + state: stack::State, /// A buffer used when reading attribute or ignore files or their respective objects from the object database. buf: Vec, /// If case folding should happen when looking up attributes or exclusions. case: gix_glob::pattern::Case, /// A lookup table for object ids to read from in some situations when looking up attributes or exclusions. id_mappings: Vec, - statistics: cache::Statistics, + statistics: stack::Statistics, } pub(crate) type PathIdMapping = (BString, gix_hash::ObjectId); /// -pub mod cache; -/// -pub mod checkout; -pub use checkout::function::checkout; - -pub mod status; -pub use status::function::status; +pub mod stack; diff --git a/gix-worktree/src/cache/delegate.rs b/gix-worktree/src/stack/delegate.rs similarity index 99% rename from gix-worktree/src/cache/delegate.rs rename to gix-worktree/src/stack/delegate.rs index d982ae7592e..4c14ba297c7 100644 --- a/gix-worktree/src/cache/delegate.rs +++ b/gix-worktree/src/stack/delegate.rs @@ -1,6 +1,6 @@ use bstr::{BStr, ByteSlice}; -use crate::{cache::State, PathIdMapping}; +use crate::{stack::State, PathIdMapping}; /// Various aggregate numbers related to the stack delegate itself. #[derive(Default, Clone, Copy, Debug)] diff --git a/gix-worktree/src/cache/mod.rs b/gix-worktree/src/stack/mod.rs similarity index 96% rename from gix-worktree/src/cache/mod.rs rename to gix-worktree/src/stack/mod.rs index 4088de5f6ea..6892f99025d 100644 --- a/gix-worktree/src/cache/mod.rs +++ b/gix-worktree/src/stack/mod.rs @@ -4,10 +4,10 @@ use std::path::{Path, PathBuf}; use bstr::{BStr, ByteSlice}; use gix_hash::oid; -use super::Cache; +use super::Stack; use crate::PathIdMapping; -/// Various aggregate numbers collected from when the corresponding [`Cache`] was instantiated. +/// Various aggregate numbers collected from when the corresponding [`Stack`] was instantiated. #[derive(Default, Clone, Copy, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Statistics { @@ -45,12 +45,12 @@ pub enum State { #[must_use] pub struct Platform<'a> { - parent: &'a Cache, + parent: &'a Stack, is_dir: Option, } /// Initialization -impl Cache { +impl Stack { /// Create a new instance with `worktree_root` being the base for all future paths we match. /// `state` defines the capabilities of the cache. /// The `case` configures attribute and exclusion case sensitivity at *query time*, which should match the case that @@ -64,7 +64,7 @@ impl Cache { id_mappings: Vec, ) -> Self { let root = worktree_root.into(); - Cache { + Stack { stack: gix_fs::Stack::new(root), state, case, @@ -76,12 +76,12 @@ impl Cache { } /// Entry points for attribute query -impl Cache { +impl Stack { /// Append the `relative` path to the root directory of the cache and efficiently create leading directories, while assuring that no /// symlinks are in that path. /// Unless `is_dir` is known with `Some(…)`, then `relative` points to a directory itself in which case the entire resulting /// path is created as directory. If it's not known it is assumed to be a file. - /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()], with mappnigs + /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()], with mappnigs /// /// Provide access to cached information for that `relative` path via the returned platform. pub fn at_path( @@ -110,7 +110,7 @@ impl Cache { /// Obtain a platform for lookups from a repo-`relative` path, typically obtained from an index entry. `is_dir` should reflect /// whether it's a directory or not, or left at `None` if unknown. - /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()]. + /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()]. /// All effects are similar to [`at_path()`][Self::at_path()]. /// /// If `relative` ends with `/` and `is_dir` is `None`, it is automatically assumed to be a directory. @@ -140,7 +140,7 @@ impl Cache { } /// Mutation -impl Cache { +impl Stack { /// Reset the statistics after returning them. pub fn take_statistics(&mut self) -> Statistics { std::mem::take(&mut self.statistics) @@ -159,7 +159,7 @@ impl Cache { } /// Access -impl Cache { +impl Stack { /// Return the statistics we gathered thus far. pub fn statistics(&self) -> &Statistics { &self.statistics diff --git a/gix-worktree/src/cache/platform.rs b/gix-worktree/src/stack/platform.rs similarity index 98% rename from gix-worktree/src/cache/platform.rs rename to gix-worktree/src/stack/platform.rs index d07ef6e8858..8d29566e8bb 100644 --- a/gix-worktree/src/cache/platform.rs +++ b/gix-worktree/src/stack/platform.rs @@ -2,7 +2,7 @@ use std::path::Path; use bstr::ByteSlice; -use crate::cache::Platform; +use crate::stack::Platform; /// Access impl<'a> Platform<'a> { diff --git a/gix-worktree/src/cache/state/attributes.rs b/gix-worktree/src/stack/state/attributes.rs similarity index 96% rename from gix-worktree/src/cache/state/attributes.rs rename to gix-worktree/src/stack/state/attributes.rs index 00b61544879..ea6b0f61a30 100644 --- a/gix-worktree/src/cache/state/attributes.rs +++ b/gix-worktree/src/stack/state/attributes.rs @@ -4,8 +4,8 @@ use bstr::{BStr, ByteSlice}; use gix_glob::pattern::Case; use crate::{ - cache::state::{AttributeMatchGroup, Attributes}, - Cache, PathIdMapping, + stack::state::{AttributeMatchGroup, Attributes}, + PathIdMapping, Stack, }; /// Various aggregate numbers related [`Attributes`]. @@ -23,7 +23,7 @@ pub struct Statistics { /// Decide where to read `.gitattributes` files from. /// /// To Retrieve attribute files from id mappings, see -/// [State::id_mappings_from_index()][crate::cache::State::id_mappings_from_index()]. +/// [State::id_mappings_from_index()][crate::stack::State::id_mappings_from_index()]. /// /// These mappings are typically produced from an index. /// If a tree should be the source, build an attribute list from a tree instead, or convert a tree to an index. @@ -200,7 +200,7 @@ impl Attributes { } /// Attribute matching specific methods -impl Cache { +impl Stack { /// Creates a new container to store match outcomes for all attribute matches. /// /// ### Panics @@ -230,7 +230,7 @@ impl Cache { } /// Return the metadata collection that enables initializing attribute match outcomes as done in - /// [`attribute_matches()`][Cache::attribute_matches()] or [`selected_attribute_matches()`][Cache::selected_attribute_matches()] + /// [`attribute_matches()`][Stack::attribute_matches()] or [`selected_attribute_matches()`][Stack::selected_attribute_matches()] /// /// ### Panics /// diff --git a/gix-worktree/src/cache/state/ignore.rs b/gix-worktree/src/stack/state/ignore.rs similarity index 98% rename from gix-worktree/src/cache/state/ignore.rs rename to gix-worktree/src/stack/state/ignore.rs index df7d0bbe682..0945a3c9403 100644 --- a/gix-worktree/src/cache/state/ignore.rs +++ b/gix-worktree/src/stack/state/ignore.rs @@ -4,7 +4,7 @@ use bstr::{BStr, ByteSlice}; use gix_glob::pattern::Case; use crate::{ - cache::state::{Ignore, IgnoreMatchGroup}, + stack::state::{Ignore, IgnoreMatchGroup}, PathIdMapping, }; @@ -12,7 +12,7 @@ use crate::{ #[derive(Default, Debug, Clone, Copy)] pub enum Source { /// Retrieve ignore files from id mappings, see - /// [State::id_mappings_from_index()][crate::cache::State::id_mappings_from_index()]. + /// [State::id_mappings_from_index()][crate::stack::State::id_mappings_from_index()]. /// /// These mappings are typically produced from an index. /// If a tree should be the source, build an attribute list from a tree instead, or convert a tree to an index. diff --git a/gix-worktree/src/cache/state/mod.rs b/gix-worktree/src/stack/state/mod.rs similarity index 99% rename from gix-worktree/src/cache/state/mod.rs rename to gix-worktree/src/stack/state/mod.rs index 48118e505ec..f353e13c42d 100644 --- a/gix-worktree/src/cache/state/mod.rs +++ b/gix-worktree/src/stack/state/mod.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use bstr::{BString, ByteSlice}; use gix_glob::pattern::Case; -use crate::{cache::State, PathIdMapping}; +use crate::{stack::State, PathIdMapping}; type AttributeMatchGroup = gix_attributes::Search; type IgnoreMatchGroup = gix_ignore::Search; diff --git a/gix-worktree/src/untracked.rs b/gix-worktree/src/untracked.rs deleted file mode 100644 index 6e77d7fa3ba..00000000000 --- a/gix-worktree/src/untracked.rs +++ /dev/null @@ -1 +0,0 @@ -// TODO: untracked file detection, needs fs::Cache diff --git a/gix-worktree/tests/fixtures/generated-archives/.gitignore b/gix-worktree/tests/fixtures/generated-archives/.gitignore index e8d0fd48dce..6f631797de0 100644 --- a/gix-worktree/tests/fixtures/generated-archives/.gitignore +++ b/gix-worktree/tests/fixtures/generated-archives/.gitignore @@ -1,7 +1,2 @@ make_ignore_and_attributes_setup.tar.xz -make_mixed_without_submodules.tar.xz -make_mixed_without_submodules_and_symlinks.tar.xz make_attributes_baseline.tar.xz -make_dangerous_symlink.tar.xz -status_unchanged.tar.xz -status_changed.tar.xz diff --git a/gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz b/gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz index 56edd71ff4a..dc93af2130b 100644 --- a/gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz +++ b/gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24f605623efc49819d1b30c52fe22da8f94f2d267e8030ec9bc3b9b845801f76 -size 9220 +oid sha256:1804dc740055b8a5afe65a2db14f29c8ae4691896e67342a8dcb11530fd448c6 +size 9240 diff --git a/gix-worktree/tests/fixtures/generated-archives/racy_git.tar.xz b/gix-worktree/tests/fixtures/generated-archives/racy_git.tar.xz deleted file mode 100644 index 2d045b26aab..00000000000 --- a/gix-worktree/tests/fixtures/generated-archives/racy_git.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35b728a127f3b6170bac44469ff36d5ad0be2a4247a8926f1aaffb97b5973efc -size 1596 diff --git a/gix-worktree/tests/fixtures/generated-archives/status_conflict.tar.xz b/gix-worktree/tests/fixtures/generated-archives/status_conflict.tar.xz deleted file mode 100644 index dbe191fbe1f..00000000000 --- a/gix-worktree/tests/fixtures/generated-archives/status_conflict.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd6d32ab7a1e372d80a617926cac2463f6620baedf74642d78fe7f8c956fd031 -size 11036 diff --git a/gix-worktree/tests/fixtures/generated-archives/status_intent_to_add.tar.xz b/gix-worktree/tests/fixtures/generated-archives/status_intent_to_add.tar.xz deleted file mode 100644 index 76feea7dc82..00000000000 --- a/gix-worktree/tests/fixtures/generated-archives/status_intent_to_add.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:876670d74c01249d361aa73d83ab20d846db7c922a3ca825f778b5f9d746c401 -size 9304 diff --git a/gix-worktree/tests/fixtures/generated-archives/status_removed.tar.xz b/gix-worktree/tests/fixtures/generated-archives/status_removed.tar.xz deleted file mode 100644 index 7b1462fc83e..00000000000 --- a/gix-worktree/tests/fixtures/generated-archives/status_removed.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5fe85a65e3689e9e60598130be60761dc4ea129e04d7d5501320f7ebad1eb2b -size 10520 diff --git a/gix-worktree/tests/fixtures/make_ignore_setup.sh b/gix-worktree/tests/fixtures/make_ignore_setup.sh deleted file mode 100755 index c06d3926429..00000000000 --- a/gix-worktree/tests/fixtures/make_ignore_setup.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -eu -o pipefail - -git init -q - -cat <.git/info/exclude -# a sample .git/info/exclude -file-anywhere -/file-from-top - -dir-anywhere/ -/dir-from-top - -subdir-anywhere/file -subdir-anywhere/dir/ -EOF - -git commit --allow-empty -m "init" diff --git a/gix-worktree/tests/worktree/mod.rs b/gix-worktree/tests/worktree/mod.rs index 85ffef380a4..4fd60015588 100644 --- a/gix-worktree/tests/worktree/mod.rs +++ b/gix-worktree/tests/worktree/mod.rs @@ -1,17 +1,9 @@ -mod cache; -mod checkout; -mod status; +use gix_hash::ObjectId; -use std::path::{Path, PathBuf}; +mod stack; -use gix_hash::ObjectId; pub type Result = std::result::Result>; pub fn hex_to_id(hex: &str) -> ObjectId { ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex") } - -pub fn fixture_path(name: &str) -> PathBuf { - let dir = gix_testtools::scripted_fixture_read_only(Path::new(name).with_extension("sh")).expect("script works"); - dir -} diff --git a/gix-worktree/tests/worktree/cache/attributes.rs b/gix-worktree/tests/worktree/stack/attributes.rs similarity index 95% rename from gix-worktree/tests/worktree/cache/attributes.rs rename to gix-worktree/tests/worktree/stack/attributes.rs index b7d9f55d8f6..6f0246597e0 100644 --- a/gix-worktree/tests/worktree/cache/attributes.rs +++ b/gix-worktree/tests/worktree/stack/attributes.rs @@ -1,7 +1,7 @@ use bstr::ByteSlice; use gix_attributes::search::Outcome; use gix_glob::pattern::Case; -use gix_worktree::cache::state; +use gix_worktree::stack::state; #[test] fn baseline() -> crate::Result { @@ -19,17 +19,17 @@ fn baseline() -> crate::Result { let mut buf = Vec::new(); let mut collection = gix_attributes::search::MetadataCollection::default(); - let state = gix_worktree::cache::State::for_checkout( + let state = gix_worktree::stack::State::for_checkout( false, state::Attributes::new( gix_attributes::Search::new_globals([base.join("user.attributes")], &mut buf, &mut collection)?, Some(git_dir.join("info").join("attributes")), - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, collection, ), ); - let mut cache = gix_worktree::Cache::new(&base, state, case, buf, vec![]); + let mut cache = gix_worktree::Stack::new(&base, state, case, buf, vec![]); let mut actual = cache.attribute_matches(); let input = std::fs::read(base.join("baseline"))?; diff --git a/gix-worktree/tests/worktree/cache/create_directory.rs b/gix-worktree/tests/worktree/stack/create_directory.rs similarity index 89% rename from gix-worktree/tests/worktree/cache/create_directory.rs rename to gix-worktree/tests/worktree/stack/create_directory.rs index 48bfcd862e2..7d21c550394 100644 --- a/gix-worktree/tests/worktree/cache/create_directory.rs +++ b/gix-worktree/tests/worktree/stack/create_directory.rs @@ -1,7 +1,7 @@ use std::path::Path; -use gix_worktree::{cache, Cache}; -use tempfile::{tempdir, TempDir}; +use gix_testtools::tempfile::{tempdir, TempDir}; +use gix_worktree::{stack, Stack}; #[allow(clippy::ptr_arg)] fn panic_on_find<'buf>(_oid: &gix_hash::oid, _buf: &'buf mut Vec) -> std::io::Result> { @@ -11,9 +11,9 @@ fn panic_on_find<'buf>(_oid: &gix_hash::oid, _buf: &'buf mut Vec) -> std::io #[test] fn root_is_assumed_to_exist_and_files_in_root_do_not_create_directory() -> crate::Result { let dir = tempdir()?; - let mut cache = Cache::new( + let mut cache = Stack::new( dir.path().join("non-existing-root"), - cache::State::for_checkout(false, Default::default()), + stack::State::for_checkout(false, Default::default()), Default::default(), Vec::new(), Default::default(), @@ -68,7 +68,7 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R std::fs::write(tmp.path().join("file-in-dir"), [])?; for dirname in &["file-in-dir", "link-to-dir"] { - if let cache::State::CreateDirectoryAndAttributesStack { + if let stack::State::CreateDirectoryAndAttributesStack { unlink_on_collision, .. } = cache.state_mut() { @@ -90,7 +90,7 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R ); cache.take_statistics(); for dirname in &["link-to-dir", "file-in-dir"] { - if let cache::State::CreateDirectoryAndAttributesStack { + if let stack::State::CreateDirectoryAndAttributesStack { unlink_on_collision, .. } = cache.state_mut() { @@ -109,11 +109,11 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R Ok(()) } -fn new_cache() -> (Cache, TempDir) { +fn new_cache() -> (Stack, TempDir) { let dir = tempdir().unwrap(); - let cache = Cache::new( + let cache = Stack::new( dir.path(), - cache::State::for_checkout(false, Default::default()), + stack::State::for_checkout(false, Default::default()), Default::default(), Vec::new(), Default::default(), diff --git a/gix-worktree/tests/worktree/cache/ignore.rs b/gix-worktree/tests/worktree/stack/ignore.rs similarity index 93% rename from gix-worktree/tests/worktree/cache/ignore.rs rename to gix-worktree/tests/worktree/stack/ignore.rs index d8210694325..516475fbd7b 100644 --- a/gix-worktree/tests/worktree/cache/ignore.rs +++ b/gix-worktree/tests/worktree/stack/ignore.rs @@ -1,7 +1,7 @@ use bstr::{BStr, ByteSlice}; use gix_glob::pattern::Case; use gix_odb::FindExt; -use gix_worktree::{cache::state::ignore::Source, Cache}; +use gix_worktree::{stack::state::ignore::Source, Stack}; use crate::hex_to_id; @@ -37,16 +37,16 @@ fn exclude_by_dir_is_handled_just_like_git() { let mut buf = Vec::new(); let case = gix_glob::pattern::Case::Sensitive; - let state = gix_worktree::cache::State::for_add( + let state = gix_worktree::stack::State::for_add( Default::default(), - gix_worktree::cache::state::Ignore::new( + gix_worktree::stack::state::Ignore::new( Default::default(), gix_ignore::Search::from_git_dir(&git_dir, None, &mut buf).unwrap(), None, Source::WorktreeThenIdMappingIfNotSkipped, ), ); - let mut cache = Cache::new(&dir, state, case, buf, Default::default()); + let mut cache = Stack::new(&dir, state, case, buf, Default::default()); let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline")).unwrap(); let expectations = IgnoreExpectations { lines: baseline.lines(), @@ -95,9 +95,9 @@ fn check_against_baseline() -> crate::Result { }; let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?; let odb = gix_odb::at(git_dir.join("objects"))?; - let state = gix_worktree::cache::State::for_add( + let state = gix_worktree::stack::State::for_add( Default::default(), - gix_worktree::cache::state::Ignore::new( + gix_worktree::stack::state::Ignore::new( gix_ignore::Search::from_overrides(vec!["!force-include"]), gix_ignore::Search::from_git_dir(&git_dir, Some(user_exclude_path), &mut buf)?, None, @@ -113,7 +113,7 @@ fn check_against_baseline() -> crate::Result { hex_to_id("5c7e0ed672d3d31d83a3df61f13cc8f7b22d5bfd") )] ); - let mut cache = Cache::new(&worktree_dir, state, case, buf, attribute_files_in_index); + let mut cache = Stack::new(&worktree_dir, state, case, buf, attribute_files_in_index); let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?; let expectations = IgnoreExpectations { diff --git a/gix-worktree/tests/worktree/cache/mod.rs b/gix-worktree/tests/worktree/stack/mod.rs similarity index 100% rename from gix-worktree/tests/worktree/cache/mod.rs rename to gix-worktree/tests/worktree/stack/mod.rs diff --git a/gix/Cargo.toml b/gix/Cargo.toml index b3bd08d53a1..703c9c8e989 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -162,6 +162,7 @@ gix-credentials = { version = "^0.17.1", path = "../gix-credentials" } gix-prompt = { version = "^0.5.5", path = "../gix-prompt" } gix-index = { version = "^0.22.0", path = "../gix-index" } gix-worktree = { version = "^0.24.0", path = "../gix-worktree" } +gix-worktree-state = { version = "^0.1.0", path = "../gix-worktree-state" } gix-hashtable = { version = "^0.2.4", path = "../gix-hashtable" } gix-commitgraph = { version = "^0.18.2", path = "../gix-commitgraph" } gix-pathspec = { version = "^0.1.0", path = "../gix-pathspec" } diff --git a/gix/src/clone/checkout.rs b/gix/src/clone/checkout.rs index 8657f9a3aa9..a51b7197146 100644 --- a/gix/src/clone/checkout.rs +++ b/gix/src/clone/checkout.rs @@ -27,7 +27,8 @@ pub mod main_worktree { CheckoutOptions(#[from] crate::config::checkout_options::Error), #[error(transparent)] IndexCheckout( - #[from] gix_worktree::checkout::Error>, + #[from] + gix_worktree_state::checkout::Error>, ), #[error("Failed to reopen object database as Arc (only if thread-safety wasn't compiled in)")] OpenArcOdb(#[from] std::io::Error), @@ -68,7 +69,7 @@ pub mod main_worktree { &mut self, mut progress: impl crate::Progress, should_interrupt: &AtomicBool, - ) -> Result<(Repository, gix_worktree::checkout::Outcome), Error> { + ) -> Result<(Repository, gix_worktree_state::checkout::Outcome), Error> { let _span = gix_trace::coarse!("gix::clone::PrepareCheckout::main_worktree()"); let repo = self .repo @@ -82,7 +83,7 @@ pub mod main_worktree { None => { return Ok(( self.repo.take().expect("still present"), - gix_worktree::checkout::Outcome::default(), + gix_worktree_state::checkout::Outcome::default(), )) } }; @@ -95,7 +96,7 @@ pub mod main_worktree { let mut opts = repo .config - .checkout_options(repo, gix_worktree::cache::state::attributes::Source::IdMapping)?; + .checkout_options(repo, gix_worktree::stack::state::attributes::Source::IdMapping)?; opts.destination_is_initially_empty = true; let mut files = progress.add_child_with_id("checkout", ProgressId::CheckoutFiles.into()); @@ -105,7 +106,7 @@ pub mod main_worktree { bytes.init(None, crate::progress::bytes()); let start = std::time::Instant::now(); - let outcome = gix_worktree::checkout( + let outcome = gix_worktree_state::checkout( &mut index, workdir, { diff --git a/gix/src/config/cache/access.rs b/gix/src/config/cache/access.rs index 35220ce7644..7ca9be0d59c 100644 --- a/gix/src/config/cache/access.rs +++ b/gix/src/config/cache/access.rs @@ -160,8 +160,8 @@ impl Cache { pub(crate) fn checkout_options( &self, repo: &Repository, - attributes_source: gix_worktree::cache::state::attributes::Source, - ) -> Result { + attributes_source: gix_worktree::stack::state::attributes::Source, + ) -> Result { let git_dir = repo.git_dir(); let thread_limit = self.apply_leniency( self.resolved @@ -189,7 +189,7 @@ impl Cache { } else { gix_filter::driver::apply::Delay::Forbid }; - Ok(gix_worktree::checkout::Options { + Ok(gix_worktree_state::checkout::Options { filter_process_delay, filters, attributes: self @@ -219,14 +219,14 @@ impl Cache { &self, git_dir: &std::path::Path, overrides: Option, - source: gix_worktree::cache::state::ignore::Source, + source: gix_worktree::stack::state::ignore::Source, buf: &mut Vec, - ) -> Result { + ) -> Result { let excludes_file = match self.excludes_file().transpose()? { Some(user_path) => Some(user_path), None => self.xdg_config_path("ignore")?, }; - Ok(gix_worktree::cache::state::Ignore::new( + Ok(gix_worktree::stack::state::Ignore::new( overrides.unwrap_or_default(), gix_ignore::Search::from_git_dir(git_dir, excludes_file, buf)?, None, @@ -237,9 +237,9 @@ impl Cache { pub(crate) fn assemble_attribute_globals( &self, git_dir: &std::path::Path, - source: gix_worktree::cache::state::attributes::Source, + source: gix_worktree::stack::state::attributes::Source, attributes: crate::open::permissions::Attributes, - ) -> Result<(gix_worktree::cache::state::Attributes, Vec), config::attribute_stack::Error> { + ) -> Result<(gix_worktree::stack::state::Attributes, Vec), config::attribute_stack::Error> { let configured_or_user_attributes = match self .trusted_file_path("core", None, Core::ATTRIBUTES_FILE.name) .transpose()? @@ -265,7 +265,7 @@ impl Cache { let info_attributes_path = git_dir.join("info").join("attributes"); let mut buf = Vec::new(); let mut collection = gix_attributes::search::MetadataCollection::default(); - let state = gix_worktree::cache::state::Attributes::new( + let state = gix_worktree::stack::state::Attributes::new( gix_attributes::Search::new_globals(attribute_files, &mut buf, &mut collection)?, Some(info_attributes_path), source, diff --git a/gix/src/filter.rs b/gix/src/filter.rs index 073ea6328b9..27447e12bc7 100644 --- a/gix/src/filter.rs +++ b/gix/src/filter.rs @@ -67,7 +67,7 @@ pub mod pipeline { #[derive(Clone)] pub struct Pipeline<'repo> { inner: gix_filter::Pipeline, - cache: gix_worktree::Cache, + cache: gix_worktree::Stack, repo: &'repo Repository, } @@ -110,7 +110,7 @@ impl<'repo> Pipeline<'repo> { /// Create a new instance by extracting all necessary information and configuration from a `repo` along with `cache` for accessing /// attributes. The `index` is used for some filters which may access it under very specific circumstances. - pub fn new(repo: &'repo Repository, cache: gix_worktree::Cache) -> Result { + pub fn new(repo: &'repo Repository, cache: gix_worktree::Stack) -> Result { let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), Self::options(repo)?); Ok(Pipeline { inner: pipeline, @@ -120,7 +120,7 @@ impl<'repo> Pipeline<'repo> { } /// Detach the repository and obtain the individual functional parts. - pub fn into_parts(self) -> (gix_filter::Pipeline, gix_worktree::Cache) { + pub fn into_parts(self) -> (gix_filter::Pipeline, gix_worktree::Stack) { (self.inner, self.cache) } } diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index 16649898d2f..587aef4bf93 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -43,7 +43,7 @@ impl<'repo> Pathspec<'repo> { repo: &'repo Repository, patterns: impl IntoIterator>, inherit_ignore_case: bool, - make_attributes: impl FnOnce() -> Result>, + make_attributes: impl FnOnce() -> Result>, ) -> Result { let mut defaults = repo.pathspec_defaults()?; if inherit_ignore_case && repo.config.fs_capabilities()?.ignore_case { @@ -67,9 +67,9 @@ impl<'repo> Pathspec<'repo> { Ok(Self { repo, search, cache }) } /// Turn ourselves into the functional parts for direct usage. - /// Note that the [`cache`](gix_worktree::Cache) is only set if one of the [`search` patterns](Search) + /// Note that the [`cache`](gix_worktree::Stack) is only set if one of the [`search` patterns](Search) /// is specifying attributes to match for. - pub fn into_parts(self) -> (Search, Option) { + pub fn into_parts(self) -> (Search, Option) { (self.search, self.cache) } } @@ -77,7 +77,7 @@ impl<'repo> Pathspec<'repo> { /// Access impl<'repo> Pathspec<'repo> { /// Return the attributes cache which is used when matching attributes in pathspecs, or `None` if none of the pathspecs require that. - pub fn attributes(&self) -> Option<&gix_worktree::Cache> { + pub fn attributes(&self) -> Option<&gix_worktree::Stack> { self.cache.as_ref() } diff --git a/gix/src/repository/attributes.rs b/gix/src/repository/attributes.rs index 23fd65203d9..e875ef0b0d8 100644 --- a/gix/src/repository/attributes.rs +++ b/gix/src/repository/attributes.rs @@ -29,10 +29,10 @@ impl Repository { pub fn attributes( &self, index: &gix_index::State, - attributes_source: gix_worktree::cache::state::attributes::Source, - ignore_source: gix_worktree::cache::state::ignore::Source, + attributes_source: gix_worktree::stack::state::attributes::Source, + ignore_source: gix_worktree::stack::state::ignore::Source, exclude_overrides: Option, - ) -> Result { + ) -> Result { let case = if self.config.ignore_case { gix_glob::pattern::Case::Fold } else { @@ -46,9 +46,9 @@ impl Repository { let ignore = self.config .assemble_exclude_globals(self.git_dir(), exclude_overrides, ignore_source, &mut buf)?; - let state = gix_worktree::cache::State::AttributesAndIgnoreStack { attributes, ignore }; + let state = gix_worktree::stack::State::AttributesAndIgnoreStack { attributes, ignore }; let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case); - Ok(gix_worktree::Cache::new( + Ok(gix_worktree::Stack::new( // this is alright as we don't cause mutation of that directory, it's virtual. self.work_dir().unwrap_or(self.git_dir()), state, @@ -62,8 +62,8 @@ impl Repository { pub fn attributes_only( &self, index: &gix_index::State, - attributes_source: gix_worktree::cache::state::attributes::Source, - ) -> Result { + attributes_source: gix_worktree::stack::state::attributes::Source, + ) -> Result { let case = if self.config.ignore_case { gix_glob::pattern::Case::Fold } else { @@ -74,9 +74,9 @@ impl Repository { attributes_source, self.options.permissions.attributes, )?; - let state = gix_worktree::cache::State::AttributesStack(attributes); + let state = gix_worktree::stack::State::AttributesStack(attributes); let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case); - Ok(gix_worktree::Cache::new( + Ok(gix_worktree::Stack::new( // this is alright as we don't cause mutation of that directory, it's virtual. self.work_dir().unwrap_or(self.git_dir()), state, @@ -105,8 +105,8 @@ impl Repository { &self, index: &gix_index::State, overrides: Option, - source: gix_worktree::cache::state::ignore::Source, - ) -> Result { + source: gix_worktree::stack::state::ignore::Source, + ) -> Result { let case = if self.config.ignore_case { gix_glob::pattern::Case::Fold } else { @@ -116,9 +116,9 @@ impl Repository { let ignore = self .config .assemble_exclude_globals(self.git_dir(), overrides, source, &mut buf)?; - let state = gix_worktree::cache::State::IgnoreStack(ignore); + let state = gix_worktree::stack::State::IgnoreStack(ignore); let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case); - Ok(gix_worktree::Cache::new( + Ok(gix_worktree::Stack::new( // this is alright as we don't cause mutation of that directory, it's virtual. self.work_dir().unwrap_or(self.git_dir()), state, diff --git a/gix/src/repository/filter.rs b/gix/src/repository/filter.rs index 77dd9005d62..6f08309ce0f 100644 --- a/gix/src/repository/filter.rs +++ b/gix/src/repository/filter.rs @@ -49,13 +49,13 @@ impl Repository { }, Ok, )?)?; - let cache = self.attributes_only(&index, gix_worktree::cache::state::attributes::Source::IdMapping)?; + let cache = self.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?; (cache, IndexPersistedOrInMemory::InMemory(index)) } else { let index = self.index()?; let cache = self.attributes_only( &index, - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, )?; (cache, IndexPersistedOrInMemory::Persisted(index)) }; diff --git a/gix/src/repository/pathspec.rs b/gix/src/repository/pathspec.rs index 5a7e8245fec..4b2ab8c331a 100644 --- a/gix/src/repository/pathspec.rs +++ b/gix/src/repository/pathspec.rs @@ -17,7 +17,7 @@ impl Repository { Pathspec::new(self, patterns, inherit_ignore_case, || { self.attributes_only( index, - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, ) .map_err(Into::into) }) diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index c182e624342..b05c4fcbf48 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -74,7 +74,7 @@ impl crate::Repository { // TODO(perf): when loading a non-HEAD tree, we effectively traverse the tree twice. This is usually fast though, and sharing // an object cache between the copies of the ODB handles isn't trivial and needs a lock. let index = self.index_from_tree(&id)?; - let mut cache = self.attributes_only(&index, gix_worktree::cache::state::attributes::Source::IdMapping)?; + let mut cache = self.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?; let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), crate::filter::Pipeline::options(self)?); let objects = self.objects.clone().into_arc().expect("TBD error handling"); diff --git a/gix/src/types.rs b/gix/src/types.rs index 581ea76e92b..076512a4b58 100644 --- a/gix/src/types.rs +++ b/gix/src/types.rs @@ -202,7 +202,7 @@ pub struct Remote<'repo> { pub struct Pathspec<'repo> { pub(crate) repo: &'repo Repository, /// The cache to power attribute access. It's only initialized if we have a pattern with attributes. - pub(crate) cache: Option, + pub(crate) cache: Option, /// The prepared search to use for checking matches. pub(crate) search: gix_pathspec::Search, } diff --git a/gix/src/worktree/mod.rs b/gix/src/worktree/mod.rs index 3fbdca49993..bd808373927 100644 --- a/gix/src/worktree/mod.rs +++ b/gix/src/worktree/mod.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; #[cfg(feature = "worktree-archive")] pub use gix_archive as archive; pub use gix_worktree::*; +pub use gix_worktree_state as state; #[cfg(feature = "worktree-stream")] pub use gix_worktree_stream as stream; @@ -120,12 +121,12 @@ pub mod excludes { /// /// When only excludes are desired, this is the most efficient way to obtain them. Otherwise use /// [`Worktree::attributes()`][crate::Worktree::attributes()] for accessing both attributes and excludes. - pub fn excludes(&self, overrides: Option) -> Result { + pub fn excludes(&self, overrides: Option) -> Result { let index = self.index()?; Ok(self.parent.excludes( &index, overrides, - gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, + gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, )?) } } @@ -150,23 +151,23 @@ pub mod attributes { /// /// * `$XDG_CONFIG_HOME/…/ignore|attributes` if `core.excludesFile|attributesFile` is *not* set, otherwise use the configured file. /// * `$GIT_DIR/info/exclude|attributes` if present. - pub fn attributes(&self, overrides: Option) -> Result { + pub fn attributes(&self, overrides: Option) -> Result { let index = self.index()?; Ok(self.parent.attributes( &index, - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, - gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped, overrides, )?) } /// Like [attributes()][Self::attributes()], but without access to exclude/ignore information. - pub fn attributes_only(&self) -> Result { + pub fn attributes_only(&self) -> Result { let index = self.index()?; self.parent .attributes_only( &index, - gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping, ) .map_err(|err| Error::CreateCache(err.into())) } diff --git a/justfile b/justfile index 0421dc4c995..5284615fbeb 100755 --- a/justfile +++ b/justfile @@ -99,6 +99,7 @@ check: cargo check -p gix-config-value cargo check -p gix-config --all-features cargo check -p gix-config + cargo check -p gix-diff --no-default-features cargo check -p gix-transport cargo check -p gix-transport --features blocking-client cargo check -p gix-transport --features async-client @@ -134,14 +135,18 @@ unit-tests: cargo test -p gix-archive --features tar cargo test -p gix-archive --features tar_gz cargo test -p gix-archive --features zip - cd gix-object; \ + cd gix-status; \ set -ex; \ cargo test; \ - cargo test --features verbose-object-parsing-errors - cd gix-worktree; \ + cargo test --features "internal-testing-gix-features-parallel" + cd gix-worktree-state; \ set -ex; \ cargo test; \ cargo test --features "internal-testing-gix-features-parallel" + cd gix-object; \ + set -ex; \ + cargo test; \ + cargo test --features verbose-object-parsing-errors cargo test -p gix-tempfile --features signals cargo test -p gix-tempfile cargo test -p gix-features