| @@ -1,16 +1,15 @@ |
| 1 | 1 | use crate::{pack, pack::data::output, FindExt}; |
| 2 | | −use git_features::{hash, parallel, progress::Progress}; |
| 3 | | −use git_hash::{oid, ObjectId}; |
| 2 | +use git_features::{parallel, progress::Progress}; |
| 4 | 3 | |
| 5 | | −/// Write all `objects` into `out` without attempting to apply any delta compression. |
| 6 | | −/// TODO: Update this |
| 7 | | −/// This allows objects to be written rather immediately. |
| 8 | | −/// Objects are held in memory and compressed using DEFLATE, with those in-flight chunks of compressed |
| 9 | | −/// objects being sent to the current thread for writing. No buffering of these objects is performed, |
| 10 | | −/// allowing for natural back-pressure in case of slow writers. |
| 4 | +/// Given a known list of object `counts`, calculate entries ready to be put into a data pack. |
| 11 | 5 | /// |
| 12 | | −/// * `objects` |
| 13 | | −/// * A list of objects to add to the pack. Duplication checks are performed so no object is ever added to a pack twice. |
| 6 | +/// This allows objects to be written quite soon without having to wait for the entire pack to be built in memory. |
| 7 | +/// A chunk of objects is held in memory and compressed using DEFLATE, and serve the output of this iterator. |
| 8 | +/// That way slow writers will naturally apply back pressure, and communicate to the implementation that more time can be |
| 9 | +/// spent compressing objects. |
| 10 | +/// |
| 11 | +/// * `counts` |
| 12 | +/// * A list of previously counted objects to add to the pack. Duplication checks are not performed, no object is expected to be duplicated. |
| 14 | 13 | /// * `progress` |
| 15 | 14 | /// * a way to obtain progress information |
| 16 | 15 | /// * `options` |
| @@ -32,15 +31,14 @@ use git_hash::{oid, ObjectId}; · 15 unmodified lines |
| 32 | 31 | /// so with minimal overhead (especially compared to `gixp index-from-pack`)~~ Probably works now by chaining Iterators |
| 33 | 32 | /// or keeping enough state to write a pack and then generate an index with recorded data. |
| 34 | 33 | /// |
| 35 | | −pub fn objects_to_entries_iter<Find, Iter, Oid, Cache>( |
| 34 | +pub fn objects_to_entries_iter<Find, Cache>( |
| 35 | + counts: impl AsRef<[output::Count]>, |
| 36 | 36 | db: Find, |
| 37 | 37 | make_cache: impl Fn() -> Cache + Send + Clone + Sync + 'static, |
| 38 | | − objects: Iter, |
| 39 | 38 | _progress: impl Progress, |
| 40 | 39 | Options { |
| 41 | 40 | version, |
| 42 | 41 | thread_limit, |
| 43 | | − input_object_expansion, |
| 44 | 42 | chunk_size, |
| 45 | 43 | }: Options, |
| 46 | 44 | ) -> impl Iterator<Item = Result<Vec<output::Entry>, Error<Find::Error>>> |
| @@ -48,26 +46,16 @@ pub fn objects_to_entries_iter<Find, Iter, Oid, Cache>( · 1 unmodified line |
| 48 | 46 | where |
| 49 | 47 | Find: crate::Find + Clone + Send + Sync + 'static, |
| 50 | 48 | <Find as crate::Find>::Error: Send, |
| 51 | | − Iter: Iterator<Item = Oid> + Send + 'static, |
| 52 | | − Oid: AsRef<oid> + Send + 'static, |
| 53 | 49 | Cache: pack::cache::DecodeEntry, |
| 54 | 50 | { |
| 55 | 51 | assert!( |
| 56 | 52 | matches!(version, pack::data::Version::V2), |
| 57 | 53 | "currently we can only write version 2" |
| 58 | 54 | ); |
| 59 | | − let lower_bound = objects.size_hint().0; |
| 60 | | − let (chunk_size, thread_limit, _) = parallel::optimize_chunk_size_and_thread_limit( |
| 61 | | − chunk_size, |
| 62 | | − if lower_bound == 0 { None } else { Some(lower_bound) }, |
| 63 | | − thread_limit, |
| 64 | | − None, |
| 65 | | − ); |
| 66 | | − let chunks = util::Chunks { |
| 67 | | − iter: objects, |
| 68 | | − size: chunk_size, |
| 69 | | − }; |
| 70 | | − let seen_objs = std::sync::Arc::new(dashmap::DashSet::<ObjectId>::new()); |
| 55 | + let counts = counts.as_ref(); |
| 56 | + let (chunk_size, thread_limit, _) = |
| 57 | + parallel::optimize_chunk_size_and_thread_limit(chunk_size, Some(counts.len()), thread_limit, None); |
| 58 | + let chunks = counts.chunks(chunk_size); |
| 71 | 59 | |
| 72 | 60 | parallel::reduce::Stepwise::new( |
| 73 | 61 | chunks, |
| @@ -75,408 +63,34 @@ where · 1 unmodified line |
| 75 | 63 | move |_n| { |
| 76 | 64 | ( |
| 77 | 65 | Vec::new(), // object data buffer |
| 78 | | − Vec::new(), // object data buffer 2 to hold two objects at a time |
| 79 | 66 | make_cache(), // cache to speed up pack operations |
| 80 | 67 | ) |
| 81 | 68 | }, |
| 82 | | − { |
| 83 | | − let seen_objs = std::sync::Arc::clone(&seen_objs); |
| 84 | | − move |oids: Vec<Oid>, (buf1, buf2, cache)| { |
| 85 | | − use ObjectExpansion::*; |
| 86 | | − let mut out = Vec::new(); |
| 87 | | − let mut tree_traversal_state = git_traverse::tree::breadthfirst::State::default(); |
| 88 | | − let mut tree_diff_state = git_diff::tree::State::default(); |
| 89 | | − let mut parent_commit_ids = Vec::new(); |
| 90 | | − let seen_objs = seen_objs.as_ref(); |
| 91 | | − let mut traverse_delegate = tree::traverse::AllUnseen::new(seen_objs); |
| 92 | | − let mut changes_delegate = tree::changes::AllNew::new(seen_objs); |
| 93 | | − |
| 94 | | − for id in oids.into_iter() { |
| 95 | | − let id = id.as_ref(); |
| 96 | | − let obj = db |
| 97 | | − .find(id, buf1, cache)? |
| 98 | | − .ok_or_else(|| Error::NotFound { oid: id.to_owned() })?; |
| 99 | | − match input_object_expansion { |
| 100 | | − TreeAdditionsComparedToAncestor => { |
| 101 | | − use git_object::Kind::*; |
| 102 | | − let mut obj = obj; |
| 103 | | − let mut id = id.to_owned(); |
| 104 | | − |
| 105 | | − loop { |
| 106 | | − push_obj_entry_unique(&mut out, seen_objs, &db, version, &id, &obj)?; |
| 107 | | − match obj.kind { |
| 108 | | − Tree | Blob => break, |
| 109 | | − Tag => { |
| 110 | | − id = immutable::TagIter::from_bytes(obj.data) |
| 111 | | − .target_id() |
| 112 | | − .expect("every tag has a target"); |
| 113 | | − obj = db |
| 114 | | − .find_existing(id, buf1, cache) |
| 115 | | − .map_err(|_| Error::NotFound { oid: id.to_owned() })?; |
| 116 | | − continue; |
| 117 | | − } |
| 118 | | − Commit => { |
| 119 | | − let current_tree_iter = { |
| 120 | | − let mut commit_iter = immutable::CommitIter::from_bytes(obj.data); |
| 121 | | − let tree_id = commit_iter.tree_id().expect("every commit has a tree"); |
| 122 | | − parent_commit_ids.clear(); |
| 123 | | − for token in commit_iter { |
| 124 | | − match token { |
| 125 | | − Ok(immutable::commit::iter::Token::Parent { id }) => { |
| 126 | | − parent_commit_ids.push(id) |
| 127 | | − } |
| 128 | | − Ok(_) => break, |
| 129 | | − Err(err) => return Err(Error::CommitDecode(err)), |
| 130 | | − } |
| 131 | | − } |
| 132 | | − let obj = db |
| 133 | | − .find_existing(tree_id, buf1, cache) |
| 134 | | − .map_err(|_| Error::NotFound { oid: tree_id })?; |
| 135 | | − push_obj_entry_unique(&mut out, seen_objs, &db, version, &tree_id, &obj)?; |
| 136 | | − immutable::TreeIter::from_bytes(obj.data) |
| 137 | | − }; |
| 138 | | − |
| 139 | | − let objects = if parent_commit_ids.is_empty() { |
| 140 | | − traverse_delegate.clear(); |
| 141 | | − git_traverse::tree::breadthfirst( |
| 142 | | − current_tree_iter, |
| 143 | | − &mut tree_traversal_state, |
| 144 | | − |oid, buf| db.find_existing_tree_iter(oid, buf, cache).ok(), |
| 145 | | − &mut traverse_delegate, |
| 146 | | − ) |
| 147 | | − .map_err(Error::TreeTraverse)?; |
| 148 | | − &traverse_delegate.objects |
| 149 | | − } else { |
| 150 | | − changes_delegate.clear(); |
| 151 | | − for commit_id in &parent_commit_ids { |
| 152 | | − let parent_tree_id = { |
| 153 | | − let parent_commit_obj = db |
| 154 | | − .find_existing(commit_id, buf2, cache) |
| 155 | | − .map_err(|_| Error::NotFound { |
| 156 | | − oid: commit_id.to_owned(), |
| 157 | | − })?; |
| 158 | | − |
| 159 | | − push_obj_entry_unique( |
| 160 | | − &mut out, |
| 161 | | − seen_objs, |
| 162 | | − &db, |
| 163 | | − version, |
| 164 | | − &commit_id, |
| 165 | | − &parent_commit_obj, |
| 166 | | − )?; |
| 167 | | − immutable::CommitIter::from_bytes(parent_commit_obj.data) |
| 168 | | − .tree_id() |
| 169 | | − .expect("every commit has a tree") |
| 170 | | − }; |
| 171 | | − let parent_tree = { |
| 172 | | − let parent_tree_obj = db |
| 173 | | − .find_existing(parent_tree_id, buf2, cache) |
| 174 | | − .map_err(|_| Error::NotFound { oid: parent_tree_id })?; |
| 175 | | − push_obj_entry_unique( |
| 176 | | − &mut out, |
| 177 | | − seen_objs, |
| 178 | | − &db, |
| 179 | | − version, |
| 180 | | − &parent_tree_id, |
| 181 | | − &parent_tree_obj, |
| 182 | | − )?; |
| 183 | | − immutable::TreeIter::from_bytes(parent_tree_obj.data) |
| 184 | | − }; |
| 185 | | − |
| 186 | | − git_diff::tree::Changes::from(Some(parent_tree)) |
| 187 | | − .needed_to_obtain( |
| 188 | | − current_tree_iter.clone(), |
| 189 | | − &mut tree_diff_state, |
| 190 | | − |oid, buf| db.find_existing_tree_iter(oid, buf, cache).ok(), |
| 191 | | − &mut changes_delegate, |
| 192 | | − ) |
| 193 | | − .map_err(Error::TreeChanges)?; |
| 194 | | − } |
| 195 | | − &changes_delegate.objects |
| 196 | | − }; |
| 197 | | − for id in objects.iter() { |
| 198 | | − let obj = db |
| 199 | | − .find(id, buf2, cache)? |
| 200 | | − .ok_or(Error::NotFound { oid: id.to_owned() })?; |
| 201 | | − out.push(obj_to_entry(&db, version, id, &obj)?); |
| 202 | | − } |
| 203 | | − break; |
| 204 | | − } |
| 205 | | − } |
| 206 | | − } |
| 207 | | − } |
| 208 | | − TreeContents => { |
| 209 | | − use git_object::Kind::*; |
| 210 | | − let mut id: ObjectId = id.into(); |
| 211 | | − let mut obj = obj; |
| 212 | | − loop { |
| 213 | | − push_obj_entry_unique(&mut out, seen_objs, &db, version, &id, &obj)?; |
| 214 | | − match obj.kind { |
| 215 | | − Tree => { |
| 216 | | − traverse_delegate.clear(); |
| 217 | | − git_traverse::tree::breadthfirst( |
| 218 | | − git_object::immutable::TreeIter::from_bytes(obj.data), |
| 219 | | − &mut tree_traversal_state, |
| 220 | | − |oid, buf| db.find_existing_tree_iter(oid, buf, cache).ok(), |
| 221 | | − &mut traverse_delegate, |
| 222 | | − ) |
| 223 | | − .map_err(Error::TreeTraverse)?; |
| 224 | | − for id in traverse_delegate.objects.iter() { |
| 225 | | − let obj = db |
| 226 | | − .find(id, buf1, cache)? |
| 227 | | − .ok_or(Error::NotFound { oid: id.to_owned() })?; |
| 228 | | − out.push(obj_to_entry(&db, version, id, &obj)?); |
| 229 | | − } |
| 230 | | − break; |
| 231 | | − } |
| 232 | | − Commit => { |
| 233 | | − id = immutable::CommitIter::from_bytes(obj.data) |
| 234 | | − .tree_id() |
| 235 | | − .expect("every commit has a tree"); |
| 236 | | − obj = db |
| 237 | | − .find_existing(id, buf1, cache) |
| 238 | | − .map_err(|_| Error::NotFound { oid: id.to_owned() })?; |
| 239 | | − continue; |
| 240 | | − } |
| 241 | | − Blob => break, |
| 242 | | − Tag => { |
| 243 | | − id = immutable::TagIter::from_bytes(obj.data) |
| 244 | | − .target_id() |
| 245 | | − .expect("every tag has a target"); |
| 246 | | − obj = db |
| 247 | | − .find_existing(id, buf1, cache) |
| 248 | | − .map_err(|_| Error::NotFound { oid: id.to_owned() })?; |
| 249 | | − continue; |
| 250 | | − } |
| 251 | | − } |
| 252 | | − } |
| 69 | + move |counts: &[output::Count], (buf, cache)| { |
| 70 | + let mut out = Vec::new(); |
| 71 | + for count in counts.into_iter() { |
| 72 | + out.push(match count.entry_pack_location { |
| 73 | + Some(ref location) => match output::Entry::from_pack_entry(location, count, version) { |
| 74 | + Some(entry) => entry, |
| 75 | + None => { |
| 76 | + let obj = db.find_existing(count.id, buf, cache)?; |
| 77 | + output::Entry::from_data(count, &obj) |
| 253 | 78 | } |
| 254 | | − AsIs => push_obj_entry_unique(&mut out, seen_objs, &db, version, id, &obj)?, |
| 79 | + }, |
| 80 | + None => { |
| 81 | + let obj = db.find_existing(count.id, buf, cache)?; |
| 82 | + output::Entry::from_data(count, &obj) |
| 255 | 83 | } |
| 256 | | − } |
| 257 | | − Ok(out) |
| 84 | + }?); |
| 258 | 85 | } |
| 86 | + Ok(out) |
| 259 | 87 | }, |
| 260 | 88 | parallel::reduce::IdentityWithResult::default(), |
| 261 | 89 | ) |
| 262 | 90 | } |
| 263 | 91 | |
| 264 | | −mod tree { |
| 265 | | − pub mod changes { |
| 266 | | − use dashmap::DashSet; |
| 267 | | − use git_diff::tree::visit::{Action, Change}; |
| 268 | | − use git_diff::tree::Visit; |
| 269 | | − use git_hash::bstr::BStr; |
| 270 | | − use git_hash::ObjectId; |
| 271 | | − use std::collections::HashSet; |
| 272 | | − |
| 273 | | − pub struct AllNew<'a> { |
| 274 | | − pub objects: HashSet<ObjectId>, |
| 275 | | − all_seen: &'a DashSet<ObjectId>, |
| 276 | | − } |
| 277 | | − |
| 278 | | − impl<'a> AllNew<'a> { |
| 279 | | − pub fn new(all_seen: &'a DashSet<ObjectId>) -> Self { |
| 280 | | − AllNew { |
| 281 | | − objects: Default::default(), |
| 282 | | − all_seen, |
| 283 | | − } |
| 284 | | − } |
| 285 | | − pub fn clear(&mut self) { |
| 286 | | − self.objects.clear(); |
| 287 | | − } |
| 288 | | − } |
| 289 | | − |
| 290 | | − impl<'a> Visit for AllNew<'a> { |
| 291 | | − fn pop_front_tracked_path_and_set_current(&mut self) {} |
| 292 | | − |
| 293 | | − fn push_back_tracked_path_component(&mut self, _component: &BStr) {} |
| 294 | | − |
| 295 | | − fn push_path_component(&mut self, _component: &BStr) {} |
| 296 | | − |
| 297 | | − fn pop_path_component(&mut self) {} |
| 298 | | − |
| 299 | | − fn visit(&mut self, change: Change) -> Action { |
| 300 | | − match change { |
| 301 | | − Change::Addition { oid, .. } | Change::Modification { oid, .. } => { |
| 302 | | − let inserted = self.all_seen.insert(oid); |
| 303 | | − if inserted { |
| 304 | | − self.objects.insert(oid); |
| 305 | | − } |
| 306 | | − } |
| 307 | | − Change::Deletion { .. } => {} |
| 308 | | − }; |
| 309 | | − Action::Continue |
| 310 | | − } |
| 311 | | − } |
| 312 | | − } |
| 313 | | − pub mod traverse { |
| 314 | | − use dashmap::DashSet; |
| 315 | | − use git_hash::{bstr::BStr, ObjectId}; |
| 316 | | − use git_object::immutable::tree::Entry; |
| 317 | | − use git_traverse::tree::visit::{Action, Visit}; |
| 318 | | − use std::collections::HashSet; |
| 319 | | − |
| 320 | | − pub struct AllUnseen<'a> { |
| 321 | | − pub objects: HashSet<ObjectId>, |
| 322 | | − all_seen: &'a DashSet<ObjectId>, |
| 323 | | − } |
| 324 | | − |
| 325 | | − impl<'a> AllUnseen<'a> { |
| 326 | | − pub fn new(all_seen: &'a DashSet<ObjectId>) -> Self { |
| 327 | | − AllUnseen { |
| 328 | | − objects: Default::default(), |
| 329 | | − all_seen, |
| 330 | | − } |
| 331 | | − } |
| 332 | | − pub fn clear(&mut self) { |
| 333 | | − self.objects.clear(); |
| 334 | | − } |
| 335 | | − } |
| 336 | | − |
| 337 | | − impl<'a> Visit for AllUnseen<'a> { |
| 338 | | − fn pop_front_tracked_path_and_set_current(&mut self) {} |
| 339 | | − |
| 340 | | − fn push_back_tracked_path_component(&mut self, _component: &BStr) {} |
| 341 | | − |
| 342 | | − fn push_path_component(&mut self, _component: &BStr) {} |
| 343 | | − |
| 344 | | − fn pop_path_component(&mut self) {} |
| 345 | | − |
| 346 | | − fn visit_tree(&mut self, entry: &Entry<'_>) -> Action { |
| 347 | | − let inserted = self.all_seen.insert(entry.oid.to_owned()); |
| 348 | | − if inserted { |
| 349 | | − self.objects.insert(entry.oid.to_owned()); |
| 350 | | − Action::Continue |
| 351 | | − } else { |
| 352 | | − Action::Skip |
| 353 | | − } |
| 354 | | − } |
| 355 | | − |
| 356 | | − fn visit_nontree(&mut self, entry: &Entry<'_>) -> Action { |
| 357 | | − let inserted = self.all_seen.insert(entry.oid.to_owned()); |
| 358 | | − if inserted { |
| 359 | | − self.objects.insert(entry.oid.to_owned()); |
| 360 | | − } |
| 361 | | − Action::Continue |
| 362 | | − } |
| 363 | | − } |
| 364 | | − } |
| 365 | | −} |
| 366 | | − |
| 367 | | −fn push_obj_entry_unique<Find>( |
| 368 | | − out: &mut Vec<output::Entry>, |
| 369 | | − all_seen: &DashSet<ObjectId>, |
| 370 | | − db: &Find, |
| 371 | | − version: pack::data::Version, |
| 372 | | − id: &oid, |
| 373 | | − obj: &crate::data::Object<'_>, |
| 374 | | −) -> Result<(), Error<Find::Error>> |
| 375 | | −where |
| 376 | | − Find: crate::Find, |
| 377 | | −{ |
| 378 | | − let inserted = all_seen.insert(id.to_owned()); |
| 379 | | − if inserted { |
| 380 | | − out.push(obj_to_entry(db, version, id, obj)?); |
| 381 | | − } |
| 382 | | − Ok(()) |
| 383 | | −} |
| 384 | | − |
| 385 | | −fn obj_to_entry<Find>( |
| 386 | | − db: &Find, |
| 387 | | − version: pack::data::Version, |
| 388 | | − id: &oid, |
| 389 | | − obj: &crate::data::Object<'_>, |
| 390 | | −) -> Result<output::Entry, Error<Find::Error>> |
| 391 | | −where |
| 392 | | − Find: crate::Find, |
| 393 | | −{ |
| 394 | | − Ok(match db.pack_entry(&obj) { |
| 395 | | − Some(entry) if entry.version == version => { |
| 396 | | − let pack_entry = pack::data::Entry::from_bytes(entry.data, 0); |
| 397 | | − if let Some(expected) = entry.crc32 { |
| 398 | | − let actual = hash::crc32(entry.data); |
| 399 | | − if actual != expected { |
| 400 | | − return Err(Error::PackToPackCopyCrc32Mismatch { actual, expected }); |
| 401 | | − } |
| 402 | | − } |
| 403 | | − if pack_entry.header.is_base() { |
| 404 | | − output::Entry { |
| 405 | | − id: id.to_owned(), |
| 406 | | − object_kind: pack_entry.header.to_kind().expect("non-delta"), |
| 407 | | − kind: output::entry::Kind::Base, |
| 408 | | − decompressed_size: obj.data.len(), |
| 409 | | − compressed_data: entry.data[pack_entry.data_offset as usize..].to_owned(), |
| 410 | | − } |
| 411 | | − } else { |
| 412 | | − output::Entry::from_data(id, &obj).map_err(Error::NewEntry)? |
| 413 | | − } |
| 414 | | − } |
| 415 | | − _ => output::Entry::from_data(id, &obj).map_err(Error::NewEntry)?, |
| 416 | | − }) |
| 417 | | −} |
| 418 | | − |
| 419 | | −mod util { |
| 420 | | − pub struct Chunks<I> { |
| 421 | | − pub size: usize, |
| 422 | | − pub iter: I, |
| 423 | | − } |
| 424 | | − |
| 425 | | − impl<I, Item> Iterator for Chunks<I> |
| 426 | | − where |
| 427 | | − I: Iterator<Item = Item>, |
| 428 | | − { |
| 429 | | − type Item = Vec<Item>; |
| 430 | | − |
| 431 | | − fn next(&mut self) -> Option<Self::Item> { |
| 432 | | − let mut res = Vec::with_capacity(self.size); |
| 433 | | − let mut items_left = self.size; |
| 434 | | − while let Some(item) = self.iter.next() { |
| 435 | | − res.push(item); |
| 436 | | − items_left -= 1; |
| 437 | | − if items_left == 0 { |
| 438 | | − break; |
| 439 | | − } |
| 440 | | − } |
| 441 | | − if res.is_empty() { |
| 442 | | − None |
| 443 | | − } else { |
| 444 | | − Some(res) |
| 445 | | − } |
| 446 | | − } |
| 447 | | − } |
| 448 | | −} |
| 449 | | − |
| 450 | 92 | mod types { |
| 451 | | − use crate::pack::data::output::entry; |
| 452 | | − use git_hash::ObjectId; |
| 453 | | − |
| 454 | | − /// The way input objects are handled |
| 455 | | − #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] |
| 456 | | − #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] |
| 457 | | − pub enum ObjectExpansion { |
| 458 | | − /// Don't do anything with the input objects except for transforming them into pack entries |
| 459 | | − AsIs, |
| 460 | | − /// If the input object is a Commit then turn it into a pack entry. Additionally obtain its tree, turn it into a pack entry |
| 461 | | − /// along with all of its contents, that is nested trees, and any other objects reachable from it. |
| 462 | | − /// Otherwise, the same as [`AsIs`][ObjectExpansion::AsIs]. |
| 463 | | − /// |
| 464 | | − /// This mode is useful if all reachable objects should be added, as in cloning a repository. |
| 465 | | − TreeContents, |
| 466 | | − /// If the input is a commit, obtain its ancestors and turn them into pack entries. Obtain the ancestor trees along with the commits |
| 467 | | − /// tree and turn them into pack entries. Finally obtain the added/changed objects when comparing the ancestor trees with the |
| 468 | | − /// current tree and turn them into entries as well. |
| 469 | | − /// Otherwise, the same as [`AsIs`][ObjectExpansion::AsIs]. |
| 470 | | − /// |
| 471 | | − /// This mode is useful to build a pack containing only new objects compared to a previous state. |
| 472 | | − TreeAdditionsComparedToAncestor, |
| 473 | | − } |
| 474 | | − |
| 475 | | − impl Default for ObjectExpansion { |
| 476 | | − fn default() -> Self { |
| 477 | | − ObjectExpansion::AsIs |
| 478 | | − } |
| 479 | | − } |
| 93 | + use crate::{find, pack::data::output::entry}; |
| 480 | 94 | |
| 481 | 95 | /// Configuration options for the pack generation functions provied in [this module][crate::pack::data::output]. |
| 482 | 96 | #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] |
| @@ -489,8 +103,6 @@ mod types { · 6 unmodified lines |
| 489 | 103 | pub chunk_size: usize, |
| 490 | 104 | /// The pack data version to produce |
| 491 | 105 | pub version: crate::pack::data::Version, |
| 492 | | − /// The way input objects are handled |
| 493 | | − pub input_object_expansion: ObjectExpansion, |
| 494 | 106 | } |
| 495 | 107 | |
| 496 | 108 | impl Default for Options { |
| @@ -499,7 +111,6 @@ mod types { · 2 unmodified lines |
| 499 | 111 | thread_limit: None, |
| 500 | 112 | chunk_size: 10, |
| 501 | 113 | version: Default::default(), |
| 502 | | − input_object_expansion: Default::default(), |
| 503 | 114 | } |
| 504 | 115 | } |
| 505 | 116 | } |
| @@ -507,26 +118,14 @@ mod types { · 1 unmodified line |
| 507 | 118 | /// The error returned by the pack generation function [`to_entry_iter()`][crate::pack::data::output::objects_to_entries_iter()]. |
| 508 | 119 | #[derive(Debug, thiserror::Error)] |
| 509 | 120 | #[allow(missing_docs)] |
| 510 | | − pub enum Error<LocateErr> |
| 121 | + pub enum Error<FindErr> |
| 511 | 122 | where |
| 512 | | − LocateErr: std::error::Error + 'static, |
| 123 | + FindErr: std::error::Error + 'static, |
| 513 | 124 | { |
| 514 | 125 | #[error(transparent)] |
| 515 | | − CommitDecode(git_object::immutable::object::decode::Error), |
| 516 | | − #[error(transparent)] |
| 517 | | − Locate(#[from] LocateErr), |
| 518 | | − #[error(transparent)] |
| 519 | | − TreeTraverse(git_traverse::tree::breadthfirst::Error), |
| 520 | | − #[error(transparent)] |
| 521 | | − TreeChanges(git_diff::tree::changes::Error), |
| 522 | | − #[error("Object id {oid} wasn't found in object database")] |
| 523 | | − NotFound { oid: ObjectId }, |
| 524 | | − #[error("Entry expected to have hash {expected}, but it had {actual}")] |
| 525 | | − PackToPackCopyCrc32Mismatch { actual: u32, expected: u32 }, |
| 126 | + FindExisting(find::existing_object::Error<FindErr>), |
| 526 | 127 | #[error(transparent)] |
| 527 | | − NewEntry(entry::Error), |
| 128 | + NewEntry(#[from] entry::Error), |
| 528 | 129 | } |
| 529 | 130 | } |
| 530 | | −use dashmap::DashSet; |
| 531 | | −use git_object::immutable; |
| 532 | | −pub use types::{Error, ObjectExpansion, Options}; |
| 131 | +pub use types::{Error, Options}; |