Fixing log -- filters, along with performance improvements
Dependencies
- [2]
6F6AAHK4Simplifying pijul::commands::log, and fixing Broken Pipe errors - [3]
SMMBFECLConverting to the new patch format "online" - [4]
OU6JOR3CAdd path filtering for log, add json output for log - [5]
F2S6XETOFixing log --hash-only - [6]
SXEYMYF7Fixing the bad changes in history (unfortunately, by rebooting). - [7]
L4JXJHWXpijul/*: reorganize imports and remove extern crate
Change contents
- replacement in pijul/src/commands/log.rs at line 2
use std::collections::{HashMap, HashSet};use std::collections::HashMap; - replacement in pijul/src/commands/log.rs at line 128
) -> Result<Vec<libpijul::Inode>, Error<E>> {) -> Result<Vec<(libpijul::Inode,Option<libpijul::pristine::Position<libpijul::ChangeId>>,)>,Error<E>,> { - replacement in pijul/src/commands/log.rs at line 158
Ok(Some(s)) => inodes.push(libpijul::fs::find_inode(txn, s)?),Ok(Some(s)) => {let inode = libpijul::fs::find_inode(txn, s)?;let inode_position = txn.get_inodes(&inode, None)?;inodes.push((inode, inode_position.cloned()))} - edit in pijul/src/commands/log.rs at line 169[3.2841]→[3.2841:3001](∅→∅),[3.3001]→[2.3298:3355](∅→∅),[2.3355]→[3.3070:3111](∅→∅),[3.3070]→[3.3070:3111](∅→∅),[3.3111]→[2.3356:3405](∅→∅),[2.3405]→[3.3165:3417](∅→∅),[3.3165]→[3.3165:3417](∅→∅),[3.3417]→[2.3406:3436](∅→∅),[2.3436]→[3.3489:3787](∅→∅),[3.3489]→[3.3489:3787](∅→∅),[3.3787]→[2.3437:3573](∅→∅),[2.3573]→[3.4336:4511](∅→∅),[3.4336]→[3.4336:4511](∅→∅)
/// Given a list of path filters which represent the files/directories for which/// the user wants to see the logs, find the subset of relevant change hashes.fn filtered_hashes<E: std::error::Error>(txn: &Txn,path: &Path,filters: &[String],) -> Result<HashSet<libpijul::Hash>, Error<E>> {let inodes = get_inodes(txn, path, filters)?;let mut hashes = HashSet::<libpijul::Hash>::new();for inode in inodes {// The Position<ChangeId> for the file Inode.let inode_position = match txn.get_inodes(&inode, None)? {None => continue,Some(p) => p,};for pair in txn.iter_touched(inode_position)? {let (position, touched_change_id) = pair?;// Push iff the file ChangeId for this element matches that of the file Inodeif &position.change == &inode_position.change {let ser_h = txn.get_external(touched_change_id)?.unwrap();hashes.insert(libpijul::Hash::from(*ser_h));} else {// We've gone past the relevant subset of changes in the iterator.break;}}}Ok(hashes)} - edit in pijul/src/commands/log.rs at line 312
// If the user applied path filters, figure out what change hashes// are to be logged.let mut requested_hashes = filtered_hashes(&self.txn,self.repo_path.as_ref(),self.cmd.filters.as_slice(),)?; - replacement in pijul/src/commands/log.rs at line 313[3.10703]→[3.10703:11547](∅→∅),[3.11547]→[2.3650:3695](∅→∅),[2.3695]→[3.11678:12071](∅→∅),[3.11678]→[3.11678:12071](∅→∅)
// Get the (Hash, Merkle) pairs for the portion of reverse_log// that are between offset and limit.let hs = self.txn.reverse_log(&*self.channel_ref.read(), None)?.skip(self.offset).take(self.limit).map(|res| {res.map(|(_, (ser_h, ser_m))| {(libpijul::Hash::from(ser_h), libpijul::Merkle::from(ser_m))})});for pr in hs {let (h, mrk) = pr?;if (self.cmd.filters.is_empty()) || requested_hashes.remove(&h) {// If there were no path filters applied, OR is this was one of the hashes// marked by the file filters that were appliedlet entry = self.mk_log_entry(&mut authors, &mut id_path, h, Some(mrk))?;f(entry).map_err(Error::E)?;} else if requested_hashes.is_empty() {// If the user applied path filters, but the relevant change hashes// have been exhausted, we can break early.break;} else {// The user applied path filters; this wasn't a hit, but// there are still hits to be logged.continue;let inodes = get_inodes(&self.txn, &self.repo_path, &self.cmd.filters)?;let mut offset = self.offset;let mut limit = self.limit;for pr in self.txn.reverse_log(&*self.channel_ref.read(), None)? {let (_, (h, mrk)) = pr?;let cid = self.txn.get_internal(h)?.unwrap();let mut is_in_filters = inodes.is_empty();for (_, position) in inodes.iter() {if let Some(position) = position {is_in_filters = self.txn.get_touched_files(position, Some(cid))?.is_some();if is_in_filters {break;}}}if is_in_filters {if offset == 0 && limit > 0 {// If there were no path filters applied, OR is this was one of the hashes// marked by the file filters that were appliedlet entry =self.mk_log_entry(&mut authors, &mut id_path, h.into(), Some(mrk.into()))?;f(entry).map_err(Error::E)?;limit -= 1} else if limit > 0 {offset -= 1} else {break;}