gix_worktree_state/checkout/
function.rs1use std::sync::atomic::AtomicBool;
2
3use gix_features::{interrupt, parallel::in_parallel_with_finalize};
4use gix_worktree::{stack, Stack};
5
6use crate::checkout::chunk;
7
8#[allow(clippy::too_many_arguments)]
19pub fn checkout<Find>(
20 index: &mut gix_index::State,
21 dir: impl Into<std::path::PathBuf>,
22 objects: Find,
23 files: &dyn gix_features::progress::Count,
24 bytes: &dyn gix_features::progress::Count,
25 should_interrupt: &AtomicBool,
26 options: crate::checkout::Options,
27) -> Result<crate::checkout::Outcome, crate::checkout::Error>
28where
29 Find: gix_object::Find + Send + Clone,
30{
31 let paths = index.take_path_backing();
32 let res = checkout_inner(index, &paths, dir, objects, files, bytes, should_interrupt, options);
33 index.return_path_backing(paths);
34 res
35}
36
37#[allow(clippy::too_many_arguments)]
38fn checkout_inner<Find>(
39 index: &mut gix_index::State,
40 paths: &gix_index::PathStorage,
41 dir: impl Into<std::path::PathBuf>,
42 objects: Find,
43 files: &dyn gix_features::progress::Count,
44 bytes: &dyn gix_features::progress::Count,
45 should_interrupt: &AtomicBool,
46 mut options: crate::checkout::Options,
47) -> Result<crate::checkout::Outcome, crate::checkout::Error>
48where
49 Find: gix_object::Find + Send + Clone,
50{
51 let num_files = files.counter();
52 let num_bytes = bytes.counter();
53 let dir = dir.into();
54 let (chunk_size, thread_limit, num_threads) = gix_features::parallel::optimize_chunk_size_and_thread_limit(
55 100,
56 index.entries().len().into(),
57 options.thread_limit,
58 None,
59 );
60
61 let mut ctx = chunk::Context {
62 buf: Vec::new(),
63 options: (&options).into(),
64 path_cache: Stack::from_state_and_ignore_case(
65 dir,
66 options.fs.ignore_case,
67 stack::State::for_checkout(
68 options.overwrite_existing,
69 options.validate,
70 std::mem::take(&mut options.attributes),
71 ),
72 index,
73 paths,
74 ),
75 filters: options.filters,
76 objects,
77 };
78
79 let chunk::Outcome {
80 mut collisions,
81 mut errors,
82 mut bytes_written,
83 files: files_updated,
84 delayed_symlinks,
85 delayed_paths_unknown,
86 delayed_paths_unprocessed,
87 } = if num_threads == 1 {
88 let entries_with_paths = interrupt::Iter::new(index.entries_mut_with_paths_in(paths), should_interrupt);
89 let mut delayed_filter_results = Vec::new();
90 let mut out = chunk::process(
91 entries_with_paths,
92 &num_files,
93 &num_bytes,
94 &mut delayed_filter_results,
95 &mut ctx,
96 )?;
97 chunk::process_delayed_filter_results(delayed_filter_results, &num_files, &num_bytes, &mut out, &mut ctx)?;
98 out
99 } else {
100 let entries_with_paths = interrupt::Iter::new(index.entries_mut_with_paths_in(paths), should_interrupt);
101 in_parallel_with_finalize(
102 gix_features::iter::Chunks {
103 inner: entries_with_paths,
104 size: chunk_size,
105 },
106 thread_limit,
107 {
108 let ctx = ctx.clone();
109 move |_| (Vec::new(), ctx)
110 },
111 |chunk, (delayed_filter_results, ctx)| {
112 chunk::process(chunk.into_iter(), &num_files, &num_bytes, delayed_filter_results, ctx)
113 },
114 |(delayed_filter_results, mut ctx)| {
115 let mut out = chunk::Outcome::default();
116 chunk::process_delayed_filter_results(
117 delayed_filter_results,
118 &num_files,
119 &num_bytes,
120 &mut out,
121 &mut ctx,
122 )?;
123 Ok(out)
124 },
125 chunk::Reduce {
126 aggregate: Default::default(),
127 },
128 )?
129 };
130
131 for (entry, entry_path) in delayed_symlinks {
132 bytes_written += chunk::checkout_entry_handle_result(
133 entry,
134 entry_path,
135 &mut errors,
136 &mut collisions,
137 &num_files,
138 &num_bytes,
139 &mut ctx,
140 )?
141 .as_bytes()
142 .expect("only symlinks are delayed here, they are never filtered (or delayed again)")
143 as u64;
144 }
145
146 Ok(crate::checkout::Outcome {
147 files_updated,
148 collisions,
149 errors,
150 bytes_written,
151 delayed_paths_unknown,
152 delayed_paths_unprocessed,
153 })
154}