Partial push and pull (WARNING: breaks the existing protocol)
[?]
Dec 19, 2020, 5:01 PM
MU5GSJAW65PEG3BRYUKZ7O37BPHW3MOX3S5E2RFOXKGUOJEEDQ5ACDependencies
- [2]
VO5OQW4WRemoving anyhow in libpijul - [3]
X6YFD4WVDo not download changes if we already have them - [4]
FE5ES6Q4Stop pushing/pulling if the remote returns an error - [5]
SLJ3OHD4unrecord: show list of changes if none were given as arguments - [6]
KDF6FJRVbigger clippy refactors - [7]
7L32EXDWWhen pulling, treating the pending change as a local change - [8]
5QTMRUXNFixing a race condition between progress bars - [9]
YAJAXIV5Unrecording changes atomically - [10]
UDHP4ZVBFixing SSH asynchronicity issues - [11]
K6GWUOD5Styling progress bars - [12]
Q45QHPO4Feedback on network stuff - [13]
SXEYMYF7Fixing the bad changes in history (unfortunately, by rebooting). - [14]
AEPEFS7OWrite help for each argument - [15]
WLUID7NADo not block when downloading more than 100 changes over SSH - [16]
5HF7C67Mpush/pull: fixed "changes" arguments - [17]
WZVCLZKYaddress clippy lints - [18]
5DVRL6MFHard-unrecord - [19]
4H2XTVJ2Fix some mistakes in the docs - [20]
PCEJFKFXProgress bar for upload and apply - [21]
QWD7UE76push/pull: rename `channel` option - [22]
367UBQ6KForwarding SSH stderr, and progress bar for push - [23]
76PCXGMLPushing to, and pulling from the local repository - [24]
VQPAUKBQchannel switch as an alias to reset - [25]
BAUL3WR2Format, versions, README - [26]
I52XSRUHMassive cleanup, and simplification - [27]
HXEIH4UQPulling more than 100 changes at once - [28]
L4JXJHWXpijul/*: reorganize imports and remove extern crate - [29]
AN7IDX26pijul: added ChangesNotFound error variant - [30]
FBXYP7QMForgot to add remote::http - [*]
BBKV6VMNFixing push/pull messages, and do not reverse the changes to download/upload - [*]
M5FK3ABTComplete dependencies when pushing and pulling
Change contents
- edit in pijul/src/remote/ssh.rs at line 1
use std::collections::HashSet; - edit in pijul/src/remote/ssh.rs at line 12
use libpijul::pristine::Position; - replacement in pijul/src/remote/ssh.rs at line 260
sender: tokio::sync::mpsc::Sender<Option<(u64, Hash, Merkle)>>,sender: tokio::sync::mpsc::Sender<Option<super::ListLine>>, - replacement in pijul/src/remote/ssh.rs at line 477
let (n, h, m) = parse_line(l)?;sender.send(Some((n, h, m))).await.unwrap_or(());sender.send(parse_line(l).ok()).await.unwrap_or(()) - replacement in pijul/src/remote/ssh.rs at line 683
) -> Result<(), anyhow::Error> {) -> Result<HashSet<Position<Hash>>, anyhow::Error> { - replacement in pijul/src/remote/ssh.rs at line 691
write!(command, " {}", p).unwrap()write!(command, " {:?}", p).unwrap() - replacement in pijul/src/remote/ssh.rs at line 695
debug!("waiting ssh");while let Some(Some((n, h, m))) = receiver.recv().await {txn.put_remote(remote, n, (h, m))?;debug!("waiting ssh, command: {:?}", std::str::from_utf8(&command));let mut result = HashSet::new();while let Some(Some(m)) = receiver.recv().await {match m {super::ListLine::Change { n, h, m } => {txn.put_remote(remote, n, (h, m))?;}super::ListLine::Position(pos) => {result.insert(pos);}} - replacement in pijul/src/remote/ssh.rs at line 710
debug!("no msg");Ok(())debug!("no msg, result = {:?}", result);Ok(result) - edit in pijul/src/remote/mod.rs at line 1
use std::collections::HashSet; - edit in pijul/src/remote/mod.rs at line 5
use anyhow::bail; - replacement in pijul/src/remote/mod.rs at line 168
) -> Result<Option<RemoteRef<T>>, anyhow::Error> {) -> Result<Option<(HashSet<Position<Hash>>, RemoteRef<T>)>, anyhow::Error> { - replacement in pijul/src/remote/mod.rs at line 195
self.download_changelist(txn, &mut remote, n, path).await?;let paths = self.download_changelist(txn, &mut remote, n, path).await?; - replacement in pijul/src/remote/mod.rs at line 203
Ok(Some(remote))Ok(Some((paths, remote))) - replacement in pijul/src/remote/mod.rs at line 373
) -> Result<(), anyhow::Error> {) -> Result<HashSet<Position<Hash>>, anyhow::Error> { - replacement in pijul/src/remote/mod.rs at line 377[6.63964]→[6.63964:64637](∅→∅),[6.64637]→[6.64637:64787](∅→∅),[6.64787]→[6.64787:64911](∅→∅),[6.64911]→[6.64911:65045](∅→∅),[6.65045]→[6.65045:65068](∅→∅),[6.65068]→[6.65068:65082](∅→∅),[6.65082]→[6.2257:2308](∅→∅)
RemoteRepo::Http(ref h) => {let url = h.url.clone() + "/" + DOT_DIR;let from_ = from.to_string();let mut query = vec![("changelist", &from_), ("channel", &h.channel)];for p in paths.iter() {query.push(("path", p));}let res = h.client.get(&url).query(&query).send().await?;if !res.status().is_success() {return Err((crate::Error::Http {status: res.status(),}).into());}let resp = res.bytes().await?;if let Ok(data) = std::str::from_utf8(&resp) {for l in data.lines() {if !l.is_empty() {let (n, h, m) = parse_line(l)?;txn.put_remote(remote, n, (h, m))?;} else {break;}}}Ok(())}RemoteRepo::LocalChannel(_) => Ok(()),RemoteRepo::Http(ref h) => h.download_changelist(txn, remote, from, paths).await,RemoteRepo::LocalChannel(_) => Ok(HashSet::new()), - edit in pijul/src/remote/mod.rs at line 429
inodes: &HashSet<Position<Hash>>, - replacement in pijul/src/remote/mod.rs at line 431
) -> Result<(), anyhow::Error> {) -> Result<Vec<Hash>, anyhow::Error> { - edit in pijul/src/remote/mod.rs at line 468
let mut to_apply_inodes = Vec::new(); - edit in pijul/src/remote/mod.rs at line 484
let touches_inodes = inodes.is_empty()|| {debug!("inodes = {:?}", inodes);use libpijul::changestore::ChangeStore;let changes = repo.changes.get_changes(h)?;changes.iter().any(|c| {c.iter().any(|c| {let inode = c.inode();debug!("inode = {:?}", inode);if let Some(h) = inode.change {inodes.contains(&Position {change: h,pos: inode.pos,})} else {false}})})}|| { inodes.iter().any(|i| i.change == *h) };if touches_inodes {to_apply_inodes.push(*h);} else {continue;} - replacement in pijul/src/remote/mod.rs at line 534
Ok(())Ok(to_apply_inodes) - replacement in pijul/src/remote/mod.rs at line 612
self.pull(repo, txn, channel, &to_unrecord, false).await?;self.pull(repo, txn, channel, &to_unrecord, &HashSet::new(), false).await?; - replacement in pijul/src/remote/mod.rs at line 633
self.pull(repo, txn, channel, &to_pull, true).await?;self.pull(repo, txn, channel, &to_pull, &HashSet::new(), true).await?; - replacement in pijul/src/remote/mod.rs at line 709
let remote_changes = selflet (inodes, remote_changes) = self - replacement in pijul/src/remote/mod.rs at line 717
self.pull(repo, txn, local_channel, &pullable, true).awaitself.pull(repo, txn, local_channel, &pullable, &inodes, true).await?;Ok(()) - replacement in pijul/src/remote/mod.rs at line 723
fn parse_line(data: &str) -> Result<(u64, Hash, Merkle), anyhow::Error> {use libpijul::pristine::{ChangePosition, Position};use regex::Regex;lazy_static! {static ref CHANGELIST_LINE: Regex =Regex::new(r#"(?P<num>[0-9]+)\.(?P<hash>[A-Za-z0-9]+)\.(?P<merkle>[A-Za-z0-9]+)"#).unwrap();static ref PATHS_LINE: Regex =Regex::new(r#"(?P<hash>[A-Za-z0-9]+)\.(?P<num>[0-9]+)"#).unwrap();}enum ListLine {Change { n: u64, h: Hash, m: Merkle },Position(Position<Hash>),}fn parse_line(data: &str) -> Result<ListLine, anyhow::Error> { - replacement in pijul/src/remote/mod.rs at line 740
let mut it = data.split('.');let n = if let Some(n) = it.next().and_then(|n| n.parse().ok()) {n} else {return Err((Error::ProtocolError {line: data.as_bytes().to_vec(),}).into());};debug!("n = {:?}", n);let h = if let Some(h) = it.next().and_then(|h| Hash::from_base32(h.as_bytes())) {h} else {return Err((Error::ProtocolError {line: data.as_bytes().to_vec(),}).into());};debug!("h = {:?}", h);let m = if let Some(m) = it.next().and_then(|m| {debug!("m = {:?}", m);Merkle::from_base32(m.as_bytes())}) {m} else {return Err((Error::ProtocolError {line: data.as_bytes().to_vec(),}).into());};debug!("m = {:?}", m);if it.next().is_some() {return Err((Error::ProtocolError {line: data.as_bytes().to_vec(),}).into());if let Some(caps) = CHANGELIST_LINE.captures(data) {if let (Some(h), Some(m)) = (Hash::from_base32(caps.name("hash").unwrap().as_str().as_bytes()),Merkle::from_base32(caps.name("merkle").unwrap().as_str().as_bytes()),) {return Ok(ListLine::Change {n: caps.name("num").unwrap().as_str().parse()?,h,m,});}}if let Some(caps) = PATHS_LINE.captures(data) {return Ok(ListLine::Position(Position {change: Hash::from_base32(caps.name("hash").unwrap().as_str().as_bytes()).unwrap(),pos: ChangePosition(caps.name("num").unwrap().as_str().parse().unwrap()),})); - replacement in pijul/src/remote/mod.rs at line 758
Ok((n, h, m))bail!("Protocol error, offending line: {:?}", data) - edit in pijul/src/remote/local.rs at line 1
use std::collections::HashSet; - replacement in pijul/src/remote/local.rs at line 5
use libpijul::pristine::{Base32, Hash, Merkle, MutTxnT, TxnT};use libpijul::pristine::{Base32, Hash, Merkle, MutTxnT, Position, TxnT}; - replacement in pijul/src/remote/local.rs at line 47
) -> Result<(), anyhow::Error> {) -> Result<HashSet<Position<Hash>>, anyhow::Error> { - replacement in pijul/src/remote/local.rs at line 54
return Ok(());return Ok(HashSet::new()); - replacement in pijul/src/remote/local.rs at line 56
let mut paths_ = Vec::new();let mut paths_ = HashSet::new();let mut result = HashSet::new(); - replacement in pijul/src/remote/local.rs at line 60
paths_.push(p)debug!("p = {:?}", p);result.insert(Position {change: remote_txn.get_external(p.change).unwrap(),pos: p.pos,});paths_.insert(p);paths_.extend(libpijul::fs::iter_graph_descendants(&remote_txn,&remote_channel.borrow(),p,)); - edit in pijul/src/remote/local.rs at line 73
debug!("paths_ = {:?}", paths_); - replacement in pijul/src/remote/local.rs at line 92
Ok(())Ok(result) - edit in pijul/src/remote/http.rs at line 1
use std::collections::HashSet; - replacement in pijul/src/remote/http.rs at line 6
use libpijul::pristine::Base32;use libpijul::pristine::{Base32, MutTxnT, Position};use libpijul::{Hash, RemoteRef}; - edit in pijul/src/remote/http.rs at line 113
pub async fn download_changelist<T: MutTxnT>(&self,txn: &mut T,remote: &mut RemoteRef<T>,from: u64,paths: &[String],) -> Result<HashSet<Position<Hash>>, anyhow::Error> {let url = self.url.clone() + "/" + super::DOT_DIR;let from_ = from.to_string();let mut query = vec![("changelist", &from_), ("channel", &self.channel)];for p in paths.iter() {query.push(("path", p));}let res = self.client.get(&url).query(&query).send().await?;if !res.status().is_success() {return Err((crate::Error::Http {status: res.status(),}).into());}let resp = res.bytes().await?;let mut result = HashSet::new();if let Ok(data) = std::str::from_utf8(&resp) {for l in data.lines() {if !l.is_empty() {match super::parse_line(l)? {super::ListLine::Change { n, m, h } => {txn.put_remote(remote, n, (h, m))?;}super::ListLine::Position(pos) => {result.insert(pos);}}} else {break;}}}Ok(result)} - edit in pijul/src/main.rs at line 166
#[error("Ambiguous path: {:?}", path)]AmbiguousPath { path: String }, - edit in pijul/src/main.rs at line 182
#[error("Changes not found: {:?}", hashes)]ChangesNotFound { hashes: Vec<String> }, - edit in pijul/src/commands/reset.rs at line 100
let now = std::time::Instant::now(); - replacement in pijul/src/commands/reset.rs at line 122
txn.commit()?txn.commit()?;debug!("now = {:?}", now.elapsed()); - edit in pijul/src/commands/reset.rs at line 125
let locks = libpijul::TIMERS.lock().unwrap();debug!("retrieve: {:?}, graph: {:?}, output: {:?}",locks.alive_retrieve, locks.alive_graph, locks.alive_output,); - edit in pijul/src/commands/pushpull.rs at line 6
use anyhow::bail; - replacement in pijul/src/commands/pushpull.rs at line 73
path: Option<String>,path: Vec<String>, - replacement in pijul/src/commands/pushpull.rs at line 103
path: Option<String>,path: Vec<String>, - replacement in pijul/src/commands/pushpull.rs at line 129
return Err(crate::Error::MissingRemote.into());bail!("Missing remote"); - replacement in pijul/src/commands/pushpull.rs at line 154[6.115611]→[6.115611:115664](∅→∅),[6.115664]→[6.0:20](∅→∅),[6.20]→[6.115696:115743](∅→∅),[6.115696]→[6.115696:115743](∅→∅),[6.1778]→[6.115743:115823](∅→∅),[6.115743]→[6.115743:115823](∅→∅)
let mut paths = if let Some(p) = self.path {vec![p]} else {vec![]};let remote_changes = remote.update_changelist(&mut txn, &paths).await?;let remote_changes = remote.update_changelist(&mut txn, &self.path).await?; - replacement in pijul/src/commands/pushpull.rs at line 157
let path = if let Some(path) = paths.pop() {let (p, ambiguous) = txn.follow_oldest_path(&repo.changes, &channel, &path)?;let mut paths = HashSet::new();for path in self.path.iter() {let (p, ambiguous) = txn.follow_oldest_path(&repo.changes, &channel, path)?; - replacement in pijul/src/commands/pushpull.rs at line 161
return Err((crate::Error::AmbiguousPath { path }).into());bail!("Ambiguous path: {:?}", path) - replacement in pijul/src/commands/pushpull.rs at line 163
Some(p)} else {None};paths.insert(p);paths.extend(libpijul::fs::iter_graph_descendants(&txn,&channel.borrow(),p,));} - replacement in pijul/src/commands/pushpull.rs at line 173
if let Some(ref remote_changes) = remote_changes {if let Some((_, ref remote_changes)) = remote_changes { - replacement in pijul/src/commands/pushpull.rs at line 179
if let Some(ref p) = path {if txn.get_touched_files(*p, Some(h_int)).is_some() {to_upload.push(h)if paths.is_empty() {to_upload.push(h)} else {for p in paths.iter() {if txn.get_touched_files(*p, Some(h_int)).is_some() {to_upload.push(h);break;} - edit in pijul/src/commands/pushpull.rs at line 188
} else {to_upload.push(h) - replacement in pijul/src/commands/pushpull.rs at line 195
if let Some(ref p) = path {if txn.get_touched_files(*p, Some(h_int)).is_some() {to_upload.push(h)if paths.is_empty() {to_upload.push(h)} else {for p in paths.iter() {if txn.get_touched_files(*p, Some(h_int)).is_some() {to_upload.push(h);break;} - edit in pijul/src/commands/pushpull.rs at line 204
} else {to_upload.push(h) - replacement in pijul/src/commands/pushpull.rs at line 236
return Err((crate::Error::ChangesNotFound { hashes: not_found }).into());bail!("Changes not found: {:?}", not_found) - edit in pijul/src/commands/pushpull.rs at line 245[32.77][33.69]
let remote_changes = remote_changes.map(|x| x.1); - replacement in pijul/src/commands/pushpull.rs at line 284
return Err(crate::Error::MissingRemote.into());bail!("Missing remote") - replacement in pijul/src/commands/pushpull.rs at line 301[6.118434]→[6.118434:118489](∅→∅),[6.118489]→[6.6122:6203](∅→∅),[6.6203]→[6.118578:118637](∅→∅),[6.118578]→[6.118578:118637](∅→∅),[6.2097]→[6.118637:118721](∅→∅),[6.118637]→[6.118637:118721](∅→∅)
let to_download = if self.changes.is_empty() {let mut paths = if let Some(p) = self.path {vec![p]} else {vec![]};let remote_changes = remote.update_changelist(&mut txn, &paths).await?;let mut inodes: HashSet<libpijul::pristine::Position<libpijul::Hash>> = HashSet::new();let mut to_download = if self.changes.is_empty() {let remote_changes = remote.update_changelist(&mut txn, &self.path).await?; - replacement in pijul/src/commands/pushpull.rs at line 306
if let Some(ref remote_changes) = remote_changes {if let Some((inodes_, remote_changes)) = remote_changes {inodes.extend(inodes_.into_iter()); - replacement in pijul/src/commands/pushpull.rs at line 316
let path = if let Some(path) = paths.pop() {let (p, ambiguous) = txn.follow_oldest_path(&repo.changes, &channel, &path)?;let mut inodes_ = HashSet::new();for path in self.path.iter() {let (p, ambiguous) = txn.follow_oldest_path(&repo.changes, &channel, path)?; - replacement in pijul/src/commands/pushpull.rs at line 320
return Err((crate::Error::AmbiguousPath { path }).into());bail!("Ambiguous path: {:?}", path) - replacement in pijul/src/commands/pushpull.rs at line 322
Some(p)} else {None};inodes_.insert(p);inodes_.extend(libpijul::fs::iter_graph_descendants(&txn,&channel.borrow(),p,));}inodes.extend(inodes_.iter().map(|x| libpijul::pristine::Position {change: txn.get_external(x.change).unwrap(),pos: x.pos,})); - replacement in pijul/src/commands/pushpull.rs at line 344
if let Some(ref p) = path {if txn.get_touched_files(*p, Some(h_int)).is_some() {to_download.push(h)}} else {if inodes_.is_empty()|| inodes_.iter().any(|&inode| {txn.get_rev_touched_files(h_int, Some(inode)).is_some()}){ - edit in pijul/src/commands/pushpull.rs at line 364
debug!("recording");let hash = super::pending(&mut txn, &mut channel, &mut repo)?;let to_download = remote.pull(&mut repo,&mut txn,&mut channel,&mut to_download,&inodes,self.all,).await?; - replacement in pijul/src/commands/pushpull.rs at line 382[6.119504]→[6.119504:119533](∅→∅),[6.119533]→[6.1503:1574](∅→∅),[6.1574]→[6.119907:119922](∅→∅),[6.119907]→[6.119907:119922](∅→∅),[6.119922]→[3.951:1028](∅→∅),[3.1028]→[6.120101:120122](∅→∅),[6.120101]→[6.120101:120122](∅→∅)
debug!("recording");let hash = super::pending(&mut txn, &mut channel, &mut repo)?;remote.pull(&mut repo, &mut txn, &mut channel, &to_download, self.all).await?; - replacement in pijul/src/commands/pushpull.rs at line 421
txn.output_repository_no_pending(&mut repo.working_copy,&repo.changes,&mut channel,"",true,)?;debug!("inodes = {:?}", inodes);if inodes.is_empty() {txn.output_repository_no_pending(&mut repo.working_copy,&repo.changes,&mut channel,"",true,)?;} else {for i in inodes {let i = if let Some(change) = txn.get_internal(i.change) {libpijul::pristine::Position { change, pos: i.pos }} else {continue;};let (path, _) =libpijul::fs::find_path(&repo.changes, &txn, &channel.borrow(), false, i)?;debug!("path = {:?}", path);txn.output_repository_no_pending(&mut repo.working_copy,&repo.changes,&mut channel,&path,true,)?;}} - replacement in pijul/src/commands/pushpull.rs at line 512
return Err((crate::Error::MissingDep { h: *n }).into());bail!("Missing dependency: {:?}", n) - replacement in pijul/src/commands/protocol.rs at line 1
use std::collections::HashMap;use std::collections::{HashMap, HashSet}; - replacement in pijul/src/commands/protocol.rs at line 31
static ref CHANGELIST_PATHS: Regex = Regex::new(r#""((\\")|[^"])+""#).unwrap();static ref CHANGELIST_PATHS: Regex = Regex::new(r#""(((\\")|[^"])+)""#).unwrap(); - replacement in pijul/src/commands/protocol.rs at line 97
let mut paths = Vec::new();let mut paths = HashSet::new();debug!("cap[3] = {:?}", &cap[3]); - replacement in pijul/src/commands/protocol.rs at line 100
let s: String = r[0].parse().unwrap();let s: String = r[1].replace("\\\"", "\""); - replacement in pijul/src/commands/protocol.rs at line 109
paths.push(p)let h = txn.get_external(p.change).unwrap();writeln!(o, "{}.{}", h.to_base32(), p.pos.0)?;paths.insert(p);paths.extend(libpijul::fs::iter_graph_descendants(&txn,&channel.borrow(),p,)); - edit in pijul/src/commands/protocol.rs at line 124
debug!("paths = {:?}", paths); - replacement in pijul/src/commands/protocol.rs at line 128
|| paths.iter().any(|x| txn.get_touched_files(*x, Some(h_int)).is_some())|| paths.iter().any(|x| {x.change == h_int || txn.get_touched_files(*x, Some(h_int)).is_some()}) - edit in libpijul/src/pristine/mod.rs at line 1348
debug!("registering change {:?}", hash); - replacement in libpijul/src/pristine/mod.rs at line 1352
debug!(target:"libpijul::register_change", "dep = {:?}", dep);debug!("dep = {:?}", dep); - replacement in libpijul/src/pristine/mod.rs at line 1354
debug!(target:"libpijul::register_change", "{:?} depends on {:?}", internal, dep_internal);debug!("{:?} depends on {:?}", internal, dep_internal); - replacement in libpijul/src/pristine/mod.rs at line 1359
let inode = match *hunk {Atom::NewVertex(NewVertex { ref inode, .. }) => inode,Atom::EdgeMap(EdgeMap { ref inode, .. }) => inode,let (inode, pos) = match *hunk {Atom::NewVertex(NewVertex {ref inode,ref flag,ref start,ref end,..}) => {if flag.contains(EdgeFlags::FOLDER) && start == end {(inode, Some(*start))} else {(inode, None)}}Atom::EdgeMap(EdgeMap { ref inode, .. }) => (inode, None), - replacement in libpijul/src/pristine/mod.rs at line 1382
debug!(target:"libpijul::register_change", "touched: {:?} {:?}", inode, internal);debug!("touched: {:?} {:?}", inode, internal); - edit in libpijul/src/pristine/mod.rs at line 1385
if let Some(pos) = pos {let inode = Position {change: internal,pos,};txn.put_touched_files(inode, internal)?;txn.put_rev_touched_files(internal, inode)?;} - edit in libpijul/src/fs.rs at line 20
use std::collections::HashSet; - edit in libpijul/src/fs.rs at line 427
}/// An iterator over the descendants of an/// inode key in the graph.////// Constructed using/// [`iter_graph_descendants`](fn.iter_graph_descendants.html).pub struct GraphDescendants<'txn, 'channel, T: TxnT> {txn: &'txn T,channel: &'channel Channel<T>,stack: Vec<AdjacentIterator<'txn, T>>,visited: HashSet<Position<ChangeId>>, - edit in libpijul/src/fs.rs at line 441
impl<'txn, 'channel, T: TxnT> Iterator for GraphDescendants<'txn, 'channel, T> {type Item = Position<ChangeId>;fn next(&mut self) -> Option<Self::Item> {if let Some(mut adj) = self.stack.pop() {if let Some(child) = adj.next() {self.stack.push(adj);let dest = find_block(self.txn, &self.channel, child.dest).unwrap();let grandchild = iter_adjacent(self.txn,&self.channel,dest,EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,).next().unwrap();if self.visited.insert(grandchild.dest) {self.stack.push(iter_adjacent(self.txn,&self.channel,grandchild.dest.inode_vertex(),EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,))}return Some(grandchild.dest);} else {// No child left, actually pop.}}None}}/// Returns a list of files under the given key. The root key is/// [`pristine::Vertex::ROOT`](../pristine/constant.Vertex::ROOT.html).pub fn iter_graph_descendants<'txn, 'channel, T: TxnT>(txn: &'txn T,channel: &'channel Channel<T>,key: Position<ChangeId>,) -> GraphDescendants<'txn, 'channel, T> {GraphDescendants {stack: vec![iter_adjacent(txn,&channel,key.inode_vertex(),EdgeFlags::FOLDER,EdgeFlags::FOLDER | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,)],visited: HashSet::new(),txn,channel,}} - edit in libpijul/src/changestore/mod.rs at line 46
}fn get_changes(&self,hash: &Hash,) -> Result<Vec<crate::change::Record<Option<Hash>, crate::change::Local>>, Self::Error> {Ok(self.get_change(hash)?.hashed.changes)