History

Merge branch 'worktree-organization'

Sebastian Thiel committed 3 years ago

Commit 8d0d8e02 parents ef54aab e5717e193 files · +424 −252Browse files

Unified · Split

93 files
  1. Cargo.lock +38 −4
  2. Cargo.toml +2 −0
  3. README.md +2 −0
  4. crate-status.md +28 −20
  5. etc/gix-components.monopic +0 −0
  6. etc/gix-components.txt +3 −0
  7. gitoxide-core/src/hours/core.rs +2 −2
  8. gitoxide-core/src/index/checkout.rs +4 −4
  9. gitoxide-core/src/repository/attributes/query.rs +4 −4
  10. gitoxide-core/src/repository/clone.rs +1 −1
  11. gitoxide-core/src/repository/index/entries.rs +7 −7
  12. gix-archive/tests/archive.rs +5 −5
  13. gix-diff/Cargo.toml +11 −1
  14. gix-diff/src/lib.rs +7 −0
  15. gix-filter/tests/pipeline/mod.rs +8 −8
  16. gix-status/CHANGELOG.md +0 −0
  17. gix-status/Cargo.toml +37 −0
  18. gix-status/LICENSE-APACHE +1 −0
  19. gix-status/LICENSE-MIT +1 −0
  20. gix-status/src/index_as_worktree/content.rs +0 −0
  21. gix-status/src/index_as_worktree/function.rs +3 −3
  22. gix-status/src/index_as_worktree/mod.rs +0 −0
  23. gix-status/src/index_as_worktree/recorder.rs +1 −1
  24. gix-status/src/index_as_worktree/types.rs +2 −2
  25. gix-status/src/lib.rs +15 −0
  26. gix-status/src/read.rs +1 −2
  27. gix-status/tests/fixtures/generated-archives/.gitignore +2 −0
  28. gix-status/tests/fixtures/generated-archives/racy_git.tar.xz +3 −0
  29. gix-status/tests/fixtures/generated-archives/status_conflict.tar.xz +3 −0
  30. gix-status/tests/fixtures/generated-archives/status_intent_to_add.tar.xz +3 −0
  31. gix-status/tests/fixtures/generated-archives/status_removed.tar.xz +3 −0
  32. gix-status/tests/fixtures/racy_git.sh +0 −0
  33. gix-status/tests/fixtures/status_changed.sh +0 −0
  34. gix-status/tests/fixtures/status_conflict.sh +0 −0
  35. gix-status/tests/fixtures/status_intent_to_add.sh +0 −0
  36. gix-status/tests/fixtures/status_removed.sh +0 −0
  37. gix-status/tests/fixtures/status_unchanged.sh +0 −0
  38. gix-status/tests/status-multi-threaded.rs +4 −0
  39. gix-status/tests/status-single-threaded.rs +4 −0
  40. gix-status/tests/status/index_as_worktree.rs +6 −6
  41. gix-status/tests/status/mod.rs +7 −0
  42. gix-worktree-state/Cargo.toml +44 −0
  43. gix-worktree-state/LICENSE-APACHE +1 −0
  44. gix-worktree-state/LICENSE-MIT +1 −0
  45. gix-worktree-state/src/checkout/chunk.rs +3 −2
  46. gix-worktree-state/src/checkout/entry.rs +2 −2
  47. gix-worktree-state/src/checkout/function.rs +4 −3
  48. gix-worktree-state/src/checkout/mod.rs +1 −1
  49. gix-worktree-state/src/lib.rs +6 −0
  50. gix-worktree-state/tests/fixtures/generated-archives/.gitignore +5 −0
  51. gix-worktree-state/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz +0 −0
  52. gix-worktree-state/tests/fixtures/make_dangerous_symlink.sh +0 −0
  53. gix-worktree-state/tests/fixtures/make_ignorecase_collisions.sh +0 −0
  54. gix-worktree-state/tests/fixtures/make_mixed_without_submodules.sh +0 −0
  55. gix-worktree-state/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh +0 −0
  56. gix-worktree-state/tests/state-multi-threaded.rs +4 −0
  57. gix-worktree-state/tests/state-single-threaded.rs +4 −0
  58. gix-worktree-state/tests/state/checkout.rs +10 −10
  59. gix-worktree-state/tests/state/mod.rs +10 −0
  60. gix-worktree-stream/tests/stream.rs +5 −5
  61. gix-worktree/Cargo.toml +1 −9
  62. gix-worktree/src/lib.rs +5 −14
  63. gix-worktree/src/stack/delegate.rs +1 −1
  64. gix-worktree/src/stack/mod.rs +10 −10
  65. gix-worktree/src/stack/platform.rs +1 −1
  66. gix-worktree/src/stack/state/attributes.rs +5 −5
  67. gix-worktree/src/stack/state/ignore.rs +2 −2
  68. gix-worktree/src/stack/state/mod.rs +1 −1
  69. gix-worktree/src/untracked.rs +0 −1
  70. gix-worktree/tests/fixtures/generated-archives/.gitignore +0 −5
  71. gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz +2 −2
  72. gix-worktree/tests/fixtures/generated-archives/racy_git.tar.xz +0 −3
  73. gix-worktree/tests/fixtures/generated-archives/status_conflict.tar.xz +0 −3
  74. gix-worktree/tests/fixtures/generated-archives/status_intent_to_add.tar.xz +0 −3
  75. gix-worktree/tests/fixtures/generated-archives/status_removed.tar.xz +0 −3
  76. gix-worktree/tests/fixtures/make_ignore_setup.sh +0 −18
  77. gix-worktree/tests/worktree/mod.rs +2 −10
  78. gix-worktree/tests/worktree/stack/attributes.rs +4 −4
  79. gix-worktree/tests/worktree/stack/create_directory.rs +9 −9
  80. gix-worktree/tests/worktree/stack/ignore.rs +7 −7
  81. gix-worktree/tests/worktree/stack/mod.rs +0 −0
  82. gix/Cargo.toml +1 −0
  83. gix/src/clone/checkout.rs +6 −5
  84. gix/src/config/cache/access.rs +9 −9
  85. gix/src/filter.rs +3 −3
  86. gix/src/pathspec.rs +4 −4
  87. gix/src/repository/attributes.rs +13 −13
  88. gix/src/repository/filter.rs +2 −2
  89. gix/src/repository/pathspec.rs +1 −1
  90. gix/src/repository/worktree.rs +1 −1
  91. gix/src/types.rs +1 −1
  92. gix/src/worktree/mod.rs +8 −7
  93. justfile +8 −3
Cargo.lock+38−4
@@ -1240,6 +1240,7 @@ dependencies = [ · 1239 unmodified lines
12401240 "gix-utils 0.1.5",
12411241 "gix-validate 0.8.0",
12421242 "gix-worktree 0.24.0",
1243+ "gix-worktree-state",
12431244 "gix-worktree-stream",
12441245 "is_ci",
12451246 "log",
@@ -1497,6 +1498,7 @@ dependencies = [ · 251 unmodified lines
14971498 name = "gix-diff"
14981499 version = "0.34.0"
14991500 dependencies = [
1501+ "document-features",
15001502 "getrandom",
15011503 "gix-hash 0.11.4",
15021504 "gix-object 0.34.0",
@@ -2215,6 +2217,22 @@ dependencies = [ · 712 unmodified lines
22152217 name = "gix-sequencer"
22162218 version = "0.0.0"
22172219
2220+[[package]]
2221+name = "gix-status"
2222+version = "0.1.0"
2223+dependencies = [
2224+ "bstr",
2225+ "filetime",
2226+ "gix-features 0.32.1",
2227+ "gix-fs 0.4.1",
2228+ "gix-hash 0.11.4",
2229+ "gix-index 0.22.0",
2230+ "gix-object 0.34.0",
2231+ "gix-path 0.8.4",
2232+ "gix-testtools",
2233+ "thiserror",
2234+]
2235+
22182236 [[package]]
22192237 name = "gix-submodule"
22202238 version = "0.1.0"
@@ -2449,10 +2467,8 @@ version = "0.24.0" · 228 unmodified lines
24492467 dependencies = [
24502468 "bstr",
24512469 "document-features",
2452− "filetime",
24532470 "gix-attributes 0.16.0",
24542471 "gix-features 0.32.1",
2455− "gix-filter",
24562472 "gix-fs 0.4.1",
24572473 "gix-glob 0.10.2",
24582474 "gix-hash 0.11.4",
@@ -2462,11 +2478,29 @@ dependencies = [ · 3 unmodified lines
24622478 "gix-odb",
24632479 "gix-path 0.8.4",
24642480 "gix-testtools",
2481+ "serde",
2482+ "symlink",
2483+]
2484+
2485+[[package]]
2486+name = "gix-worktree-state"
2487+version = "0.1.0"
2488+dependencies = [
2489+ "bstr",
2490+ "gix-features 0.32.1",
2491+ "gix-filter",
2492+ "gix-fs 0.4.1",
2493+ "gix-glob 0.10.2",
2494+ "gix-hash 0.11.4",
2495+ "gix-index 0.22.0",
2496+ "gix-object 0.34.0",
2497+ "gix-odb",
2498+ "gix-path 0.8.4",
2499+ "gix-testtools",
2500+ "gix-worktree 0.24.0",
24652501 "io-close",
24662502 "once_cell",
2467− "serde",
24682503 "symlink",
2469− "tempfile",
24702504 "thiserror",
24712505 "walkdir",
24722506 ]
Cargo.toml+2−0
@@ -235,6 +235,8 @@ members = [ · 234 unmodified lines
235235 "gix-index",
236236 "gix-bitmap",
237237 "gix-worktree",
238+ "gix-worktree-state",
239+ "gix-status",
238240 "gix-revision",
239241 "gix-packetline",
240242 "gix-packetline-blocking",
README.md+2−0
@@ -95,6 +95,8 @@ is usable to some extent. · 94 unmodified lines
9595 * [gix-worktree-stream](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-worktree-stream)
9696 * [gix-archive](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-archive)
9797 * [gix-submodule](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-submodule)
98+ * [gix-status](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-status)
99+ * [gix-worktree-state](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-worktree-state)
98100 * `gitoxide-core`
99101 * **very early** _(possibly without any documentation and many rough edges)_
100102 * [gix-date](https://github.com/Byron/gitoxide/blob/main/crate-status.md#gix-date)
crate-status.md+28−20
@@ -453,28 +453,36 @@ Make it the best-performing implementation and the most convenient one. · 452 unmodified lines
453453 ### gix-glob
454454 * [x] parse pattern
455455 * [x] a type for pattern matching of paths and non-paths, optionally case-insensitively.
456−
457−### gix-worktree
456+
457+### gix-status
458+* [x] differences between index and worktree to turn index into worktree
459+* [ ] differences between tree and index to turn tree into index
460+* [ ] untracked files
461+* [ ] fast answer to 'is it dirty'.
462+*
463+### gix-worktree-state
458464 * handle the working **tree/checkout**
459− - [x] checkout an index of files, executables and symlinks just as fast as git
460− - [x] forbid symlinks in directories
461− - [ ] handle submodules
462− - [ ] handle sparse directories
463− - [ ] handle sparse index
464− - [x] linear scaling with multi-threading up to IO saturation
465− - supported attributes to affect working tree and index contents
466− - [ ] eol
467− - [ ] working-tree-encoding
468− - …more
469− - **filtering**
470− - [ ] `text`
471− - [ ] `ident`
472− - [ ] filter processes
473− - [ ] single-invocation clean/smudge filters
474−* manage multiple worktrees
465+ - [x] checkout an index of files, executables and symlinks just as fast as git
466+ - [x] forbid symlinks in directories
467+ - [ ] handle submodules
468+ - [ ] handle sparse directories
469+ - [ ] handle sparse index
470+ - [x] linear scaling with multi-threading up to IO saturation
471+ - supported attributes to affect working tree and index contents
472+ - [x] eol
473+ - [x] working-tree-encoding
474+ - …more
475+ - **filtering**
476+ - [x] `text`
477+ - [x] `ident`
478+ - [x] filter processes
479+ - [x] single-invocation clean/smudge filters
475480 * access to per-path information, like `.gitignore` and `.gitattributes` in a manner well suited for efficient lookups
476− * [x] _exclude_ information
477− * [ ] attributes
481+ * [x] _exclude_ information
482+ * [x] attributes
483+
484+### gix-worktree
485+* [x] A stack to to efficiently generate attribute lists for matching paths against.
478486
479487 ### gix-revision
480488 * [x] `describe()` (similar to `git name-rev`)
etc/gix-components.monopic+0−0

Binary file not shown.

etc/gix-components.txt+3−0
@@ -0,0 +1,3 @@
1+╔════════════════╗
2+║ gix-submodule ║
3+╚════════════════╝
gitoxide-core/src/hours/core.rs+2−2
@@ -101,8 +101,8 @@ pub fn spawn_tree_delta_threads<'scope>( · 100 unmodified lines
101101 repo.index_or_load_from_head().map_err(Into::into).and_then(|index| {
102102 repo.attributes(
103103 &index,
104− gix::worktree::cache::state::attributes::Source::IdMapping,
105− gix::worktree::cache::state::ignore::Source::IdMapping,
104+ gix::worktree::stack::state::attributes::Source::IdMapping,
105+ gix::worktree::stack::state::ignore::Source::IdMapping,
106106 None,
107107 )
108108 .map_err(Into::into)
gitoxide-core/src/index/checkout.rs+4−4
@@ -4,7 +4,7 @@ use std::{ · 3 unmodified lines
44 };
55
66 use anyhow::bail;
7−use gix::{odb::FindExt, worktree::checkout, Progress};
7+use gix::{odb::FindExt, worktree::state::checkout, Progress};
88
99 use crate::{
1010 index,
@@ -55,7 +55,7 @@ pub fn checkout_exclusive( · 44 unmodified lines
5555 progress.info(format!("Skipping {num_skipped} DIR/SYMLINK/COMMIT entries"));
5656 }
5757
58− let opts = gix::worktree::checkout::Options {
58+ let opts = gix::worktree::state::checkout::Options {
5959 fs: gix::fs::Capabilities::probe(dest_directory),
6060
6161 destination_is_initially_empty: true,
@@ -86,7 +86,7 @@ pub fn checkout_exclusive( · 24 unmodified lines
8686 delayed_paths_unknown,
8787 delayed_paths_unprocessed,
8888 } = match repo {
89− Some(repo) => gix::worktree::checkout(
89+ Some(repo) => gix::worktree::state::checkout(
9090 &mut index,
9191 dest_directory,
9292 {
@@ -109,7 +109,7 @@ pub fn checkout_exclusive( · 16 unmodified lines
109109 should_interrupt,
110110 opts,
111111 ),
112− None => gix::worktree::checkout(
112+ None => gix::worktree::state::checkout(
113113 &mut index,
114114 dest_directory,
115115 |_, buf| {
gitoxide-core/src/repository/attributes/query.rs+4−4
@@ -89,16 +89,16 @@ pub(crate) mod function { · 88 unmodified lines
8989
9090 pub(crate) fn attributes_cache(
9191 repo: &gix::Repository,
92−) -> anyhow::Result<(gix::worktree::Cache, IndexPersistedOrInMemory)> {
92+) -> anyhow::Result<(gix::worktree::Stack, IndexPersistedOrInMemory)> {
9393 let index = repo.index_or_load_from_head()?;
9494 let cache = repo.attributes(
9595 &index,
9696 if repo.is_bare() {
97− gix::worktree::cache::state::attributes::Source::IdMapping
97+ gix::worktree::stack::state::attributes::Source::IdMapping
9898 } else {
99− gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping
99+ gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping
100100 },
101− gix::worktree::cache::state::ignore::Source::IdMapping,
101+ gix::worktree::stack::state::ignore::Source::IdMapping,
102102 None,
103103 )?;
104104 Ok((cache, index))
gitoxide-core/src/repository/clone.rs+1−1
@@ -111,7 +111,7 @@ pub(crate) mod function { · 110 unmodified lines
111111 }
112112 };
113113
114− if let Some(gix::worktree::checkout::Outcome { collisions, errors, .. }) = outcome {
114+ if let Some(gix::worktree::state::checkout::Outcome { collisions, errors, .. }) = outcome {
115115 if !(collisions.is_empty() && errors.is_empty()) {
116116 let mut messages = Vec::new();
117117 if !errors.is_empty() {
gitoxide-core/src/repository/index/entries.rs+7−7
@@ -56,22 +56,22 @@ pub(crate) mod function { · 55 unmodified lines
5656 match attrs {
5757 Attributes::WorktreeAndIndex => {
5858 if repo.is_bare() {
59− gix::worktree::cache::state::attributes::Source::IdMapping
59+ gix::worktree::stack::state::attributes::Source::IdMapping
6060 } else {
61− gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping
61+ gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping
6262 }
6363 }
64− Attributes::Index => gix::worktree::cache::state::attributes::Source::IdMapping,
64+ Attributes::Index => gix::worktree::stack::state::attributes::Source::IdMapping,
6565 },
6666 match attrs {
6767 Attributes::WorktreeAndIndex => {
6868 if repo.is_bare() {
69− gix::worktree::cache::state::ignore::Source::IdMapping
69+ gix::worktree::stack::state::ignore::Source::IdMapping
7070 } else {
71− gix::worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped
71+ gix::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped
7272 }
7373 }
74− Attributes::Index => gix::worktree::cache::state::ignore::Source::IdMapping,
74+ Attributes::Index => gix::worktree::stack::state::ignore::Source::IdMapping,
7575 },
7676 None,
7777 )
@@ -203,7 +203,7 @@ pub(crate) mod function { · 125 unmodified lines
203203 pub excluded: usize,
204204 pub with_attributes: usize,
205205 pub max_attributes_per_path: usize,
206− pub cache: Option<gix::worktree::cache::Statistics>,
206+ pub cache: Option<gix::worktree::stack::Statistics>,
207207 }
208208
209209 #[cfg(feature = "serde")]
gix-archive/tests/archive.rs+5−5
@@ -11,7 +11,7 @@ mod from_tree { · 10 unmodified lines
1111 use gix_object::tree::EntryMode;
1212 use gix_odb::FindExt;
1313 use gix_testtools::bstr::ByteSlice;
14− use gix_worktree::cache::state::attributes::Source;
14+ use gix_worktree::stack::state::attributes::Source;
1515
1616 use crate::hex_to_id;
1717
@@ -284,7 +284,7 @@ mod from_tree { · 266 unmodified lines
284284 Ok(())
285285 }
286286
287− fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Cache)> {
287+ fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Stack)> {
288288 let dir = gix_testtools::scripted_fixture_read_only("basic.sh")?;
289289
290290 let head = {
@@ -295,14 +295,14 @@ mod from_tree { · 4 unmodified lines
295295
296296 let mut collection = Default::default();
297297 let mut buf = Default::default();
298− let attributes = gix_worktree::cache::state::Attributes::new(
298+ let attributes = gix_worktree::stack::state::Attributes::new(
299299 gix_attributes::Search::new_globals(None::<PathBuf>, &mut buf, &mut collection)?,
300300 None,
301301 Source::WorktreeThenIdMapping,
302302 collection,
303303 );
304− let state = gix_worktree::cache::State::AttributesStack(attributes);
305− let cache = gix_worktree::Cache::new(&dir, state, Case::Sensitive, Default::default(), Default::default());
304+ let state = gix_worktree::stack::State::AttributesStack(attributes);
305+ let cache = gix_worktree::Stack::new(&dir, state, Case::Sensitive, Default::default(), Default::default());
306306 Ok((dir, head, odb.into_arc()?, cache))
307307 }
308308
gix-diff/Cargo.toml+11−1
@@ -11,6 +11,9 @@ rust-version = "1.65" · 10 unmodified lines
1111 autotests = false
1212
1313 [features]
14+default = ["blob"]
15+## Enable diffing of blobs using imara-diff.
16+blob = ["dep:imara-diff"]
1417 ## Data structures implement `serde::Serialize` and `serde::Deserialize`.
1518 serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
1619 ## Make it possible to compile to the `wasm32-unknown-unknown` target.
@@ -23,6 +26,13 @@ doctest = false · 6 unmodified lines
2326 gix-hash = { version = "^0.11.4", path = "../gix-hash" }
2427 gix-object = { version = "^0.34.0", path = "../gix-object" }
2528 thiserror = "1.0.32"
26−imara-diff = "0.1.3"
29+imara-diff = { version = "0.1.3", optional = true }
2730 serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
2831 getrandom = { version = "0.2.8", optional = true, default-features = false, features = ["js"] }
32+
33+document-features = { version = "0.2.0", optional = true }
34+
35+[package.metadata.docs.rs]
36+all-features = true
37+features = ["document-features"]
38+rustdoc-args = ["--cfg", "docsrs"]
gix-diff/src/lib.rs+7−0
@@ -1,4 +1,10 @@
11 //! Algorithms for diffing various git object types and for generating patches, highly optimized for performance.
2+//! ## Feature Flags
3+#![cfg_attr(
4+feature = "document-features",
5+cfg_attr(doc, doc = ::document_features::document_features!())
6+)]
7+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
28 #![deny(missing_docs, rust_2018_idioms)]
39 #![forbid(unsafe_code)]
410
@@ -6,4 +12,5 @@ · 1 unmodified line
612 pub mod tree;
713
814 ///
15+#[cfg(feature = "blob")]
916 pub mod blob;
gix-filter/tests/pipeline/mod.rs+8−8
@@ -17,22 +17,22 @@ fn default() -> crate::Result { · 16 unmodified lines
1717 Ok(())
1818 }
1919
20−fn attribute_cache(name: &str) -> gix_testtools::Result<gix_worktree::Cache> {
20+fn attribute_cache(name: &str) -> gix_testtools::Result<gix_worktree::Stack> {
2121 let dir = gix_testtools::scripted_fixture_read_only("pipeline_repos.sh")?.join(name);
22− Ok(gix_worktree::Cache::new(
22+ Ok(gix_worktree::Stack::new(
2323 dir,
24− gix_worktree::cache::State::for_add(
25− gix_worktree::cache::state::Attributes::new(
24+ gix_worktree::stack::State::for_add(
25+ gix_worktree::stack::state::Attributes::new(
2626 Default::default(),
2727 None,
28− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
28+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
2929 Default::default(),
3030 ),
31− gix_worktree::cache::state::Ignore::new(
31+ gix_worktree::stack::state::Ignore::new(
3232 Default::default(),
3333 Default::default(),
3434 None,
35− gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
35+ gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
3636 ),
3737 ),
3838 Case::Sensitive,
@@ -49,7 +49,7 @@ fn pipeline( · 10 unmodified lines
4949 gix_filter::pipeline::CrlfRoundTripCheck,
5050 eol::Configuration,
5151 ),
52−) -> gix_testtools::Result<(gix_worktree::Cache, gix_filter::Pipeline)> {
52+) -> gix_testtools::Result<(gix_worktree::Stack, gix_filter::Pipeline)> {
5353 let cache = attribute_cache(name)?;
5454 let (drivers, encodings_with_roundtrip_check, crlf_roundtrip_check, eol_config) = init();
5555 let pipe = gix_filter::Pipeline::new(
gix-status/CHANGELOG.mdrenamed from gix-worktree/CHANGELOG.md+0−0

File renamed without changes.

gix-status/Cargo.toml+37−0
@@ -0,0 +1,37 @@
1+[package]
2+name = "gix-status"
3+version = "0.1.0"
4+repository = "https://github.com/Byron/gitoxide"
5+license = "MIT OR Apache-2.0"
6+description = "A crate of the gitoxide project dealing with 'git status'-like functionality"
7+authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>", "Pascal Kuthe <pascal.kuthe@semimod.de>"]
8+edition = "2021"
9+include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"]
10+rust-version = "1.65"
11+
12+[lib]
13+doctest = false
14+
15+[[test]]
16+name = "multi-threaded"
17+path = "tests/status-multi-threaded.rs"
18+required-features = ["internal-testing-gix-features-parallel"]
19+
20+[features]
21+internal-testing-gix-features-parallel = ["gix-features/parallel"]
22+
23+[dependencies]
24+gix-index = { version = "^0.22.0", path = "../gix-index" }
25+gix-fs = { version = "^0.4.1", path = "../gix-fs" }
26+gix-hash = { version = "^0.11.4", path = "../gix-hash" }
27+gix-object = { version = "^0.34.0", path = "../gix-object" }
28+gix-path = { version = "^0.8.4", path = "../gix-path" }
29+gix-features = { version = "^0.32.1", path = "../gix-features" }
30+
31+thiserror = "1.0.26"
32+filetime = "0.2.15"
33+bstr = { version = "1.3.0", default-features = false }
34+
35+[dev-dependencies]
36+gix-testtools = { path = "../tests/tools" }
37+
gix-status/LICENSE-APACHE+1−0
@@ -0,0 +1 @@
1+../LICENSE-APACHE
gix-status/LICENSE-MIT+1−0
@@ -0,0 +1 @@
1+../LICENSE-MIT
gix-status/src/index_as_worktree/content.rsrenamed from gix-worktree/src/status/content.rs+0−0

File renamed without changes.

gix-status/src/index_as_worktree/function.rsrenamed from gix-worktree/src/status/function.rs+3−3
@@ -5,13 +5,13 @@ use filetime::FileTime; · 4 unmodified lines
55 use gix_features::parallel::{in_parallel_if, Reduce};
66
77 use crate::{
8− read,
9− status::{
8+ index_as_worktree::{
109 content,
1110 content::CompareBlobs,
1211 types::{Error, Options},
1312 Change, VisitEntry,
1413 },
14+ read,
1515 };
1616
1717 /// 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::{ · 6 unmodified lines
2424 /// Note that this isn't technically quite what this function does as this also provides some additional information,
2525 /// like whether a file has conflicts, and files that were added with `git add` are shown as a special
2626 /// changes despite not technically requiring a change to the index since `git add` already added the file to the index.
27−pub fn status<'index, T, Find, E>(
27+pub fn index_as_worktree<'index, T, Find, E>(
2828 index: &'index mut gix_index::State,
2929 worktree: &Path,
3030 collector: &mut impl VisitEntry<'index, ContentChange = T>,
gix-status/src/index_as_worktree/mod.rsrenamed from gix-worktree/src/status/mod.rs+0−0

File renamed without changes.

gix-status/src/index_as_worktree/recorder.rsrenamed from gix-worktree/src/status/recorder.rs+1−1
@@ -1,7 +1,7 @@
11 use bstr::BStr;
22 use gix_index as index;
33
4−use crate::status::{Change, VisitEntry};
4+use crate::index_as_worktree::{Change, VisitEntry};
55
66 /// Convenience implementation of [`VisitEntry`] that collects all non-trivial changes into a `Vec`.
77 #[derive(Debug, Default)]
gix-status/src/index_as_worktree/types.rsrenamed from gix-worktree/src/status/types.rs+2−2
@@ -1,6 +1,6 @@
11 use bstr::BStr;
22
3−/// The error returned by [`status()`][crate::status()].
3+/// The error returned by [`status()`](crate::index_as_worktree()).
44 #[derive(Debug, thiserror::Error)]
55 #[allow(missing_docs)]
66 pub enum Error {
@@ -40,7 +40,7 @@ pub enum Change<T = ()> { · 33 unmodified lines
4040 /// Indicates that one of the stat changes was an executable bit change
4141 /// which is a significant change itself.
4242 executable_bit_changed: bool,
43− /// The output of the [`CompareBlobs`][crate::status::content::CompareBlobs] run on this entry.
43+ /// The output of the [`CompareBlobs`](crate::index_as_worktree::content::CompareBlobs) run on this entry.
4444 /// If there is no content change and only the executable bit
4545 /// changed than this is `None`.
4646 content_change: Option<T>,
gix-status/src/lib.rs+15−0
@@ -0,0 +1,15 @@
1+//! This crate includes the various diffs `git` can do between different representations
2+//! of the repository state, like comparisons between…
3+//!
4+//! * index and working tree
5+//! * index and tree
6+//! * find untracked files
7+//!
8+//! While also being able to check check if the working tree is dirty, quickly.
9+#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
10+
11+///
12+pub mod read;
13+
14+pub mod index_as_worktree;
15+pub use index_as_worktree::function::index_as_worktree;
gix-status/src/read.rsrenamed from gix-worktree/src/read.rs+1−2
@@ -10,7 +10,6 @@ use std::{ · 9 unmodified lines
1010 };
1111
1212 use gix_object::Blob;
13−use gix_path as path;
1413
1514 // TODO: tests
1615
@@ -49,7 +48,7 @@ pub fn data_to_buf_with_meta<'a>( · 32 unmodified lines
4948 if is_symlink && capabilities.symlink {
5049 // conversion to bstr can never fail because symlinks are only used
5150 // on unix (by git) so no reason to use the try version here
52− let symlink_path = path::into_bstr(read_link(path)?);
51+ let symlink_path = gix_path::into_bstr(read_link(path)?);
5352 buf.extend_from_slice(&symlink_path);
5453 // TODO: there is no reason this should be a clone
5554 // std isn't great about allowing users to avoid allocations but we could
gix-status/tests/fixtures/generated-archives/.gitignore+2−0
@@ -0,0 +1,2 @@
1+status_unchanged.tar.xz
2+status_changed.tar.xz
gix-status/tests/fixtures/generated-archives/racy_git.tar.xz+3−0
@@ -0,0 +1,3 @@
1+version https://git-lfs.github.com/spec/v1
2+oid sha256:c78c306d8a19ce7f09a4cdf284e761d9c7766a3491bfb83751b9e6f6bc8fc1c9
3+size 9812
gix-status/tests/fixtures/generated-archives/status_conflict.tar.xz+3−0
@@ -0,0 +1,3 @@
1+version https://git-lfs.github.com/spec/v1
2+oid sha256:b64431478ff4ee4613d2e1fe0766b4da8aeac8f4dee2b42726efb6d2e87bc830
3+size 11012
gix-status/tests/fixtures/generated-archives/status_intent_to_add.tar.xz+3−0
@@ -0,0 +1,3 @@
1+version https://git-lfs.github.com/spec/v1
2+oid sha256:d8fa2e8085d464945eade89cfa9dadb89345c584b1d72a535d464859f02950a7
3+size 9280
gix-status/tests/fixtures/generated-archives/status_removed.tar.xz+3−0
@@ -0,0 +1,3 @@
1+version https://git-lfs.github.com/spec/v1
2+oid sha256:cbc72bb3b08e421928d4402b49100a4ac144b4cdcc84ab70e6b721ec5ce4546c
3+size 10568
gix-status/tests/fixtures/racy_git.shrenamed from gix-worktree/tests/fixtures/racy_git.sh+0−0

File renamed without changes.

gix-status/tests/fixtures/status_changed.shrenamed from gix-worktree/tests/fixtures/status_changed.sh+0−0

File renamed without changes.

gix-status/tests/fixtures/status_conflict.shrenamed from gix-worktree/tests/fixtures/status_conflict.sh+0−0

File renamed without changes.

gix-status/tests/fixtures/status_intent_to_add.shrenamed from gix-worktree/tests/fixtures/status_intent_to_add.sh+0−0

File renamed without changes.

gix-status/tests/fixtures/status_removed.shrenamed from gix-worktree/tests/fixtures/status_removed.sh+0−0

File renamed without changes.

gix-status/tests/fixtures/status_unchanged.shrenamed from gix-worktree/tests/fixtures/status_unchanged.sh+0−0

File renamed without changes.

gix-status/tests/status-multi-threaded.rs+4−0
@@ -0,0 +1,4 @@
1+#[cfg(feature = "internal-testing-gix-features-parallel")]
2+mod status;
3+#[cfg(feature = "internal-testing-gix-features-parallel")]
4+use status::*;
gix-status/tests/status-single-threaded.rs+4−0
@@ -0,0 +1,4 @@
1+#[cfg(not(feature = "internal-testing-gix-features-parallel"))]
2+mod status;
3+#[cfg(not(feature = "internal-testing-gix-features-parallel"))]
4+use status::*;
gix-status/tests/status/index_as_worktree.rsrenamed from gix-worktree/tests/worktree/status.rs+6−6
@@ -7,9 +7,9 @@ use bstr::BStr; · 6 unmodified lines
77 use filetime::{set_file_mtime, FileTime};
88 use gix_index as index;
99 use gix_index::Entry;
10−use gix_worktree::{
11− status,
12− status::{
10+use gix_status::{
11+ index_as_worktree,
12+ index_as_worktree::{
1313 content::{CompareBlobs, FastEq, ReadDataOnce},
1414 Change, Options, Recorder,
1515 },
@@ -33,7 +33,7 @@ fn fixture(name: &str, expected_status: &[(&BStr, Option<Change>, bool)]) { · 17 unmodified lines
3333 let git_dir = worktree.join(".git");
3434 let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default()).unwrap();
3535 let mut recorder = Recorder::default();
36− status(
36+ index_as_worktree(
3737 &mut index,
3838 &worktree,
3939 &mut recorder,
@@ -172,7 +172,7 @@ fn racy_git() { · 132 unmodified lines
172172
173173 let count = Arc::new(AtomicUsize::new(0));
174174 let counter = CountCalls(count.clone(), FastEq);
175− status(
175+ index_as_worktree(
176176 &mut index,
177177 worktree,
178178 &mut recorder,
@@ -193,7 +193,7 @@ fn racy_git() { · 14 unmodified lines
193193 // and cause proper output.
194194 index.set_timestamp(FileTime::from_unix_time(timestamp as i64, 0));
195195 let mut recorder = Recorder::default();
196− status(
196+ index_as_worktree(
197197 &mut index,
198198 worktree,
199199 &mut recorder,
gix-status/tests/status/mod.rs+7−0
@@ -0,0 +1,7 @@
1+mod index_as_worktree;
2+
3+pub fn fixture_path(name: &str) -> std::path::PathBuf {
4+ let dir = gix_testtools::scripted_fixture_read_only(std::path::Path::new(name).with_extension("sh"))
5+ .expect("script works");
6+ dir
7+}
gix-worktree-state/Cargo.toml+44−0
@@ -0,0 +1,44 @@
1+[package]
2+name = "gix-worktree-state"
3+version = "0.1.0"
4+repository = "https://github.com/Byron/gitoxide"
5+license = "MIT OR Apache-2.0"
6+description = "A crate of the gitoxide project implementing setting the worktree to a particular state"
7+authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"]
8+edition = "2021"
9+include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"]
10+rust-version = "1.65"
11+
12+[lib]
13+doctest = false
14+
15+[[test]]
16+name = "multi-threaded"
17+path = "tests/state-multi-threaded.rs"
18+required-features = ["internal-testing-gix-features-parallel"]
19+
20+[features]
21+internal-testing-gix-features-parallel = ["gix-features/parallel"]
22+
23+[dependencies]
24+gix-worktree = { version = "^0.24.0", path = "../gix-worktree" }
25+gix-index = { version = "^0.22.0", path = "../gix-index" }
26+gix-fs = { version = "^0.4.1", path = "../gix-fs" }
27+gix-hash = { version = "^0.11.4", path = "../gix-hash" }
28+gix-object = { version = "^0.34.0", path = "../gix-object" }
29+gix-glob = { version = "^0.10.2", path = "../gix-glob" }
30+gix-path = { version = "^0.8.4", path = "../gix-path" }
31+gix-features = { version = "^0.32.1", path = "../gix-features" }
32+gix-filter = { version = "^0.3.0", path = "../gix-filter" }
33+
34+io-close = "0.3.7"
35+thiserror = "1.0.26"
36+bstr = { version = "1.3.0", default-features = false }
37+
38+[dev-dependencies]
39+gix-testtools = { path = "../tests/tools" }
40+gix-odb = { path = "../gix-odb" }
41+symlink = "0.1.0"
42+once_cell = "1.18.0"
43+
44+walkdir = "2.3.2"
gix-worktree-state/LICENSE-APACHE+1−0
@@ -0,0 +1 @@
1+../LICENSE-APACHE
gix-worktree-state/LICENSE-MIT+1−0
@@ -0,0 +1 @@
1+../LICENSE-MIT
gix-worktree-state/src/checkout/chunk.rsrenamed from gix-worktree/src/checkout/chunk.rs+3−2
@@ -6,7 +6,8 @@ use std::{ · 5 unmodified lines
66 use bstr::{BStr, BString};
77 use gix_hash::oid;
88
9−use crate::{checkout, checkout::entry, Cache};
9+use crate::{checkout, checkout::entry};
10+use gix_worktree::Stack;
1011
1112 mod reduce {
1213 use std::marker::PhantomData;
@@ -91,7 +92,7 @@ pub struct Outcome<'a> { · 78 unmodified lines
9192 #[derive(Clone)]
9293 pub struct Context<Find: Clone> {
9394 pub find: Find,
94− pub path_cache: Cache,
95+ pub path_cache: Stack,
9596 pub filters: gix_filter::Pipeline,
9697 pub buf: Vec<u8>,
9798 pub options: Options,
gix-worktree-state/src/checkout/entry.rsrenamed from gix-worktree/src/checkout/entry.rs+2−2
@@ -10,11 +10,11 @@ use gix_hash::oid; · 9 unmodified lines
1010 use gix_index::{entry::Stat, Entry};
1111 use io_close::Close;
1212
13−use crate::Cache;
13+use gix_worktree::Stack;
1414
1515 pub struct Context<'a, Find> {
1616 pub find: &'a mut Find,
17− pub path_cache: &'a mut Cache,
17+ pub path_cache: &'a mut Stack,
1818 pub filters: &'a mut gix_filter::Pipeline,
1919 pub buf: &'a mut Vec<u8>,
2020 }
gix-worktree-state/src/checkout/function.rsrenamed from gix-worktree/src/checkout/function.rs+4−3
@@ -3,7 +3,8 @@ use std::sync::atomic::AtomicBool; · 2 unmodified lines
33 use gix_features::{interrupt, parallel::in_parallel_with_finalize, progress::Progress};
44 use gix_hash::oid;
55
6−use crate::{cache, checkout::chunk, Cache};
6+use crate::checkout::chunk;
7+use gix_worktree::{stack, Stack};
78
89 /// Checkout the entire `index` into `dir`, and resolve objects found in index entries with `find` to write their content to their
910 /// respective path in `dir`.
@@ -65,12 +66,12 @@ where · 55 unmodified lines
6566 None,
6667 );
6768
68− let state = cache::State::for_checkout(options.overwrite_existing, std::mem::take(&mut options.attributes));
69+ let state = stack::State::for_checkout(options.overwrite_existing, std::mem::take(&mut options.attributes));
6970 let attribute_files = state.id_mappings_from_index(index, paths, case);
7071 let mut ctx = chunk::Context {
7172 buf: Vec::new(),
7273 options: (&options).into(),
73− path_cache: Cache::new(dir, state, case, Vec::with_capacity(512), attribute_files),
74+ path_cache: Stack::new(dir, state, case, Vec::with_capacity(512), attribute_files),
7475 filters: options.filters,
7576 find,
7677 };
gix-worktree-state/src/checkout/mod.rsrenamed from gix-worktree/src/checkout/mod.rs+1−1
@@ -60,7 +60,7 @@ pub struct Options { · 59 unmodified lines
6060 /// Control how stat comparisons are made when checking if a file is fresh.
6161 pub stat_options: stat::Options,
6262 /// A stack of attributes to use with the filesystem cache to use as driver for filters.
63− pub attributes: crate::cache::state::Attributes,
63+ pub attributes: gix_worktree::stack::state::Attributes,
6464 /// The filter pipeline to use for applying mandatory filters before writing to the worktree.
6565 pub filters: gix_filter::Pipeline,
6666 /// Control how long-running processes may use the 'delay' capability.
gix-worktree-state/src/lib.rs+6−0
@@ -0,0 +1,6 @@
1+//! A crate to help setting the worktree to a particular state.
2+#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
3+
4+///
5+pub mod checkout;
6+pub use checkout::function::checkout;
gix-worktree-state/tests/fixtures/generated-archives/.gitignore+5−0
@@ -0,0 +1,5 @@
1+make_ignore_and_attributes_setup.tar.xz
2+make_mixed_without_submodules.tar.xz
3+make_mixed_without_submodules_and_symlinks.tar.xz
4+make_attributes_baseline.tar.xz
5+make_dangerous_symlink.tar.xz
gix-worktree-state/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xzrenamed from gix-worktree/tests/fixtures/generated-archives/make_ignorecase_collisions.tar.xz+0−0

File renamed without changes.

gix-worktree-state/tests/fixtures/make_dangerous_symlink.shrenamed from gix-worktree/tests/fixtures/make_dangerous_symlink.sh+0−0

File renamed without changes.

gix-worktree-state/tests/fixtures/make_ignorecase_collisions.shrenamed from gix-worktree/tests/fixtures/make_ignorecase_collisions.sh+0−0

File renamed without changes.

gix-worktree-state/tests/fixtures/make_mixed_without_submodules.shrenamed from gix-worktree/tests/fixtures/make_mixed_without_submodules.sh+0−0

File renamed without changes.

gix-worktree-state/tests/fixtures/make_mixed_without_submodules_and_symlinks.shrenamed from gix-worktree/tests/fixtures/make_mixed_without_submodules_and_symlinks.sh+0−0

File renamed without changes.

gix-worktree-state/tests/state-multi-threaded.rs+4−0
@@ -0,0 +1,4 @@
1+#[cfg(feature = "internal-testing-gix-features-parallel")]
2+mod state;
3+#[cfg(feature = "internal-testing-gix-features-parallel")]
4+use state::*;
gix-worktree-state/tests/state-single-threaded.rs+4−0
@@ -0,0 +1,4 @@
1+#[cfg(not(feature = "internal-testing-gix-features-parallel"))]
2+mod state;
3+#[cfg(not(feature = "internal-testing-gix-features-parallel"))]
4+use state::*;
gix-worktree-state/tests/state/checkout.rsrenamed from gix-worktree/tests/worktree/checkout.rs+10−10
@@ -10,9 +10,9 @@ use std::{ · 9 unmodified lines
1010 use gix_features::progress;
1111 use gix_object::bstr::ByteSlice;
1212 use gix_odb::FindExt;
13−use gix_worktree::checkout::Collision;
13+use gix_testtools::tempfile::TempDir;
14+use gix_worktree_state::checkout::Collision;
1415 use once_cell::sync::Lazy;
15−use tempfile::TempDir;
1616
1717 use crate::fixture_path;
1818
@@ -454,26 +454,26 @@ pub fn dir_structure<P: AsRef<std::path::Path>>(path: P) -> Vec<std::path::PathB · 435 unmodified lines
454454 }
455455
456456 fn checkout_index_in_tmp_dir(
457− opts: gix_worktree::checkout::Options,
457+ opts: gix_worktree_state::checkout::Options,
458458 name: &str,
459−) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree::checkout::Outcome)> {
459+) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree_state::checkout::Outcome)> {
460460 checkout_index_in_tmp_dir_opts(opts, name, |_d| true, |_| Ok(()))
461461 }
462462
463463 fn checkout_index_in_tmp_dir_opts(
464− opts: gix_worktree::checkout::Options,
464+ opts: gix_worktree_state::checkout::Options,
465465 name: &str,
466466 mut allow_return_object: impl FnMut(&gix_hash::oid) -> bool + Send + Clone,
467467 prep_dest: impl Fn(&Path) -> std::io::Result<()>,
468−) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree::checkout::Outcome)> {
468+) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree_state::checkout::Outcome)> {
469469 let source_tree = fixture_path(name);
470470 let git_dir = source_tree.join(".git");
471471 let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?;
472472 let odb = gix_odb::at(git_dir.join("objects"))?.into_inner().into_arc()?;
473− let destination = tempfile::tempdir_in(std::env::current_dir()?)?;
473+ let destination = gix_testtools::tempfile::tempdir_in(std::env::current_dir()?)?;
474474 prep_dest(destination.path()).expect("preparation must succeed");
475475
476− let outcome = gix_worktree::checkout(
476+ let outcome = gix_worktree_state::checkout(
477477 &mut index,
478478 destination.path(),
479479 move |oid, buf| {
@@ -501,8 +501,8 @@ fn probe_gitoxide_dir() -> crate::Result<gix_fs::Capabilities> { · 21 unmodified lines
501501 ))
502502 }
503503
504−fn opts_from_probe() -> gix_worktree::checkout::Options {
505− gix_worktree::checkout::Options {
504+fn opts_from_probe() -> gix_worktree_state::checkout::Options {
505+ gix_worktree_state::checkout::Options {
506506 fs: probe_gitoxide_dir().unwrap(),
507507 destination_is_initially_empty: true,
508508 thread_limit: gix_features::parallel::num_threads(None).into(),
gix-worktree-state/tests/state/mod.rs+10−0
@@ -0,0 +1,10 @@
1+mod checkout;
2+
3+use std::path::{Path, PathBuf};
4+
5+pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
6+
7+pub fn fixture_path(name: &str) -> PathBuf {
8+ let dir = gix_testtools::scripted_fixture_read_only(Path::new(name).with_extension("sh")).expect("script works");
9+ dir
10+}
gix-worktree-stream/tests/stream.rs+5−5
@@ -15,7 +15,7 @@ mod from_tree { · 14 unmodified lines
1515 use gix_object::{bstr::ByteSlice, tree::EntryMode};
1616 use gix_odb::FindExt;
1717 use gix_testtools::once_cell::sync::Lazy;
18− use gix_worktree::cache::state::attributes::Source;
18+ use gix_worktree::stack::state::attributes::Source;
1919
2020 use crate::hex_to_id;
2121
@@ -231,7 +231,7 @@ mod from_tree { · 209 unmodified lines
231231 Ok(())
232232 }
233233
234− fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Cache)> {
234+ fn basic() -> gix_testtools::Result<(PathBuf, gix_hash::ObjectId, gix_odb::HandleArc, gix_worktree::Stack)> {
235235 let dir = gix_testtools::scripted_fixture_read_only("basic.sh")?;
236236
237237 let head = {
@@ -242,14 +242,14 @@ mod from_tree { · 4 unmodified lines
242242
243243 let mut collection = Default::default();
244244 let mut buf = Default::default();
245− let attributes = gix_worktree::cache::state::Attributes::new(
245+ let attributes = gix_worktree::stack::state::Attributes::new(
246246 gix_attributes::Search::new_globals(None::<PathBuf>, &mut buf, &mut collection)?,
247247 None,
248248 Source::WorktreeThenIdMapping,
249249 collection,
250250 );
251− let state = gix_worktree::cache::State::AttributesStack(attributes);
252− let cache = gix_worktree::Cache::new(&dir, state, Case::Sensitive, Default::default(), Default::default());
251+ let state = gix_worktree::stack::State::AttributesStack(attributes);
252+ let cache = gix_worktree::Stack::new(&dir, state, Case::Sensitive, Default::default(), Default::default());
253253 Ok((dir, head, odb.into_arc()?, cache))
254254 }
255255
gix-worktree/Cargo.toml+1−9
@@ -3,7 +3,7 @@ name = "gix-worktree" · 2 unmodified lines
33 version = "0.24.0"
44 repository = "https://github.com/Byron/gitoxide"
55 license = "MIT OR Apache-2.0"
6−description = "A crate of the gitoxide project dedicated implementing everything around working trees and git excludes"
6+description = "A crate of the gitoxide project for shared worktree related types and utilities."
77 authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"]
88 edition = "2021"
99 include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"]
@@ -33,25 +33,17 @@ gix-path = { version = "^0.8.4", path = "../gix-path" } · 23 unmodified lines
3333 gix-attributes = { version = "^0.16.0", path = "../gix-attributes" }
3434 gix-ignore = { version = "^0.5.1", path = "../gix-ignore" }
3535 gix-features = { version = "^0.32.1", path = "../gix-features" }
36−gix-filter = { version = "^0.3.0", path = "../gix-filter" }
3736
3837 serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
3938
40−thiserror = "1.0.26"
41−filetime = "0.2.15"
4239 bstr = { version = "1.3.0", default-features = false }
4340
4441 document-features = { version = "0.2.0", optional = true }
45−io-close = "0.3.7"
4642
4743 [dev-dependencies]
4844 gix-testtools = { path = "../tests/tools" }
4945 gix-odb = { path = "../gix-odb" }
5046 symlink = "0.1.0"
51−once_cell = "1.18.0"
52−
53−walkdir = "2.3.2"
54−tempfile = "3.2.0"
5547
5648 [package.metadata.docs.rs]
5749 features = ["document-features", "serde"]
gix-worktree/src/lib.rs+5−14
@@ -1,4 +1,4 @@
1−//! A crate with all index-centric functionality that is interacting with a worktree.
1+//! A crate with utility types for use by other crates that implement specifics.
22 //!
33 //! Unless specified differently, all operations need an index file (e.g. `.git/index`) as driver.
44 //!
@@ -11,9 +11,6 @@ · 6 unmodified lines
1111 #![deny(missing_docs, rust_2018_idioms, unsafe_code)]
1212 use bstr::BString;
1313
14−///
15−pub mod read;
16−
1714 /// A cache for efficiently executing operations on directories and files which are encountered in sorted order.
1815 /// That way, these operations can be re-used for subsequent invocations in the same directory.
1916 ///
@@ -35,26 +32,20 @@ pub mod read; · 15 unmodified lines
3532 ///
3633 /// The caching is only useful if consecutive calls to create a directory are using a sorted list of entries.
3734 #[derive(Clone)]
38−pub struct Cache {
35+pub struct Stack {
3936 stack: gix_fs::Stack,
4037 /// tells us what to do as we change paths.
41− state: cache::State,
38+ state: stack::State,
4239 /// A buffer used when reading attribute or ignore files or their respective objects from the object database.
4340 buf: Vec<u8>,
4441 /// If case folding should happen when looking up attributes or exclusions.
4542 case: gix_glob::pattern::Case,
4643 /// A lookup table for object ids to read from in some situations when looking up attributes or exclusions.
4744 id_mappings: Vec<PathIdMapping>,
48− statistics: cache::Statistics,
45+ statistics: stack::Statistics,
4946 }
5047
5148 pub(crate) type PathIdMapping = (BString, gix_hash::ObjectId);
5249
5350 ///
54−pub mod cache;
55−///
56−pub mod checkout;
57−pub use checkout::function::checkout;
58−
59−pub mod status;
60−pub use status::function::status;
51+pub mod stack;
gix-worktree/src/stack/delegate.rsrenamed from gix-worktree/src/cache/delegate.rs+1−1
@@ -1,6 +1,6 @@
11 use bstr::{BStr, ByteSlice};
22
3−use crate::{cache::State, PathIdMapping};
3+use crate::{stack::State, PathIdMapping};
44
55 /// Various aggregate numbers related to the stack delegate itself.
66 #[derive(Default, Clone, Copy, Debug)]
gix-worktree/src/stack/mod.rsrenamed from gix-worktree/src/cache/mod.rs+10−10
@@ -4,10 +4,10 @@ use std::path::{Path, PathBuf}; · 3 unmodified lines
44 use bstr::{BStr, ByteSlice};
55 use gix_hash::oid;
66
7−use super::Cache;
7+use super::Stack;
88 use crate::PathIdMapping;
99
10−/// Various aggregate numbers collected from when the corresponding [`Cache`] was instantiated.
10+/// Various aggregate numbers collected from when the corresponding [`Stack`] was instantiated.
1111 #[derive(Default, Clone, Copy, Debug)]
1212 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1313 pub struct Statistics {
@@ -45,12 +45,12 @@ pub enum State { · 31 unmodified lines
4545
4646 #[must_use]
4747 pub struct Platform<'a> {
48− parent: &'a Cache,
48+ parent: &'a Stack,
4949 is_dir: Option<bool>,
5050 }
5151
5252 /// Initialization
53−impl Cache {
53+impl Stack {
5454 /// Create a new instance with `worktree_root` being the base for all future paths we match.
5555 /// `state` defines the capabilities of the cache.
5656 /// The `case` configures attribute and exclusion case sensitivity at *query time*, which should match the case that
@@ -64,7 +64,7 @@ impl Cache { · 7 unmodified lines
6464 id_mappings: Vec<PathIdMapping>,
6565 ) -> Self {
6666 let root = worktree_root.into();
67− Cache {
67+ Stack {
6868 stack: gix_fs::Stack::new(root),
6969 state,
7070 case,
@@ -76,12 +76,12 @@ impl Cache { · 5 unmodified lines
7676 }
7777
7878 /// Entry points for attribute query
79−impl Cache {
79+impl Stack {
8080 /// Append the `relative` path to the root directory of the cache and efficiently create leading directories, while assuring that no
8181 /// symlinks are in that path.
8282 /// Unless `is_dir` is known with `Some(…)`, then `relative` points to a directory itself in which case the entire resulting
8383 /// path is created as directory. If it's not known it is assumed to be a file.
84− /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()], with mappnigs
84+ /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()], with mappnigs
8585 ///
8686 /// Provide access to cached information for that `relative` path via the returned platform.
8787 pub fn at_path<Find, E>(
@@ -110,7 +110,7 @@ impl Cache { · 22 unmodified lines
110110
111111 /// Obtain a platform for lookups from a repo-`relative` path, typically obtained from an index entry. `is_dir` should reflect
112112 /// whether it's a directory or not, or left at `None` if unknown.
113− /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()].
113+ /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()].
114114 /// All effects are similar to [`at_path()`][Self::at_path()].
115115 ///
116116 /// If `relative` ends with `/` and `is_dir` is `None`, it is automatically assumed to be a directory.
@@ -140,7 +140,7 @@ impl Cache { · 23 unmodified lines
140140 }
141141
142142 /// Mutation
143−impl Cache {
143+impl Stack {
144144 /// Reset the statistics after returning them.
145145 pub fn take_statistics(&mut self) -> Statistics {
146146 std::mem::take(&mut self.statistics)
@@ -159,7 +159,7 @@ impl Cache { · 12 unmodified lines
159159 }
160160
161161 /// Access
162−impl Cache {
162+impl Stack {
163163 /// Return the statistics we gathered thus far.
164164 pub fn statistics(&self) -> &Statistics {
165165 &self.statistics
gix-worktree/src/stack/platform.rsrenamed from gix-worktree/src/cache/platform.rs+1−1
@@ -2,7 +2,7 @@ use std::path::Path; · 1 unmodified line
22
33 use bstr::ByteSlice;
44
5−use crate::cache::Platform;
5+use crate::stack::Platform;
66
77 /// Access
88 impl<'a> Platform<'a> {
gix-worktree/src/stack/state/attributes.rsrenamed from gix-worktree/src/cache/state/attributes.rs+5−5
@@ -4,8 +4,8 @@ use bstr::{BStr, ByteSlice}; · 3 unmodified lines
44 use gix_glob::pattern::Case;
55
66 use crate::{
7− cache::state::{AttributeMatchGroup, Attributes},
8− Cache, PathIdMapping,
7+ stack::state::{AttributeMatchGroup, Attributes},
8+ PathIdMapping, Stack,
99 };
1010
1111 /// Various aggregate numbers related [`Attributes`].
@@ -23,7 +23,7 @@ pub struct Statistics { · 11 unmodified lines
2323 /// Decide where to read `.gitattributes` files from.
2424 ///
2525 /// To Retrieve attribute files from id mappings, see
26−/// [State::id_mappings_from_index()][crate::cache::State::id_mappings_from_index()].
26+/// [State::id_mappings_from_index()][crate::stack::State::id_mappings_from_index()].
2727 ///
2828 /// These mappings are typically produced from an index.
2929 /// 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 { · 170 unmodified lines
200200 }
201201
202202 /// Attribute matching specific methods
203−impl Cache {
203+impl Stack {
204204 /// Creates a new container to store match outcomes for all attribute matches.
205205 ///
206206 /// ### Panics
@@ -230,7 +230,7 @@ impl Cache { · 23 unmodified lines
230230 }
231231
232232 /// Return the metadata collection that enables initializing attribute match outcomes as done in
233− /// [`attribute_matches()`][Cache::attribute_matches()] or [`selected_attribute_matches()`][Cache::selected_attribute_matches()]
233+ /// [`attribute_matches()`][Stack::attribute_matches()] or [`selected_attribute_matches()`][Stack::selected_attribute_matches()]
234234 ///
235235 /// ### Panics
236236 ///
gix-worktree/src/stack/state/ignore.rsrenamed from gix-worktree/src/cache/state/ignore.rs+2−2
@@ -4,7 +4,7 @@ use bstr::{BStr, ByteSlice}; · 3 unmodified lines
44 use gix_glob::pattern::Case;
55
66 use crate::{
7− cache::state::{Ignore, IgnoreMatchGroup},
7+ stack::state::{Ignore, IgnoreMatchGroup},
88 PathIdMapping,
99 };
1010
@@ -12,7 +12,7 @@ use crate::{ · 1 unmodified line
1212 #[derive(Default, Debug, Clone, Copy)]
1313 pub enum Source {
1414 /// Retrieve ignore files from id mappings, see
15− /// [State::id_mappings_from_index()][crate::cache::State::id_mappings_from_index()].
15+ /// [State::id_mappings_from_index()][crate::stack::State::id_mappings_from_index()].
1616 ///
1717 /// These mappings are typically produced from an index.
1818 /// If a tree should be the source, build an attribute list from a tree instead, or convert a tree to an index.
gix-worktree/src/stack/state/mod.rsrenamed from gix-worktree/src/cache/state/mod.rs+1−1
@@ -3,7 +3,7 @@ use std::path::PathBuf; · 2 unmodified lines
33 use bstr::{BString, ByteSlice};
44 use gix_glob::pattern::Case;
55
6−use crate::{cache::State, PathIdMapping};
6+use crate::{stack::State, PathIdMapping};
77
88 type AttributeMatchGroup = gix_attributes::Search;
99 type IgnoreMatchGroup = gix_ignore::Search;
gix-worktree/src/untracked.rs+0−1
@@ -1 +0,0 @@
1−// TODO: untracked file detection, needs fs::Cache
gix-worktree/tests/fixtures/generated-archives/.gitignore+0−5
@@ -1,7 +1,2 @@
11 make_ignore_and_attributes_setup.tar.xz
2−make_mixed_without_submodules.tar.xz
3−make_mixed_without_submodules_and_symlinks.tar.xz
42 make_attributes_baseline.tar.xz
5−make_dangerous_symlink.tar.xz
6−status_unchanged.tar.xz
7−status_changed.tar.xz
gix-worktree/tests/fixtures/generated-archives/make_special_exclude_case.tar.xz+2−2
@@ -1,3 +1,3 @@
11 version https://git-lfs.github.com/spec/v1
2−oid sha256:24f605623efc49819d1b30c52fe22da8f94f2d267e8030ec9bc3b9b845801f76
3−size 9220
2+oid sha256:1804dc740055b8a5afe65a2db14f29c8ae4691896e67342a8dcb11530fd448c6
3+size 9240
gix-worktree/tests/fixtures/generated-archives/racy_git.tar.xz+0−3
@@ -1,3 +0,0 @@
1−version https://git-lfs.github.com/spec/v1
2−oid sha256:35b728a127f3b6170bac44469ff36d5ad0be2a4247a8926f1aaffb97b5973efc
3−size 1596
gix-worktree/tests/fixtures/generated-archives/status_conflict.tar.xz+0−3
@@ -1,3 +0,0 @@
1−version https://git-lfs.github.com/spec/v1
2−oid sha256:cd6d32ab7a1e372d80a617926cac2463f6620baedf74642d78fe7f8c956fd031
3−size 11036
gix-worktree/tests/fixtures/generated-archives/status_intent_to_add.tar.xz+0−3
@@ -1,3 +0,0 @@
1−version https://git-lfs.github.com/spec/v1
2−oid sha256:876670d74c01249d361aa73d83ab20d846db7c922a3ca825f778b5f9d746c401
3−size 9304
gix-worktree/tests/fixtures/generated-archives/status_removed.tar.xz+0−3
@@ -1,3 +0,0 @@
1−version https://git-lfs.github.com/spec/v1
2−oid sha256:e5fe85a65e3689e9e60598130be60761dc4ea129e04d7d5501320f7ebad1eb2b
3−size 10520
gix-worktree/tests/fixtures/make_ignore_setup.sh+0−18
@@ -1,18 +0,0 @@
1−#!/bin/bash
2−set -eu -o pipefail
3−
4−git init -q
5−
6−cat <<EOF >.git/info/exclude
7−# a sample .git/info/exclude
8−file-anywhere
9−/file-from-top
10−
11−dir-anywhere/
12−/dir-from-top
13−
14−subdir-anywhere/file
15−subdir-anywhere/dir/
16−EOF
17−
18−git commit --allow-empty -m "init"
gix-worktree/tests/worktree/mod.rs+2−10
@@ -1,17 +1,9 @@
1−mod cache;
2−mod checkout;
3−mod status;
1+use gix_hash::ObjectId;
42
5−use std::path::{Path, PathBuf};
3+mod stack;
64
7−use gix_hash::ObjectId;
85 pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
96
107 pub fn hex_to_id(hex: &str) -> ObjectId {
118 ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex")
129 }
13−
14−pub fn fixture_path(name: &str) -> PathBuf {
15− let dir = gix_testtools::scripted_fixture_read_only(Path::new(name).with_extension("sh")).expect("script works");
16− dir
17−}
gix-worktree/tests/worktree/stack/attributes.rsrenamed from gix-worktree/tests/worktree/cache/attributes.rs+4−4
@@ -1,7 +1,7 @@
11 use bstr::ByteSlice;
22 use gix_attributes::search::Outcome;
33 use gix_glob::pattern::Case;
4−use gix_worktree::cache::state;
4+use gix_worktree::stack::state;
55
66 #[test]
77 fn baseline() -> crate::Result {
@@ -19,17 +19,17 @@ fn baseline() -> crate::Result { · 11 unmodified lines
1919
2020 let mut buf = Vec::new();
2121 let mut collection = gix_attributes::search::MetadataCollection::default();
22− let state = gix_worktree::cache::State::for_checkout(
22+ let state = gix_worktree::stack::State::for_checkout(
2323 false,
2424 state::Attributes::new(
2525 gix_attributes::Search::new_globals([base.join("user.attributes")], &mut buf, &mut collection)?,
2626 Some(git_dir.join("info").join("attributes")),
27− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
27+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
2828 collection,
2929 ),
3030 );
3131
32− let mut cache = gix_worktree::Cache::new(&base, state, case, buf, vec![]);
32+ let mut cache = gix_worktree::Stack::new(&base, state, case, buf, vec![]);
3333
3434 let mut actual = cache.attribute_matches();
3535 let input = std::fs::read(base.join("baseline"))?;
gix-worktree/tests/worktree/stack/create_directory.rsrenamed from gix-worktree/tests/worktree/cache/create_directory.rs+9−9
@@ -1,7 +1,7 @@
11 use std::path::Path;
22
3−use gix_worktree::{cache, Cache};
4−use tempfile::{tempdir, TempDir};
3+use gix_testtools::tempfile::{tempdir, TempDir};
4+use gix_worktree::{stack, Stack};
55
66 #[allow(clippy::ptr_arg)]
77 fn panic_on_find<'buf>(_oid: &gix_hash::oid, _buf: &'buf mut Vec<u8>) -> std::io::Result<gix_object::BlobRef<'buf>> {
@@ -11,9 +11,9 @@ fn panic_on_find<'buf>(_oid: &gix_hash::oid, _buf: &'buf mut Vec<u8>) -> std::io · 3 unmodified lines
1111 #[test]
1212 fn root_is_assumed_to_exist_and_files_in_root_do_not_create_directory() -> crate::Result {
1313 let dir = tempdir()?;
14− let mut cache = Cache::new(
14+ let mut cache = Stack::new(
1515 dir.path().join("non-existing-root"),
16− cache::State::for_checkout(false, Default::default()),
16+ stack::State::for_checkout(false, Default::default()),
1717 Default::default(),
1818 Vec::new(),
1919 Default::default(),
@@ -68,7 +68,7 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R · 48 unmodified lines
6868 std::fs::write(tmp.path().join("file-in-dir"), [])?;
6969
7070 for dirname in &["file-in-dir", "link-to-dir"] {
71− if let cache::State::CreateDirectoryAndAttributesStack {
71+ if let stack::State::CreateDirectoryAndAttributesStack {
7272 unlink_on_collision, ..
7373 } = cache.state_mut()
7474 {
@@ -90,7 +90,7 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R · 15 unmodified lines
9090 );
9191 cache.take_statistics();
9292 for dirname in &["link-to-dir", "file-in-dir"] {
93− if let cache::State::CreateDirectoryAndAttributesStack {
93+ if let stack::State::CreateDirectoryAndAttributesStack {
9494 unlink_on_collision, ..
9595 } = cache.state_mut()
9696 {
@@ -109,11 +109,11 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R · 12 unmodified lines
109109 Ok(())
110110 }
111111
112−fn new_cache() -> (Cache, TempDir) {
112+fn new_cache() -> (Stack, TempDir) {
113113 let dir = tempdir().unwrap();
114− let cache = Cache::new(
114+ let cache = Stack::new(
115115 dir.path(),
116− cache::State::for_checkout(false, Default::default()),
116+ stack::State::for_checkout(false, Default::default()),
117117 Default::default(),
118118 Vec::new(),
119119 Default::default(),
gix-worktree/tests/worktree/stack/ignore.rsrenamed from gix-worktree/tests/worktree/cache/ignore.rs+7−7
@@ -1,7 +1,7 @@
11 use bstr::{BStr, ByteSlice};
22 use gix_glob::pattern::Case;
33 use gix_odb::FindExt;
4−use gix_worktree::{cache::state::ignore::Source, Cache};
4+use gix_worktree::{stack::state::ignore::Source, Stack};
55
66 use crate::hex_to_id;
77
@@ -37,16 +37,16 @@ fn exclude_by_dir_is_handled_just_like_git() { · 29 unmodified lines
3737
3838 let mut buf = Vec::new();
3939 let case = gix_glob::pattern::Case::Sensitive;
40− let state = gix_worktree::cache::State::for_add(
40+ let state = gix_worktree::stack::State::for_add(
4141 Default::default(),
42− gix_worktree::cache::state::Ignore::new(
42+ gix_worktree::stack::state::Ignore::new(
4343 Default::default(),
4444 gix_ignore::Search::from_git_dir(&git_dir, None, &mut buf).unwrap(),
4545 None,
4646 Source::WorktreeThenIdMappingIfNotSkipped,
4747 ),
4848 );
49− let mut cache = Cache::new(&dir, state, case, buf, Default::default());
49+ let mut cache = Stack::new(&dir, state, case, buf, Default::default());
5050 let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline")).unwrap();
5151 let expectations = IgnoreExpectations {
5252 lines: baseline.lines(),
@@ -95,9 +95,9 @@ fn check_against_baseline() -> crate::Result { · 42 unmodified lines
9595 };
9696 let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?;
9797 let odb = gix_odb::at(git_dir.join("objects"))?;
98− let state = gix_worktree::cache::State::for_add(
98+ let state = gix_worktree::stack::State::for_add(
9999 Default::default(),
100− gix_worktree::cache::state::Ignore::new(
100+ gix_worktree::stack::state::Ignore::new(
101101 gix_ignore::Search::from_overrides(vec!["!force-include"]),
102102 gix_ignore::Search::from_git_dir(&git_dir, Some(user_exclude_path), &mut buf)?,
103103 None,
@@ -113,7 +113,7 @@ fn check_against_baseline() -> crate::Result { · 9 unmodified lines
113113 hex_to_id("5c7e0ed672d3d31d83a3df61f13cc8f7b22d5bfd")
114114 )]
115115 );
116− let mut cache = Cache::new(&worktree_dir, state, case, buf, attribute_files_in_index);
116+ let mut cache = Stack::new(&worktree_dir, state, case, buf, attribute_files_in_index);
117117
118118 let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
119119 let expectations = IgnoreExpectations {
gix-worktree/tests/worktree/stack/mod.rsrenamed from gix-worktree/tests/worktree/cache/mod.rs+0−0

File renamed without changes.

gix/Cargo.toml+1−0
@@ -162,6 +162,7 @@ gix-credentials = { version = "^0.17.1", path = "../gix-credentials" } · 161 unmodified lines
162162 gix-prompt = { version = "^0.5.5", path = "../gix-prompt" }
163163 gix-index = { version = "^0.22.0", path = "../gix-index" }
164164 gix-worktree = { version = "^0.24.0", path = "../gix-worktree" }
165+gix-worktree-state = { version = "^0.1.0", path = "../gix-worktree-state" }
165166 gix-hashtable = { version = "^0.2.4", path = "../gix-hashtable" }
166167 gix-commitgraph = { version = "^0.18.2", path = "../gix-commitgraph" }
167168 gix-pathspec = { version = "^0.1.0", path = "../gix-pathspec" }
gix/src/clone/checkout.rs+6−5
@@ -27,7 +27,8 @@ pub mod main_worktree { · 26 unmodified lines
2727 CheckoutOptions(#[from] crate::config::checkout_options::Error),
2828 #[error(transparent)]
2929 IndexCheckout(
30− #[from] gix_worktree::checkout::Error<gix_odb::find::existing_object::Error<gix_odb::store::find::Error>>,
30+ #[from]
31+ gix_worktree_state::checkout::Error<gix_odb::find::existing_object::Error<gix_odb::store::find::Error>>,
3132 ),
3233 #[error("Failed to reopen object database as Arc (only if thread-safety wasn't compiled in)")]
3334 OpenArcOdb(#[from] std::io::Error),
@@ -68,7 +69,7 @@ pub mod main_worktree { · 34 unmodified lines
6869 &mut self,
6970 mut progress: impl crate::Progress,
7071 should_interrupt: &AtomicBool,
71− ) -> Result<(Repository, gix_worktree::checkout::Outcome), Error> {
72+ ) -> Result<(Repository, gix_worktree_state::checkout::Outcome), Error> {
7273 let _span = gix_trace::coarse!("gix::clone::PrepareCheckout::main_worktree()");
7374 let repo = self
7475 .repo
@@ -82,7 +83,7 @@ pub mod main_worktree { · 7 unmodified lines
8283 None => {
8384 return Ok((
8485 self.repo.take().expect("still present"),
85− gix_worktree::checkout::Outcome::default(),
86+ gix_worktree_state::checkout::Outcome::default(),
8687 ))
8788 }
8889 };
@@ -95,7 +96,7 @@ pub mod main_worktree { · 6 unmodified lines
9596
9697 let mut opts = repo
9798 .config
98− .checkout_options(repo, gix_worktree::cache::state::attributes::Source::IdMapping)?;
99+ .checkout_options(repo, gix_worktree::stack::state::attributes::Source::IdMapping)?;
99100 opts.destination_is_initially_empty = true;
100101
101102 let mut files = progress.add_child_with_id("checkout", ProgressId::CheckoutFiles.into());
@@ -105,7 +106,7 @@ pub mod main_worktree { · 3 unmodified lines
105106 bytes.init(None, crate::progress::bytes());
106107
107108 let start = std::time::Instant::now();
108− let outcome = gix_worktree::checkout(
109+ let outcome = gix_worktree_state::checkout(
109110 &mut index,
110111 workdir,
111112 {
gix/src/config/cache/access.rs+9−9
@@ -160,8 +160,8 @@ impl Cache { · 159 unmodified lines
160160 pub(crate) fn checkout_options(
161161 &self,
162162 repo: &Repository,
163− attributes_source: gix_worktree::cache::state::attributes::Source,
164− ) -> Result<gix_worktree::checkout::Options, checkout_options::Error> {
163+ attributes_source: gix_worktree::stack::state::attributes::Source,
164+ ) -> Result<gix_worktree_state::checkout::Options, checkout_options::Error> {
165165 let git_dir = repo.git_dir();
166166 let thread_limit = self.apply_leniency(
167167 self.resolved
@@ -189,7 +189,7 @@ impl Cache { · 21 unmodified lines
189189 } else {
190190 gix_filter::driver::apply::Delay::Forbid
191191 };
192− Ok(gix_worktree::checkout::Options {
192+ Ok(gix_worktree_state::checkout::Options {
193193 filter_process_delay,
194194 filters,
195195 attributes: self
@@ -219,14 +219,14 @@ impl Cache { · 23 unmodified lines
219219 &self,
220220 git_dir: &std::path::Path,
221221 overrides: Option<gix_ignore::Search>,
222− source: gix_worktree::cache::state::ignore::Source,
222+ source: gix_worktree::stack::state::ignore::Source,
223223 buf: &mut Vec<u8>,
224− ) -> Result<gix_worktree::cache::state::Ignore, config::exclude_stack::Error> {
224+ ) -> Result<gix_worktree::stack::state::Ignore, config::exclude_stack::Error> {
225225 let excludes_file = match self.excludes_file().transpose()? {
226226 Some(user_path) => Some(user_path),
227227 None => self.xdg_config_path("ignore")?,
228228 };
229− Ok(gix_worktree::cache::state::Ignore::new(
229+ Ok(gix_worktree::stack::state::Ignore::new(
230230 overrides.unwrap_or_default(),
231231 gix_ignore::Search::from_git_dir(git_dir, excludes_file, buf)?,
232232 None,
@@ -237,9 +237,9 @@ impl Cache { · 4 unmodified lines
237237 pub(crate) fn assemble_attribute_globals(
238238 &self,
239239 git_dir: &std::path::Path,
240− source: gix_worktree::cache::state::attributes::Source,
240+ source: gix_worktree::stack::state::attributes::Source,
241241 attributes: crate::open::permissions::Attributes,
242− ) -> Result<(gix_worktree::cache::state::Attributes, Vec<u8>), config::attribute_stack::Error> {
242+ ) -> Result<(gix_worktree::stack::state::Attributes, Vec<u8>), config::attribute_stack::Error> {
243243 let configured_or_user_attributes = match self
244244 .trusted_file_path("core", None, Core::ATTRIBUTES_FILE.name)
245245 .transpose()?
@@ -265,7 +265,7 @@ impl Cache { · 19 unmodified lines
265265 let info_attributes_path = git_dir.join("info").join("attributes");
266266 let mut buf = Vec::new();
267267 let mut collection = gix_attributes::search::MetadataCollection::default();
268− let state = gix_worktree::cache::state::Attributes::new(
268+ let state = gix_worktree::stack::state::Attributes::new(
269269 gix_attributes::Search::new_globals(attribute_files, &mut buf, &mut collection)?,
270270 Some(info_attributes_path),
271271 source,
gix/src/filter.rs+3−3
@@ -67,7 +67,7 @@ pub mod pipeline { · 66 unmodified lines
6767 #[derive(Clone)]
6868 pub struct Pipeline<'repo> {
6969 inner: gix_filter::Pipeline,
70− cache: gix_worktree::Cache,
70+ cache: gix_worktree::Stack,
7171 repo: &'repo Repository,
7272 }
7373
@@ -110,7 +110,7 @@ impl<'repo> Pipeline<'repo> { · 36 unmodified lines
110110
111111 /// Create a new instance by extracting all necessary information and configuration from a `repo` along with `cache` for accessing
112112 /// attributes. The `index` is used for some filters which may access it under very specific circumstances.
113− pub fn new(repo: &'repo Repository, cache: gix_worktree::Cache) -> Result<Self, pipeline::options::Error> {
113+ pub fn new(repo: &'repo Repository, cache: gix_worktree::Stack) -> Result<Self, pipeline::options::Error> {
114114 let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), Self::options(repo)?);
115115 Ok(Pipeline {
116116 inner: pipeline,
@@ -120,7 +120,7 @@ impl<'repo> Pipeline<'repo> { · 3 unmodified lines
120120 }
121121
122122 /// Detach the repository and obtain the individual functional parts.
123− pub fn into_parts(self) -> (gix_filter::Pipeline, gix_worktree::Cache) {
123+ pub fn into_parts(self) -> (gix_filter::Pipeline, gix_worktree::Stack) {
124124 (self.inner, self.cache)
125125 }
126126 }
gix/src/pathspec.rs+4−4
@@ -43,7 +43,7 @@ impl<'repo> Pathspec<'repo> { · 42 unmodified lines
4343 repo: &'repo Repository,
4444 patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
4545 inherit_ignore_case: bool,
46− make_attributes: impl FnOnce() -> Result<gix_worktree::Cache, Box<dyn std::error::Error + Send + Sync + 'static>>,
46+ make_attributes: impl FnOnce() -> Result<gix_worktree::Stack, Box<dyn std::error::Error + Send + Sync + 'static>>,
4747 ) -> Result<Self, init::Error> {
4848 let mut defaults = repo.pathspec_defaults()?;
4949 if inherit_ignore_case && repo.config.fs_capabilities()?.ignore_case {
@@ -67,9 +67,9 @@ impl<'repo> Pathspec<'repo> { · 17 unmodified lines
6767 Ok(Self { repo, search, cache })
6868 }
6969 /// Turn ourselves into the functional parts for direct usage.
70− /// Note that the [`cache`](gix_worktree::Cache) is only set if one of the [`search` patterns](Search)
70+ /// Note that the [`cache`](gix_worktree::Stack) is only set if one of the [`search` patterns](Search)
7171 /// is specifying attributes to match for.
72− pub fn into_parts(self) -> (Search, Option<gix_worktree::Cache>) {
72+ pub fn into_parts(self) -> (Search, Option<gix_worktree::Stack>) {
7373 (self.search, self.cache)
7474 }
7575 }
@@ -77,7 +77,7 @@ impl<'repo> Pathspec<'repo> { · 1 unmodified line
7777 /// Access
7878 impl<'repo> Pathspec<'repo> {
7979 /// Return the attributes cache which is used when matching attributes in pathspecs, or `None` if none of the pathspecs require that.
80− pub fn attributes(&self) -> Option<&gix_worktree::Cache> {
80+ pub fn attributes(&self) -> Option<&gix_worktree::Stack> {
8181 self.cache.as_ref()
8282 }
8383
gix/src/repository/attributes.rs+13−13
@@ -29,10 +29,10 @@ impl Repository { · 28 unmodified lines
2929 pub fn attributes(
3030 &self,
3131 index: &gix_index::State,
32− attributes_source: gix_worktree::cache::state::attributes::Source,
33− ignore_source: gix_worktree::cache::state::ignore::Source,
32+ attributes_source: gix_worktree::stack::state::attributes::Source,
33+ ignore_source: gix_worktree::stack::state::ignore::Source,
3434 exclude_overrides: Option<gix_ignore::Search>,
35− ) -> Result<gix_worktree::Cache, Error> {
35+ ) -> Result<gix_worktree::Stack, Error> {
3636 let case = if self.config.ignore_case {
3737 gix_glob::pattern::Case::Fold
3838 } else {
@@ -46,9 +46,9 @@ impl Repository { · 7 unmodified lines
4646 let ignore =
4747 self.config
4848 .assemble_exclude_globals(self.git_dir(), exclude_overrides, ignore_source, &mut buf)?;
49− let state = gix_worktree::cache::State::AttributesAndIgnoreStack { attributes, ignore };
49+ let state = gix_worktree::stack::State::AttributesAndIgnoreStack { attributes, ignore };
5050 let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case);
51− Ok(gix_worktree::Cache::new(
51+ Ok(gix_worktree::Stack::new(
5252 // this is alright as we don't cause mutation of that directory, it's virtual.
5353 self.work_dir().unwrap_or(self.git_dir()),
5454 state,
@@ -62,8 +62,8 @@ impl Repository { · 7 unmodified lines
6262 pub fn attributes_only(
6363 &self,
6464 index: &gix_index::State,
65− attributes_source: gix_worktree::cache::state::attributes::Source,
66− ) -> Result<gix_worktree::Cache, config::attribute_stack::Error> {
65+ attributes_source: gix_worktree::stack::state::attributes::Source,
66+ ) -> Result<gix_worktree::Stack, config::attribute_stack::Error> {
6767 let case = if self.config.ignore_case {
6868 gix_glob::pattern::Case::Fold
6969 } else {
@@ -74,9 +74,9 @@ impl Repository { · 4 unmodified lines
7474 attributes_source,
7575 self.options.permissions.attributes,
7676 )?;
77− let state = gix_worktree::cache::State::AttributesStack(attributes);
77+ let state = gix_worktree::stack::State::AttributesStack(attributes);
7878 let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case);
79− Ok(gix_worktree::Cache::new(
79+ Ok(gix_worktree::Stack::new(
8080 // this is alright as we don't cause mutation of that directory, it's virtual.
8181 self.work_dir().unwrap_or(self.git_dir()),
8282 state,
@@ -105,8 +105,8 @@ impl Repository { · 22 unmodified lines
105105 &self,
106106 index: &gix_index::State,
107107 overrides: Option<gix_ignore::Search>,
108− source: gix_worktree::cache::state::ignore::Source,
109− ) -> Result<gix_worktree::Cache, config::exclude_stack::Error> {
108+ source: gix_worktree::stack::state::ignore::Source,
109+ ) -> Result<gix_worktree::Stack, config::exclude_stack::Error> {
110110 let case = if self.config.ignore_case {
111111 gix_glob::pattern::Case::Fold
112112 } else {
@@ -116,9 +116,9 @@ impl Repository { · 3 unmodified lines
116116 let ignore = self
117117 .config
118118 .assemble_exclude_globals(self.git_dir(), overrides, source, &mut buf)?;
119− let state = gix_worktree::cache::State::IgnoreStack(ignore);
119+ let state = gix_worktree::stack::State::IgnoreStack(ignore);
120120 let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case);
121− Ok(gix_worktree::Cache::new(
121+ Ok(gix_worktree::Stack::new(
122122 // this is alright as we don't cause mutation of that directory, it's virtual.
123123 self.work_dir().unwrap_or(self.git_dir()),
124124 state,
gix/src/repository/filter.rs+2−2
@@ -49,13 +49,13 @@ impl Repository { · 48 unmodified lines
4949 },
5050 Ok,
5151 )?)?;
52− let cache = self.attributes_only(&index, gix_worktree::cache::state::attributes::Source::IdMapping)?;
52+ let cache = self.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?;
5353 (cache, IndexPersistedOrInMemory::InMemory(index))
5454 } else {
5555 let index = self.index()?;
5656 let cache = self.attributes_only(
5757 &index,
58− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
58+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
5959 )?;
6060 (cache, IndexPersistedOrInMemory::Persisted(index))
6161 };
gix/src/repository/pathspec.rs+1−1
@@ -17,7 +17,7 @@ impl Repository { · 16 unmodified lines
1717 Pathspec::new(self, patterns, inherit_ignore_case, || {
1818 self.attributes_only(
1919 index,
20− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
20+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
2121 )
2222 .map_err(Into::into)
2323 })
gix/src/repository/worktree.rs+1−1
@@ -74,7 +74,7 @@ impl crate::Repository { · 73 unmodified lines
7474 // TODO(perf): when loading a non-HEAD tree, we effectively traverse the tree twice. This is usually fast though, and sharing
7575 // an object cache between the copies of the ODB handles isn't trivial and needs a lock.
7676 let index = self.index_from_tree(&id)?;
77− let mut cache = self.attributes_only(&index, gix_worktree::cache::state::attributes::Source::IdMapping)?;
77+ let mut cache = self.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?;
7878 let pipeline =
7979 gix_filter::Pipeline::new(cache.attributes_collection(), crate::filter::Pipeline::options(self)?);
8080 let objects = self.objects.clone().into_arc().expect("TBD error handling");
gix/src/types.rs+1−1
@@ -202,7 +202,7 @@ pub struct Remote<'repo> { · 201 unmodified lines
202202 pub struct Pathspec<'repo> {
203203 pub(crate) repo: &'repo Repository,
204204 /// The cache to power attribute access. It's only initialized if we have a pattern with attributes.
205− pub(crate) cache: Option<gix_worktree::Cache>,
205+ pub(crate) cache: Option<gix_worktree::Stack>,
206206 /// The prepared search to use for checking matches.
207207 pub(crate) search: gix_pathspec::Search,
208208 }
gix/src/worktree/mod.rs+8−7
@@ -3,6 +3,7 @@ use std::path::PathBuf; · 2 unmodified lines
33 #[cfg(feature = "worktree-archive")]
44 pub use gix_archive as archive;
55 pub use gix_worktree::*;
6+pub use gix_worktree_state as state;
67 #[cfg(feature = "worktree-stream")]
78 pub use gix_worktree_stream as stream;
89
@@ -120,12 +121,12 @@ pub mod excludes { · 111 unmodified lines
120121 ///
121122 /// When only excludes are desired, this is the most efficient way to obtain them. Otherwise use
122123 /// [`Worktree::attributes()`][crate::Worktree::attributes()] for accessing both attributes and excludes.
123− pub fn excludes(&self, overrides: Option<gix_ignore::Search>) -> Result<gix_worktree::Cache, Error> {
124+ pub fn excludes(&self, overrides: Option<gix_ignore::Search>) -> Result<gix_worktree::Stack, Error> {
124125 let index = self.index()?;
125126 Ok(self.parent.excludes(
126127 &index,
127128 overrides,
128− gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
129+ gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
129130 )?)
130131 }
131132 }
@@ -150,23 +151,23 @@ pub mod attributes { · 18 unmodified lines
150151 ///
151152 /// * `$XDG_CONFIG_HOME/…/ignore|attributes` if `core.excludesFile|attributesFile` is *not* set, otherwise use the configured file.
152153 /// * `$GIT_DIR/info/exclude|attributes` if present.
153− pub fn attributes(&self, overrides: Option<gix_ignore::Search>) -> Result<gix_worktree::Cache, Error> {
154+ pub fn attributes(&self, overrides: Option<gix_ignore::Search>) -> Result<gix_worktree::Stack, Error> {
154155 let index = self.index()?;
155156 Ok(self.parent.attributes(
156157 &index,
157− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
158− gix_worktree::cache::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
158+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
159+ gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
159160 overrides,
160161 )?)
161162 }
162163
163164 /// Like [attributes()][Self::attributes()], but without access to exclude/ignore information.
164− pub fn attributes_only(&self) -> Result<gix_worktree::Cache, Error> {
165+ pub fn attributes_only(&self) -> Result<gix_worktree::Stack, Error> {
165166 let index = self.index()?;
166167 self.parent
167168 .attributes_only(
168169 &index,
169− gix_worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
170+ gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
170171 )
171172 .map_err(|err| Error::CreateCache(err.into()))
172173 }
justfile+8−3
@@ -99,6 +99,7 @@ check: · 98 unmodified lines
9999 cargo check -p gix-config-value
100100 cargo check -p gix-config --all-features
101101 cargo check -p gix-config
102+ cargo check -p gix-diff --no-default-features
102103 cargo check -p gix-transport
103104 cargo check -p gix-transport --features blocking-client
104105 cargo check -p gix-transport --features async-client
@@ -134,14 +135,18 @@ unit-tests: · 29 unmodified lines
134135 cargo test -p gix-archive --features tar
135136 cargo test -p gix-archive --features tar_gz
136137 cargo test -p gix-archive --features zip
137− cd gix-object; \
138+ cd gix-status; \
138139 set -ex; \
139140 cargo test; \
140− cargo test --features verbose-object-parsing-errors
141− cd gix-worktree; \
141+ cargo test --features "internal-testing-gix-features-parallel"
142+ cd gix-worktree-state; \
142143 set -ex; \
143144 cargo test; \
144145 cargo test --features "internal-testing-gix-features-parallel"
146+ cd gix-object; \
147+ set -ex; \
148+ cargo test; \
149+ cargo test --features verbose-object-parsing-errors
145150 cargo test -p gix-tempfile --features signals
146151 cargo test -p gix-tempfile
147152 cargo test -p gix-features