RMDMAYRXYBU5OQXV5HSF6LFD4NBMKRNH5EPIVW3K5HAV6D56IG6QC GBX4AFASHNICJ25B6PAGXP3C3NJ5PPXZ76STLDVPBUVEGDJP5ZAAC RUBSM5DRA4O7SGD7NO7QYFGDQ2CQL6K7SZTIQVGRWAQHGSFUBGCQC SAADQM3H4JAE2JE65Y6IHONZ57V3ZZ3IBBV72O3LRBTGWBPJWR3AC OQQ4TGEMWDB6JXZ4H4D2XQJE3PDLINTZ4YCL2O2EVG67CDSAM35AC V6J6DTJCGVYSL5W7NVSRP5ROIUWTMZW2MBYO7UBZFCUEJQO3ADWQC 7KNPYIDUXCBZ65NA74NL2DIFS6STJWN4XXHXLTIV5QXZSVLARJMAC KJOOI346EYXQIRDEGWHYILGX44AZNPHBFUDW5HYEEG5IC2ZXV6GAC 2VXTRPO4OML5A2RPI7SAEV5SJNOFIVS4TMYYG6TUUS5EXFMAPRJAC HOTQHK5URWTJ4IBMSWYPZQOPHA2ZQSPQAN5MAKGUDUAC6LZRDKOQC SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC I24UEJQLCH2SOXA4UHIYWTRDCHSOPU7AFTRUOTX7HZIAV4AZKYEQC FXEDPLRI7PXLDXV634ZA6D5Q3ZWG3ESTKJTMRPJ4MAHI7PKU3M6AC ZAEUSICJC3YOWGF6NZEQCQ34PHPRSBCJEP7FIWE6VIWJGVU734HQC VO5OQW4W2656DIYYRNZ3PO7TQ4JOKQ3GVWE5ALUTYVMX3WMXJOYQC ZSF3YFZTDOXMCOC3HOT5C6MQLYLWOR7QJAOUDS2M2Z4SC2YW3GRAC YN63NUZO4LVJ7XPMURDULTXBVJKW5MVCTZ24R7Z52QMHO3HPDUVQC 3AMEP2Y5J6GA4AWQONF4JVA3XSR3ASLHHKMYG44R72SOUY3UQCDAC GHO6DWPILBBTL6CVZKERJBTFL3EY6ZT4YM4E5R4S6YPGVFKFHCVAC IIV3EL2XYI2X7HZWKXEXQFAE3R3KC2Q7SGOT3Q332HSENMYVF32QC TVVW53HZGYPODAXEQ4BFZNSPBOFG6JEDVOKIYIDZMWFAMOBKOR2QC 3S6LU2U5TIU43WRE5RQS3IOLVJLVNCDL4W44FVK2HR3NAXZ7IDUAC LGEJSLTYI7Y2CYC3AN6ECMT3D3MTWCAKZPVQEG5MPM2OBW5FQ46AC VYHHOEYHO67JNJEODX5L3CQFIV3DAXZBBIQUOMCWJDYF3VWICDNQC LLT3GY6ULCVHMO3VUSVI5H4O244Z3ULOWLTW2IGJXIA2TWIHJDSQC LERRJNFC6324RC6ADDTEPCNR3MYH6GKIQUDD433ZAIEECFF5CADAC G6S6PWZEFJK7ARWBIFKDU6VYC5DCJ2YFJMWZOLLWWKU52R2QPXZAC DJYHARZ7CSRMX6ZFM6P52SM2EC57VTSHWAIMFSD7Q3EL7UYZGLXQC XR7MNOMU5PMOOEY2EPPUABZ7NOP432RDCWUET23ONPXTT3JQIFIAC 246V5TYIUL7CFN7G5Y7A35EEM6IJPN532ROEYVSM7Q4HCQSWPDBQC NUAOEIXMKZO5KQWQ3TLQWO3RIXBPJU4QOPW7MGCV3ITDAUHFEK5QC PKIHBUGT3N4BUZ2QP2UWJI4ICOIF6EZVXBFKG753SOTYBAKSVTFAC ZHABNS3S6FSINO74FOI5KHYXYDTBPO4FQTTYTUS7NNKEVVNLYC4AC ADPAFSMYUBTKSK63EPCY5WQGROJQWFCWO4UFPWY3ZXD5ZNH26P2QC O4DNWMPDUWI6SKYOZTQKCSX6MSR73CTGCUSM65TSQYVOUSAAS6KAC 3I4PAA2AW3VUTA3HLS2G4TQMWB7BO25DMCC7VWJHG6WMHCBHR6JAC GJZWSXHQ6SYUDTVDOUBTJYU3SG567M2AXWURWKRNVP2MISZ444DQC YCEZL7VFBZNOZTSSI24D36ACJVZKXCCEOIFWIHQWK22QPB4PDTRAC C4MJ7D7QCOFGIHQSDV3UC76DTSE5M7JSLGN5MROMSVKFVQRFSP5QC 2RXOCWUWOGHEKHT5W73LAHJSOZVRTOGS7BWLSIGEEEBJGMCZBXQAC VNBLGT6GAN2AHKRFKTKED7WNDDRGNULY5H343ZYV3ETSDZZKGBTAC XA23FMQM2AI7RMR36AYN7UNP2D5JWVJMJPHURWZO7URM7H46PU6AC I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC BD5PC25AB5MKVIYDFSDGRZ4YGX4PKW4SMZ3YAYAPNA5HLDVJUR3QC BXD3IQYNMKMI5BTANCF6NZHZP4CKPWADGJMBT2R3WTMKVKONT5QAC WZVCLZKY34KQBQU6YBGJLQCDADBQ67LQVDNRVCMQVY3O3C3EIWSQC CCFJ7VO3I73FE3MZRS5RSDRYNZVW7AXC345P4BXS7JIL2TU3LQJQC RRCSHAYZ6RLWVPNYHF2F5FSRL2KKJNPQUQRIJYLJGB23BZQQ7JLQC stack.push((source, dest));stack.push((grandparent, source_parent));
if grandparent.is_root() || grandparent.start == grandparent.end {return_value = restore_inode(txn, changes, source, dest, Inode::ROOT, salt)?;} else {stack.push((source, dest));stack.push((grandparent, source_parent));}
debug!("TAKEN 2");self.delete_obsolete_children(&*txn,txn.graph(&channel),working_copy,changes,&item.full_path,Position::ROOT,)?;Position::OPTION_ROOT
// Test for a "root" vertex below the 0 one.let f0 = EdgeFlags::FOLDER | EdgeFlags::BLOCK;let f1 = f0 | EdgeFlags::PSEUDO;self.recorded_inodes.lock().insert(Inode::ROOT, Position::ROOT.to_option());let mut has_nonempty_root = false;for e in iter_adjacent(&*txn, txn.graph(&*channel), Vertex::ROOT, f0, f1)? {let e = e?;let child = txn.find_block(txn.graph(&*channel), e.dest()).unwrap();if child.start == child.end {let grandchild =iter_adjacent(&*txn, txn.graph(&*channel), *child, f0, f1)?.next().unwrap()?.dest();root_vertices.push(grandchild);self.delete_obsolete_children(&*txn,txn.graph(&channel),working_copy,changes,&item.full_path,grandchild,)?;} else {has_nonempty_root = true}}if has_nonempty_root && !root_vertices.is_empty() {// This repository is mixed between "zero" roots,// and new-style-roots.root_vertices.push(Position::ROOT)}Position::ROOT.to_option()
// Move on to the next step.debug!("TAKING LOCK {}", line!());let txn = txn.read();let channel = channel.r.read();self.push_children::<_, _, C>(&*txn,&*channel,working_copy,&mut item,&mut components,vertex,&mut stack,prefix,changes,)?;
if root_vertices.is_empty() {// Move on to the next step.debug!("TAKING LOCK {}", line!());let txn = txn.read();let channel = channel.r.read();self.push_children::<_, _, C>(&*txn,&*channel,working_copy,&mut item,&mut components,vertex,&mut stack,prefix,changes,)?;} else {for vertex in root_vertices {let txn = txn.read();let channel = channel.r.read();self.push_children::<_, _, C>(&*txn,&*channel,working_copy,&mut item,&mut components,vertex.to_option(),&mut stack,prefix,changes,)?;}}
fn add_root_if_needed(&mut self,v_papa: Position<Option<ChangeId>>,) -> Position<Option<ChangeId>> {let mut contents = self.contents.lock();if v_papa.change == Some(ChangeId::ROOT) {let mut new_root = self.new_root.lock();if let Some(pos) = *new_root {Position { change: None, pos }} else {contents.push(0);let pos = ChangePosition(contents.len().into());contents.push(0);let pos2 = ChangePosition(contents.len().into());contents.push(0);self.actions.push(Hunk::FileAdd {add_name: Atom::NewVertex(NewVertex {up_context: vec![v_papa],down_context: vec![],start: pos2,end: pos2,flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,inode: v_papa,}),add_inode: Atom::NewVertex(NewVertex {up_context: vec![Position {change: None,pos: pos2,}],down_context: vec![],start: pos,end: pos,flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,inode: v_papa,}),contents: None,path: "/".to_string(),encoding: None,});*new_root = Some(pos);Position { change: None, pos }}} else {v_papa}}
for name_ in iter_adjacent(&*txn_,txn_.graph(&*channel_),vertex.inode_vertex(),f0,f1,)? {debug!("name_ = {:?}", name_);let name_ = name_?;if !name_.flag().contains(EdgeFlags::PARENT) {debug!("continue");continue;}if name_.flag().contains(EdgeFlags::DELETED) {debug!("is_deleted {:?}: {:?}", item.full_path, name_);is_deleted = true;break;}let name_dest = txn_.find_block_end(txn_.graph(&*channel_), name_.dest()).unwrap();let mut meta = Vec::new();let FileMetadata {basename,metadata,encoding,} = changes.get_file_meta(|p| txn_.get_external(&p).unwrap().map(From::from),*name_dest,&mut meta,).map_err(RecordError::Changestore)?;debug!("former basename of {:?}: {:?} {:?}",vertex, basename, metadata);if let Some(v_papa) =iter_adjacent(&*txn_, txn_.graph(&*channel_), *name_dest, f0, f1)?.next(){let v_papa = v_papa?;if !v_papa.flag().contains(EdgeFlags::DELETED) {former_parents.push(Parent {basename: basename.to_string(),metadata,encoding,parent: v_papa.dest().to_option(),})}}}
let (former_parents, is_deleted) =collect_former_parents::<C, W, T>(changes, &*txn_, &*channel_, vertex)?;
debug!("new_meta = {:?}", new_meta);if former_parents.len() > 1|| former_parents[0].basename != item.basename|| former_parents[0].metadata != item.metadata|| former_parents[0].parent != item.v_papa|| is_deleted{debug!("new_papa = {:?}", new_papa);self.record_moved_file::<_, _, W>(changes,&*txn_,&*channel_,&item,vertex,new_papa.unwrap(),former_parents[0].encoding.clone(),)?}if new_meta.is_file()&& (self.force_rediff|| modified_since_last_commit(&*txn_,&*channel_,&working_copy,&item.full_path,)?){let mut ret = retrieve(&*txn_, txn_.graph(&*channel_), vertex)?;let mut b = Vec::new();let encoding = working_copy.decode_file(&item.full_path, &mut b).map_err(RecordError::WorkingCopy)?;debug!("diffing…");let len = self.actions.len();self.diff(changes,&*txn_,&*channel_,diff_algorithm,item.full_path.clone(),item.inode,vertex.to_option(),&mut ret,&b,&encoding,diff_sep,)?;if self.actions.len() > len {if let Ok(last_modified) = working_copy.modified_time(&item.full_path) {if self.oldest_change == std::time::SystemTime::UNIX_EPOCH {self.oldest_change = last_modified;} else {self.oldest_change = self.oldest_change.min(last_modified);}}}debug!("new actions: {:?}, total {:?}",&self.actions.len() - len,self.actions.len());}
self.record_nondeleted(&*txn_,diff_algorithm,diff_sep,&*channel_,working_copy,changes,item,new_papa,vertex,new_meta,&former_parents,is_deleted,)?
changes,)?}Ok(())}fn record_nondeleted<T: ChannelTxnT + TreeTxnT<TreeError = <T as GraphTxnT>::GraphError>,W: WorkingCopyRead + Clone,C: ChangeStore,>(&mut self,txn: &T,diff_algorithm: diff::Algorithm,diff_sep: ®ex::bytes::Regex,channel: &T::Channel,working_copy: W,changes: &C,item: &RecordItem,new_papa: Option<Position<Option<ChangeId>>>,vertex: Position<ChangeId>,new_meta: InodeMetadata,former_parents: &[Parent],is_deleted: bool,) -> Result<(), RecordError<C::Error, W::Error, T::GraphError>>where<W as crate::working_copy::WorkingCopyRead>::Error: 'static,{if former_parents.len() > 1|| former_parents[0].basename != item.basename|| former_parents[0].metadata != item.metadata|| former_parents[0].parent != item.v_papa|| is_deleted{debug!("new_papa = {:?}", new_papa);self.record_moved_file::<_, _, W>(
}if new_meta.is_file()&& (self.force_rediff|| modified_since_last_commit(txn, channel, &working_copy, &item.full_path)?){let mut ret = retrieve(txn, txn.graph(channel), vertex)?;let mut b = Vec::new();let encoding = working_copy.decode_file(&item.full_path, &mut b).map_err(RecordError::WorkingCopy)?;debug!("diffing…");let len = self.actions.len();self.diff(changes,txn,channel,diff_algorithm,item.full_path.clone(),item.inode,vertex.to_option(),&mut ret,&b,&encoding,diff_sep,)?;if self.actions.len() > len {if let Ok(last_modified) = working_copy.modified_time(&item.full_path) {if self.oldest_change == std::time::SystemTime::UNIX_EPOCH {self.oldest_change = last_modified;} else {self.oldest_change = self.oldest_change.min(last_modified);}}}debug!("new actions: {:?}, total {:?}",&self.actions.len() - len,self.actions.len());
fn collect_former_parents<C: ChangeStore, W: WorkingCopyRead, T: ChannelTxnT>(changes: &C,txn: &T,channel: &T::Channel,vertex: Position<ChangeId>,) -> Result<(Vec<Parent>, bool), RecordError<C::Error, W::Error, T::GraphError>>whereW::Error: 'static,{let mut former_parents = Vec::new();let f0 = EdgeFlags::FOLDER | EdgeFlags::PARENT;let f1 = EdgeFlags::all();let mut is_deleted = true;for name_ in iter_adjacent(txn, txn.graph(channel), vertex.inode_vertex(), f0, f1)? {debug!("name_ = {:?}", name_);let name_ = name_?;if !name_.flag().contains(EdgeFlags::PARENT) {debug!("continue");continue;}if name_.flag().contains(EdgeFlags::DELETED) {debug!("is_deleted {:?}", name_);is_deleted = true;break;}let name_dest = txn.find_block_end(txn.graph(channel), name_.dest()).unwrap();let mut meta = Vec::new();let FileMetadata {basename,metadata,encoding,} = changes.get_file_meta(|p| txn.get_external(&p).unwrap().map(From::from),*name_dest,&mut meta,).map_err(RecordError::Changestore)?;debug!("former basename of {:?}: {:?} {:?}",vertex, basename, metadata);if let Some(v_papa) = iter_adjacent(txn, txn.graph(channel), *name_dest, f0, f1)?.next() {let v_papa = v_papa?;if !v_papa.flag().contains(EdgeFlags::DELETED) {former_parents.push(Parent {basename: basename.to_string(),metadata,encoding,parent: v_papa.dest().to_option(),})}}}Ok((former_parents, is_deleted))}
let grandparent_changed = parent_pos != grandparent.dest().to_option();
let grandparent_changed = if parent_pos.change == Some(ChangeId::ROOT) {!is_root_vertex(txn, channel, grandparent.dest())?} else {parent_pos != grandparent.dest().to_option()};
}fn is_root_vertex<T: GraphTxnT>(txn: &T,channel: &T::Graph,v: Position<ChangeId>,) -> Result<bool, TxnErr<T::GraphError>> {for parent in iter_adjacent(txn,channel,v.inode_vertex(),EdgeFlags::FOLDER | EdgeFlags::PARENT,EdgeFlags::FOLDER | EdgeFlags::PARENT | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,)? {let p = parent?.dest();let p = txn.find_block_end(channel, p).unwrap();if p.start == p.end {return Ok(true);} else {return Ok(false);}}Ok(false)
let mut conflicts = Vec::new();
let mut state = OutputState {done_vertices: HashMap::default(),actual_moves: Vec::new(),conflicts: Vec::new(),output_name_conflicts,work: work.clone(),done_inodes: HashSet::new(),salt,if_modified_after,next_prefix_basename: prefix.next(),is_following_prefix: true,pending_change_id,};
let mut next_prefix_basename = prefix.next();let mut is_first_none = true;if next_prefix_basename.is_none() {let dead = {let txn_ = txn.read();let channel = channel.read();let graph = txn_.graph(&*channel);collect_dead_files(&*txn_, graph, pending_change_id, Inode::ROOT)?};debug!("dead (line {}) = {:?}", line!(), dead);if !dead.is_empty() {let mut txn = txn.write();kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;}is_first_none = false;}
state.kill_dead_files::<_, _, P>(repo, &txn, &channel)?;
debug!("files: {:?} {:?}", a, b);{let txn = txn.read();
sort_conflicting_names(&txn, &channel, &mut b);state.output_name(repo, changes, &txn, &channel, &mut next_files, a, b)?;}std::mem::swap(&mut files, &mut next_files);}stop.store(true, std::sync::atomic::Ordering::Relaxed);let o = output_loop(repo, changes, txn, channel, work, stop, 0);for t in threads {state.conflicts.extend(t.join().unwrap()?.into_iter());}state.conflicts.extend(o?.into_iter());for (a, b) in state.actual_moves.iter() {repo.rename(a, b).map_err(OutputError::WorkingCopy)?}Ok(state.conflicts)}fn sort_conflicting_names<T: ChannelTxnT + Send + Sync + 'static>(txn: &ArcTxn<T>,channel: &ChannelRef<T>,b: &mut [(Vertex<ChangeId>, OutputItem)],) {debug!("files: {:?}", b);let txn = txn.read();let channel = channel.read();b.sort_unstable_by(|u, v| {txn.get_changeset(txn.changes(&channel), &u.0.change).unwrap().cmp(&txn.get_changeset(txn.changes(&channel), &v.0.change).unwrap(),)});}struct OutputState<'a> {actual_moves: Vec<(String, String)>,output_name_conflicts: bool,done_vertices: HashMap<Position<ChangeId>, (Vertex<ChangeId>, String)>,conflicts: Vec<Conflict>,work: Arc<crossbeam_deque::Injector<(OutputItem, String, Option<String>)>>,done_inodes: HashSet<Inode>,salt: u64,if_modified_after: Option<std::time::SystemTime>,next_prefix_basename: Option<&'a str>,is_following_prefix: bool,pending_change_id: ChangeId,}impl<'a> OutputState<'a> {fn kill_dead_files<T: TreeMutTxnT+ ChannelMutTxnT+ GraphMutTxnT<GraphError = <T as TreeTxnT>::TreeError>+ Send+ Sync+ 'static,R: WorkingCopy + Clone + Send + Sync + 'static,P: ChangeStore + Clone + 'static,>(&mut self,repo: &R,txn: &ArcTxn<T>,channel: &ChannelRef<T>,) -> Result<(), OutputError<P::Error, T::TreeError, R::Error>> {if self.next_prefix_basename.is_none() && self.is_following_prefix {let dead = {let txn_ = txn.read();
b.sort_unstable_by(|u, v| {txn.get_changeset(txn.changes(&channel), &u.0.change).unwrap().cmp(&txn.get_changeset(txn.changes(&channel), &v.0.change).unwrap(),)});
let graph = txn_.graph(&*channel);collect_dead_files(&*txn_, graph, self.pending_change_id, Inode::ROOT)?};debug!("dead (line {}) = {:?}", line!(), dead);if !dead.is_empty() {let mut txn = txn.write();kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;
let mut is_first_name = true;for (name_key, mut output_item) in b {let name_entry = match done_vertices.entry(output_item.pos) {Entry::Occupied(e) => {debug!("pos already visited: {:?} {:?} {:?} {:?}",a,output_item.pos,e.get(),name_key);if e.get().0 != name_key {conflicts.push(Conflict::MultipleNames {pos: output_item.pos,path: e.get().1.clone(),});}continue;}Entry::Vacant(e) => {debug!("first visit {:?} {:?}", a, output_item.pos);e}};
self.is_following_prefix = false;}Ok(())}
let output_item_inode = {let txn = txn.read();if let Some(inode) = txn.get_revinodes(&output_item.pos, None)? {Some((*inode, *txn.get_inodes(inode, None)?.unwrap()))} else {None}};
fn make_inode(&mut self,a: &str,name_key: Vertex<ChangeId>,output_item: &mut OutputItem,is_first_name: &mut bool,) -> MakeInode {let name_entry = match self.done_vertices.entry(output_item.pos) {Entry::Occupied(e) => {debug!("pos already visited: {:?} {:?} {:?} {:?}",a,output_item.pos,e.get(),name_key);if e.get().0 != name_key {// The same inode has more than one name.self.conflicts.push(Conflict::MultipleNames {pos: output_item.pos,path: e.get().1.clone(),});}return MakeInode::AlreadyOutput;}Entry::Vacant(e) => {debug!("first visit {:?} {:?}", a, output_item.pos);e}};let name = if !*is_first_name {// Multiple inodes share the same name.if self.output_name_conflicts {let name = make_conflicting_name(&a, name_key);self.conflicts.push(Conflict::Name { path: name.clone() });name} else {debug!("not outputting {:?} {:?}", a, name_key);self.conflicts.push(Conflict::Name {path: a.to_string(),});return MakeInode::NameConflict;}} else {*is_first_name = false;a.to_string()};debug!("name = {:?} {:?}", name, name_key);let file_name = path::file_name(&name).unwrap();path::push(&mut output_item.path, file_name);name_entry.insert((name_key, output_item.path.clone()));MakeInode::Ok(name)}
if let Some((inode, _)) = output_item_inode {if !done_inodes.insert(inode) {
fn output_name<T: TreeMutTxnT+ ChannelMutTxnT+ GraphMutTxnT<GraphError = <T as TreeTxnT>::TreeError>+ Send+ Sync+ 'static,R: WorkingCopy + Clone + Send + Sync + 'static,P: ChangeStore + Send + Clone + 'static,>(&mut self,repo: &R,changes: &P,txn: &ArcTxn<T>,channel: &ChannelRef<T>,next_files: &mut HashMap<String, Vec<(Vertex<ChangeId>, OutputItem)>>,a: String,b: Vec<(Vertex<ChangeId>, OutputItem)>,) -> Result<(), OutputError<P::Error, T::TreeError, R::Error>> {let mut is_first_name = true;for (name_key, mut output_item) in b {debug!("name_key = {:?} {:?}", name_key, output_item);let name = match self.make_inode(&a, name_key, &mut output_item, &mut is_first_name) {MakeInode::Ok(file_name) => file_name,MakeInode::AlreadyOutput => continue,MakeInode::NameConflict => break,};let output_item_inode = {let txn = txn.read();if let Some(inode) = txn.get_revinodes(&output_item.pos, None)? {if !self.done_inodes.insert(*inode) {
}let name = if !is_first_name {if output_name_conflicts {let name = make_conflicting_name(&a, name_key);conflicts.push(Conflict::Name { path: name.clone() });name} else {debug!("not outputting {:?} {:?}", a, name_key);conflicts.push(Conflict::Name {path: a.to_string(),});break;}
Some((*inode, *txn.get_inodes(inode, None)?.unwrap()))
is_first_name = false;a.clone()};let file_name = path::file_name(&name).unwrap();path::push(&mut output_item.path, file_name);name_entry.insert((name_key, output_item.path.clone()));if let Some(ref mut tmp) = output_item.tmp {path::push(tmp, file_name);}let path = std::mem::replace(&mut output_item.path, String::new());let mut tmp = output_item.tmp.take();let inode = move_or_create::<T, R, P>(txn.clone(),&repo,&output_item,output_item_inode,&path,&mut tmp,&file_name,&mut actual_moves,salt,)?;debug!("inode = {:?}", inode);if next_prefix_basename.is_none() && is_first_none {let dead = {let txn_ = txn.read();let channel = channel.read();collect_dead_files(&*txn_, txn_.graph(&*channel), pending_change_id, inode)?};debug!("dead (line {}) = {:?}", line!(), dead);if !dead.is_empty() {let mut txn = txn.write();kill_dead_files::<T, R, P>(&mut *txn, &channel, &repo, &dead)?;}is_first_none = false;
None
if output_item.meta.is_dir() {
};let file_name = path::file_name(&name).unwrap();let mut tmp = output_item.tmp.take().map(|mut tmp| {path::push(&mut tmp, file_name);tmp});let path = std::mem::replace(&mut output_item.path, String::new());let inode = move_or_create::<T, R, P>(txn.clone(),&repo,&output_item,output_item_inode,&path,&mut tmp,&file_name,&mut self.actual_moves,self.salt,)?;debug!("inode = {:?}", inode);self.kill_dead_files::<_, _, P>(repo, txn, channel)?;if output_item.meta.is_dir() {if !path.is_empty() {
{let txn = txn.read();let channel = channel.read();collect_children(&*txn,&*changes,txn.graph(&*channel),output_item.pos,inode,&path,tmp.as_deref(),next_prefix_basename,&mut next_files,)?;}debug!("setting permissions for {:?}", path);
} else {if needs_output(repo, if_modified_after, &path) {work.push((output_item.clone(), path.clone(), tmp.clone()));} else {debug!("Not outputting {:?}", path)}
if output_item.is_zombie {conflicts.push(Conflict::ZombieFile {path: name.to_string(),})
let txn = txn.read();let channel = channel.read();collect_children(&*txn,&*changes,txn.graph(&*channel),output_item.pos,inode,&path,tmp.as_deref(),self.next_prefix_basename,next_files,)?;} else {if needs_output(repo, self.if_modified_after, &path) {self.work.push((output_item.clone(), path.clone(), tmp.clone()));} else {debug!("Not outputting {:?}", path)
std::mem::swap(&mut files, &mut next_files);}stop.store(true, std::sync::atomic::Ordering::Relaxed);let o = output_loop(repo, changes, txn, channel, work, stop, 0);for t in threads {conflicts.extend(t.join().unwrap()?.into_iter());}conflicts.extend(o?.into_iter());for (a, b) in actual_moves.iter() {repo.rename(a, b).map_err(OutputError::WorkingCopy)?
Ok(())
let mut name_buf = Vec::new();let FileMetadata {basename,metadata: perms,..} = changes.get_file_meta(|h| txn.get_external(&h).unwrap().map(|x| x.into()),
if name_vertex.start != name_vertex.end {debug!("name_vertex: {:?} {:?}", e, name_vertex);collect(txn,changes,channel,inode,path,tmp,prefix_basename,files,name_vertex,)?} else {let inode_pos = iter_adjacent(txn,channel,
&mut name_buf,).map_err(PristineOutputError::Changestore)?;debug!("filename: {:?} {:?}", perms, basename);let mut name = path.to_string();if let Some(next) = prefix_basename {if next != basename {continue;}}path::push(&mut name, basename);debug!("name_vertex: {:?} {:?}", e, name_vertex);let child = if let Some(child) = iter_adjacent(txn,channel,*name_vertex,EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,)?.next(){child?} else {let mut edge = None;
EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,)?.next().unwrap()?.dest();
if !e.flag().contains(EdgeFlags::PARENT) {edge = Some(e);break;}
debug!("e = {:?}", e);let name_vertex = txn.find_block(channel, e.dest()).unwrap();collect(txn,changes,channel,inode,path,tmp,prefix_basename,files,name_vertex,)?
let e = edge.unwrap();let mut f = std::fs::File::create("debug_output").unwrap();debug_root(txn, channel, e.dest().inode_vertex(), &mut f, false).unwrap();panic!("no child");};
}}Ok(())}
debug!("child: {:?}", child);let v = files.entry(name).or_insert_with(Vec::new);v.push((
fn collect<T: GraphTxnT, P: ChangeStore>(txn: &T,changes: &P,channel: &T::Graph,inode: Inode,path: &str,tmp: Option<&str>,prefix_basename: Option<&str>,files: &mut HashMap<String, Vec<(Vertex<ChangeId>, OutputItem)>>,name_vertex: &Vertex<ChangeId>,) -> Result<(), PristineOutputError<P::Error, T::GraphError>> {let mut name_buf = Vec::new();let FileMetadata {basename,metadata: perms,..} = changes.get_file_meta(|h| txn.get_external(&h).unwrap().map(|x| x.into()),
OutputItem {parent: inode,path: path.to_string(),tmp: tmp.map(String::from),meta: perms,pos: child.dest(),is_zombie: is_zombie(txn, channel, child.dest())?,},));
&mut name_buf,).map_err(PristineOutputError::Changestore)?;debug!("filename: {:?} {:?}", perms, basename);let mut name = path.to_string();if let Some(next) = prefix_basename {if next != basename {return Ok(());}
path::push(&mut name, basename);let child = if let Some(child) = iter_adjacent(txn,channel,*name_vertex,EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,)?.next(){child?} else {let mut edge = None;for e in iter_adjacent(txn,channel,*name_vertex,EdgeFlags::FOLDER,EdgeFlags::all(),)? {let e = e?;if !e.flag().contains(EdgeFlags::PARENT) {edge = Some(e);break;}}let e = edge.unwrap();let mut f = std::fs::File::create("debug_output").unwrap();debug_root(txn, channel, e.dest().inode_vertex(), &mut f, false).unwrap();panic!("no child");};debug!("child: {:?}", child);let v = files.entry(name).or_insert_with(Vec::new);v.push((*name_vertex,OutputItem {parent: inode,path: path.to_string(),tmp: tmp.map(String::from),meta: perms,pos: child.dest(),is_zombie: is_zombie(txn, channel, child.dest())?,},));
let child = match self.adj.next()? {Ok(child) => child,Err(e) => return Some(Err(e.0)),
let dest = loop {debug!("adj2 = {:?}", self.adj2.is_some());if let Some(mut adj2) = self.adj2.take() {match adj2.next() {None => {}Some(Ok(ch)) => {self.adj2 = Some(adj2);break self.txn.find_block(self.channel, ch.dest()).unwrap();}Some(Err(e)) => return Some(Err(e.0)),}}match self.adj.next() {Some(Ok(child)) => {let d = self.txn.find_block(self.channel, child.dest()).unwrap();if d.start == d.end {match iter_adjacent(self.txn,self.channel,*d,EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,).and_then(|mut it| it.next().unwrap()).and_then(|x| {iter_adjacent(self.txn,self.channel,x.dest().inode_vertex(),EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,)}) {Ok(adj) => self.adj2 = Some(adj),Err(e) => return Some(Err(e.0)),}} else {break d;}}Some(Err(e)) => return Some(Err(e.0)),None => return None,}
let FileMetadata {basename: name,metadata: perms,..} = FileMetadata::read(&change_contents[n.start.0.into()..n.end.0.into()]);
let (name, perms) = if n.start == n.end {("", InodeMetadata::DIR)} else {let FileMetadata {basename: name,metadata: perms,..} = FileMetadata::read(&change_contents[n.start.0.into()..n.end.0.into()]);(name, perms)};