edit in pijul/src/remote/ssh.rs at line 19
replacement in pijul/src/remote/ssh.rs at line 299
[11.255]→[11.255:332](∅→∅) − sender: Option<tokio::sync::oneshot::Sender<Option<(u64, Merkle)>>>,
+ sender: Option<tokio::sync::oneshot::Sender<Option<(u64, Merkle, Merkle)>>>,
replacement in pijul/src/remote/ssh.rs at line 305
[11.353]→[11.353:410](∅→∅) − sender: Option<tokio::sync::mpsc::Sender<Hash>>,
+ sender: Option<tokio::sync::mpsc::Sender<CS>>,
replacement in pijul/src/remote/ssh.rs at line 310
[11.29]→[11.492:539](∅→∅),
[11.492]→[11.492:539](∅→∅) − hashes: Vec<libpijul::pristine::Hash>,
replacement in pijul/src/remote/ssh.rs at line 456
[11.1995]→[11.1995:2117](∅→∅) − debug!("s = {:?}", s);
− if let (Some(n), Some(m)) = (s.next(), s.next()) {
+ if let (Some(n), Some(m), Some(m2)) = (s.next(), s.next(), s.next()) {
replacement in pijul/src/remote/ssh.rs at line 459
[11.2208]→[11.2208:2308](∅→∅) − .send(Some((n, Merkle::from_base32(m.trim().as_bytes()).unwrap())))
+ .send(Some((
+ n,
+ Merkle::from_base32(m.trim().as_bytes()).unwrap(),
+ Merkle::from_base32(m2.trim().as_bytes()).unwrap(),
+ )))
replacement in pijul/src/remote/ssh.rs at line 512
[11.72]→[11.72:276](∅→∅),
[11.276]→[11.3706:3847](∅→∅),
[11.3706]→[11.3706:3847](∅→∅),
[11.3847]→[11.277:556](∅→∅) − libpijul::changestore::filesystem::push_filename(
− final_path,
− &hashes[*current],
− );
− final_path.set_extension("change");
− debug!("moving {:?} to {:?}", path, final_path);
− std::fs::create_dir_all(&final_path.parent().unwrap())?;
− let r = std::fs::rename(&path, &final_path);
− libpijul::changestore::filesystem::pop_filename(final_path);
− r?;
+ match hashes[*current] {
+ CS::Change(ref h) => {
+ libpijul::changestore::filesystem::push_filename(final_path, h);
+ debug!("moving {:?} to {:?}", path, final_path);
+ std::fs::create_dir_all(&final_path.parent().unwrap())?;
+ let r = std::fs::rename(&path, &final_path);
+ libpijul::changestore::filesystem::pop_filename(final_path);
+ r?;
+ }
+ CS::State(h) => {
+ libpijul::changestore::filesystem::push_tag_filename(
+ final_path, &h,
+ );
+ debug!("moving {:?} to {:?}", path, final_path);
+ std::fs::create_dir_all(&final_path.parent().unwrap())?;
+ let r = std::fs::rename(&path, &final_path);
+ libpijul::changestore::filesystem::pop_filename(final_path);
+ r?;
+ }
+ }
replacement in pijul/src/remote/ssh.rs at line 737
[11.36194]→[11.36194:36250](∅→∅) − ) -> Result<Option<(u64, Merkle)>, anyhow::Error> {
+ ) -> Result<Option<(u64, Merkle, Merkle)>, anyhow::Error> {
replacement in pijul/src/remote/ssh.rs at line 889
[11.528]→[11.91:184](∅→∅) − super::ListLine::Change { n, h, m, is_tagged } => f(a, n, h, m, is_tagged)?,
+ super::ListLine::Change { n, h, m, tag } => f(a, n, h, m, tag)?,
replacement in pijul/src/remote/ssh.rs at line 910
[11.44434]→[11.44434:44460](∅→∅) edit in pijul/src/remote/ssh.rs at line 916
[11.31]→[11.44594:44796](∅→∅),
[11.44594]→[11.44594:44796](∅→∅),
[11.44796]→[11.0:82](∅→∅),
[11.82]→[11.44880:44965](∅→∅),
[11.44880]→[11.44880:44965](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut local, &c);
− let mut change_file = std::fs::File::open(&local)?;
− let change_len = change_file.metadata()?.len();
− let mut change = thrussh::CryptoVec::new_zeroed(change_len as usize);
− use std::io::Read;
− change_file.read_exact(&mut change[..])?;
replacement in pijul/src/remote/ssh.rs at line 921
[11.45116]→[11.45116:45306](∅→∅),
[11.499]→[11.45306:45379](∅→∅),
[11.633]→[11.45306:45379](∅→∅),
[11.45306]→[11.45306:45379](∅→∅) − self.c
− .data(format!("apply {} {} {}\n", to_channel, c.to_base32(), change_len).as_bytes())
− .await?;
− self.c.data(&change[..]).await?;
− libpijul::changestore::filesystem::pop_filename(&mut local);
+ match c {
+ CS::Change(c) => {
+ libpijul::changestore::filesystem::push_filename(&mut local, &c);
+ let mut change_file = std::fs::File::open(&local)?;
+ let change_len = change_file.metadata()?.len();
+ let mut change = thrussh::CryptoVec::new_zeroed(change_len as usize);
+ use std::io::Read;
+ change_file.read_exact(&mut change[..])?;
+ self.c
+ .data(
+ format!("apply {} {} {}\n", to_channel, c.to_base32(), change_len)
+ .as_bytes(),
+ )
+ .await?;
+ self.c.data(&change[..]).await?;
+ libpijul::changestore::filesystem::pop_filename(&mut local);
+ }
+ CS::State(c) => {
+ libpijul::changestore::filesystem::push_tag_filename(&mut local, &c);
+ let mut tag_file = libpijul::tag::OpenTagFile::open(&local, &c)?;
+ let mut v = Vec::new();
+ tag_file.short(&mut v)?;
+ self.c
+ .data(
+ format!("tagup {} {} {}\n", c.to_base32(), to_channel, v.len())
+ .as_bytes(),
+ )
+ .await?;
+ self.c.data(&v[..]).await?;
+ libpijul::changestore::filesystem::pop_filename(&mut local);
+ }
+ }
replacement in pijul/src/remote/ssh.rs at line 961
[11.22]→[11.143:223](∅→∅),
[11.143]→[11.143:223](∅→∅),
[11.223]→[11.8746:8820](∅→∅),
[11.536]→[11.8746:8820](∅→∅),
[11.8746]→[11.8746:8820](∅→∅) − c: &mut tokio::sync::mpsc::UnboundedReceiver<libpijul::pristine::Hash>,
− sender: &mut tokio::sync::mpsc::Sender<libpijul::pristine::Hash>,
+ c: &mut tokio::sync::mpsc::UnboundedReceiver<CS>,
+ sender: &mut tokio::sync::mpsc::Sender<CS>,
replacement in pijul/src/remote/ssh.rs at line 973
[11.120]→[11.374:536](∅→∅),
[11.374]→[11.374:536](∅→∅) − c: &mut tokio::sync::mpsc::UnboundedReceiver<libpijul::pristine::Hash>,
− sender: Option<&mut tokio::sync::mpsc::Sender<libpijul::pristine::Hash>>,
+ c: &mut tokio::sync::mpsc::UnboundedReceiver<CS>,
+ sender: Option<&mut tokio::sync::mpsc::Sender<CS>>,
replacement in pijul/src/remote/ssh.rs at line 1010
[11.1197]→[11.1197:1497](∅→∅) − if full {
− self.c
− .data(format!("change {}\n", h.to_base32()).as_bytes())
− .await?;
− } else {
− self.c
− .data(format!("partial {}\n", h.to_base32()).as_bytes())
− .await?;
+ match h {
+ CS::Change(h) if full => {
+ self.c
+ .data(format!("change {}\n", h.to_base32()).as_bytes())
+ .await?;
+ }
+ CS::Change(h) => {
+ self.c
+ .data(format!("partial {}\n", h.to_base32()).as_bytes())
+ .await?;
+ }
+ CS::State(h) => {
+ self.c
+ .data(format!("tag {}\n", h.to_base32()).as_bytes())
+ .await?;
+ }
edit in pijul/src/remote/mod.rs at line 35
+ }
+
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ pub enum CS {
+ Change(Hash),
+ State(Merkle),
replacement in pijul/src/remote/mod.rs at line 167
[5.30]→[11.1300:1330](∅→∅),
[11.1300]→[11.1300:1330](∅→∅),
[11.1372]→[11.1372:1449](∅→∅) − pub to_upload: Vec<Hash>,
− pub remote_unrecs: Vec<(u64, Hash)>,
− pub unknown_changes: Vec<Hash>,
+ pub to_upload: Vec<CS>,
+ pub remote_unrecs: Vec<(u64, CS)>,
+ pub unknown_changes: Vec<CS>,
replacement in pijul/src/remote/mod.rs at line 195
[11.2895]→[11.2895:2927](∅→∅),
[11.2927]→[11.185:216](∅→∅) − pub to_download: Vec<Hash>,
− pub tags: HashSet<Merkle>,
+ pub to_download: Vec<CS>,
replacement in pijul/src/remote/mod.rs at line 197
[11.2969]→[11.2969:3063](∅→∅) − pub ours_ge_dichotomy_set: HashSet<Hash>,
− pub theirs_ge_dichotomy_set: HashSet<Hash>,
+ pub ours_ge_dichotomy_set: HashSet<CS>,
+ pub theirs_ge_dichotomy_set: HashSet<CS>,
replacement in pijul/src/remote/mod.rs at line 202
[11.278]→[11.3250:3291](∅→∅),
[11.3250]→[11.3250:3291](∅→∅) − pub remote_unrecs: Vec<(u64, Hash)>,
+ pub remote_unrecs: Vec<(u64, CS)>,
replacement in pijul/src/remote/mod.rs at line 216
[5.75]→[11.3701:3749](∅→∅),
[11.3701]→[11.3701:3749](∅→∅) − let mut to_upload = Vec::<Hash>::new();
+ let mut to_upload = Vec::new();
replacement in pijul/src/remote/mod.rs at line 226
[11.4209]→[11.4209:4258](∅→∅) − to_upload.push(h.into())
+ to_upload.push(CS::Change(h.into()))
replacement in pijul/src/remote/mod.rs at line 230
[11.4418]→[11.4418:4476](∅→∅) − to_upload.push(h.into());
+ to_upload.push(CS::Change(h.into()));
replacement in pijul/src/remote/mod.rs at line 258
[5.120]→[11.5372:5420](∅→∅),
[11.5372]→[11.5372:5420](∅→∅) − let mut to_upload = Vec::<Hash>::new();
+ let mut to_upload = Vec::new();
edit in pijul/src/remote/mod.rs at line 261
+ let mut tags: HashSet<Merkle> = HashSet::new();
+ for x in txn.rev_iter_tags(&channel.read().tags, None)? {
+ let (n, m) = x?;
+ debug!("rev_iter_tags {:?} {:?}", n, m);
+ // First, if the remote has exactly the same first n tags, break.
+ if let Some((_, p)) = txn.get_remote_tag(&remote_ref.lock().tags, (*n).into())? {
+ if p.b == m.b {
+ debug!("the remote has tag {:?}", p.a);
+ break;
+ }
+ if p.a != m.a {
+ // What to do here? It is possible that state
+ // `n` is a different state than `m.a` in the
+ // remote, and is also tagged.
+ }
+ } else {
+ tags.insert(m.a.into());
+ }
+ }
+ debug!("tags = {:?}", tags);
replacement in pijul/src/remote/mod.rs at line 283
[11.5644]→[11.5644:5730](∅→∅) − if txn.remote_has_state(remote_ref, &m)? {
− break;
+ let h_unrecorded = self
+ .remote_unrecs
+ .iter()
+ .any(|(_, hh)| hh == &CS::Change(h.into()));
+ if !h_unrecorded {
+ if txn.remote_has_state(remote_ref, &m)?.is_some() {
+ debug!("remote_has_state: {:?}", m);
+ break;
+ }
replacement in pijul/src/remote/mod.rs at line 298
[11.6075]→[11.6075:6134](∅→∅),
[11.6134]→[11.6134:6206](∅→∅) − if !txn.remote_has_change(remote_ref, &h)?
− && !self.theirs_ge_dichotomy_set.contains(&h_deser)
+ if (!txn.remote_has_change(remote_ref, &h)? || h_unrecorded)
+ && !self.theirs_ge_dichotomy_set.contains(&CS::Change(h_deser))
replacement in pijul/src/remote/mod.rs at line 302
[11.6267]→[11.6267:6315](∅→∅) − to_upload.push(h_deser)
+ if tags.remove(&m.into()) {
+ to_upload.push(CS::State(m.into()));
+ }
+ to_upload.push(CS::Change(h_deser));
replacement in pijul/src/remote/mod.rs at line 309
[11.6475]→[11.6475:6532](∅→∅) − to_upload.push(h_deser);
+ to_upload.push(CS::Change(h_deser));
+ if tags.remove(&m.into()) {
+ to_upload.push(CS::State(m.into()));
+ }
edit in pijul/src/remote/mod.rs at line 317
+ }
+ }
+ for t in tags.iter() {
+ if let Some(n) = txn.remote_has_state(&remote_ref, &t.into())? {
+ if !txn.is_tagged(&remote_ref.lock().tags, n)? {
+ to_upload.push(CS::State(*t));
+ }
+ } else {
+ debug!("the remote doesn't have state {:?}", t);
replacement in pijul/src/remote/mod.rs at line 333
[11.6896]→[11.6896:6984](∅→∅),
[11.6984]→[11.279:320](∅→∅),
[11.320]→[11.0:132](∅→∅),
[11.7022]→[11.0:132](∅→∅) − let unknown_changes = self
− .theirs_ge_dichotomy
− .iter()
− .filter_map(|(_, h, _, _)| {
− if self.ours_ge_dichotomy_set.contains(h)
− || txn.get_revchanges(&channel, h).unwrap().is_some()
+ let mut unknown_changes = Vec::new();
+ for (_, h, m, is_tag) in self.theirs_ge_dichotomy.iter() {
+ let h_is_known = txn.get_revchanges(&channel, h).unwrap().is_some();
+ let change = CS::Change(*h);
+ if !(self.ours_ge_dichotomy_set.contains(&change) || h_is_known) {
+ unknown_changes.push(change)
+ }
+ if *is_tag {
+ let m_is_known = if let Some(n) = txn
+ .channel_has_state(txn.states(&*channel.read()), &m.into())
+ .unwrap()
replacement in pijul/src/remote/mod.rs at line 345
[11.150]→[11.7082:7107](∅→∅),
[11.7082]→[11.7082:7107](∅→∅) + txn.is_tagged(txn.tags(&*channel.read()), n.into()).unwrap()
replacement in pijul/src/remote/mod.rs at line 347
[11.7132]→[11.7132:7161](∅→∅) + false
+ };
+ if !m_is_known {
+ unknown_changes.push(CS::State(*m))
replacement in pijul/src/remote/mod.rs at line 352
[11.7179]→[11.7179:7194](∅→∅),
[11.7194]→[11.7194:7231](∅→∅) − })
− .collect::<Vec<Hash>>();
replacement in pijul/src/remote/mod.rs at line 379
[11.316]→[11.321:358](∅→∅) + to_download.push(CS::Change(h));
edit in pijul/src/remote/mod.rs at line 385
[11.402]→[11.359:393](∅→∅) edit in pijul/src/remote/mod.rs at line 399
[11.8828]→[11.394:433](∅→∅) − let mut tags = HashSet::new();
replacement in pijul/src/remote/mod.rs at line 402
[11.9021]→[11.434:472](∅→∅) replacement in pijul/src/remote/mod.rs at line 421
[11.9776]→[11.473:671](∅→∅) − to_download.push(h.into());
− if txn.is_tagged(&remote_channel.tags, n)? {
− tags.insert(m.into());
− }
+ to_download.push(CS::Change(h.into()));
edit in pijul/src/remote/mod.rs at line 429
[11.9961]→[11.672:690](∅→∅) replacement in pijul/src/remote/mod.rs at line 505
[11.165]→[11.43:43](∅→∅),
[11.43]→[11.56987:57008](∅→∅),
[11.165]→[11.56987:57008](∅→∅),
[11.6499]→[11.56987:57008](∅→∅),
[11.56987]→[11.56987:57008](∅→∅),
[11.57008]→[11.269:331](∅→∅),
[11.331]→[11.57072:57093](∅→∅),
[11.567]→[11.57072:57093](∅→∅),
[11.57072]→[11.57072:57093](∅→∅) −
− let n = self
− .dichotomy_changelist(txn, &remote.lock().remote)
− .await?;
+ let n = self.dichotomy_changelist(txn, &remote.lock()).await?;
edit in pijul/src/remote/mod.rs at line 522
+ }
+ let v: Vec<_> = txn
+ .iter_tags(&remote.lock().tags, n)?
+ .filter_map(|k| {
+ debug!("filter_map {:?}", k);
+ let k = (*k.unwrap().0).into();
+ if k >= n {
+ Some(k)
+ } else {
+ None
+ }
+ })
+ .collect();
+ for k in v {
+ debug!("deleting {:?}", k);
+ txn.del_tags(&mut remote.lock().tags, k)?;
edit in pijul/src/remote/mod.rs at line 539
edit in pijul/src/remote/mod.rs at line 543
+ }
+
+ async fn update_changelist_pushpull_from_scratch(
+ &mut self,
+ txn: &mut MutTxn<()>,
+ path: &[String],
+ current_channel: &ChannelRef<MutTxn<()>>,
+ ) -> Result<RemoteDelta<MutTxn<()>>, anyhow::Error> {
+ debug!("no id, starting from scratch");
+ let (inodes, theirs_ge_dichotomy) = self.download_changelist_nocache(0, path).await?;
+ let mut theirs_ge_dichotomy_set = HashSet::new();
+ let mut to_download = Vec::new();
+ for (_, h, m, is_tag) in theirs_ge_dichotomy.iter() {
+ theirs_ge_dichotomy_set.insert(CS::Change(*h));
+ if txn.get_revchanges(current_channel, h)?.is_none() {
+ to_download.push(CS::Change(*h));
+ }
+ if *is_tag {
+ let ch = current_channel.read();
+ if let Some(n) = txn.channel_has_state(txn.states(&*ch), &m.into())? {
+ if !txn.is_tagged(txn.tags(&*ch), n.into())? {
+ to_download.push(CS::State(*m));
+ }
+ } else {
+ to_download.push(CS::State(*m));
+ }
+ }
+ }
+ Ok(RemoteDelta {
+ inodes,
+ remote_ref: None,
+ to_download,
+ ours_ge_dichotomy_set: HashSet::new(),
+ theirs_ge_dichotomy,
+ theirs_ge_dichotomy_set,
+ remote_unrecs: Vec::new(),
+ })
edit in pijul/src/remote/mod.rs at line 602
replacement in pijul/src/remote/mod.rs at line 620
[11.357]→[11.488:540](∅→∅),
[11.540]→[11.357:455](∅→∅),
[11.357]→[11.357:455](∅→∅),
[11.455]→[11.455:563](∅→∅),
[11.563]→[11.691:803](∅→∅),
[11.803]→[11.621:673](∅→∅),
[11.621]→[11.621:673](∅→∅),
[11.673]→[11.541:654](∅→∅),
[11.654]→[11.804:881](∅→∅),
[11.881]→[11.881:903](∅→∅),
[11.903]→[11.654:672](∅→∅),
[11.654]→[11.654:672](∅→∅),
[11.672]→[11.711:848](∅→∅),
[11.711]→[11.711:848](∅→∅),
[11.848]→[11.904:926](∅→∅),
[11.926]→[11.848:1051](∅→∅),
[11.848]→[11.848:1051](∅→∅),
[11.86]→[11.11504:11668](∅→∅),
[11.1051]→[11.11504:11668](∅→∅),
[11.11504]→[11.11504:11668](∅→∅) − debug!("no id, starting from scratch");
− let (inodes, theirs_ge_dichotomy) = self.download_changelist_nocache(0, path).await?;
− let mut theirs_ge_dichotomy_set = HashSet::new();
− let mut to_download = Vec::new();
− let mut tags = HashSet::new();
− for (_, h, m, is_tagged) in theirs_ge_dichotomy.iter() {
− theirs_ge_dichotomy_set.insert(*h);
− if txn.get_revchanges(current_channel, h)?.is_none() {
− to_download.push(*h);
− if *is_tagged {
− tags.insert(*m);
− }
− }
− }
− return Ok(RemoteDelta {
− inodes,
− remote_ref: None,
− to_download,
− tags,
− ours_ge_dichotomy_set: HashSet::new(),
− theirs_ge_dichotomy,
− theirs_ge_dichotomy_set,
− remote_unrecs: Vec::new(),
− });
− };
− let mut remote_ref = if let Some(name) = self.name() {
− txn.open_or_create_remote(id, name).unwrap()
− } else {
− unreachable!()
+ return self
+ .update_changelist_pushpull_from_scratch(txn, path, current_channel)
+ .await;
replacement in pijul/src/remote/mod.rs at line 624
[11.11679]→[11.11679:11710](∅→∅),
[11.11710]→[11.11710:11776](∅→∅),
[11.11776]→[11.11776:11797](∅→∅),
[11.11797]→[11.11797:11851](∅→∅) − let dichotomy_n = self
− .dichotomy_changelist(txn, &remote_ref.lock().remote)
− .await?;
− let ours_ge_dichotomy: Vec<(u64, Hash)> = txn
+ let mut remote_ref = txn.open_or_create_remote(id, self.name().unwrap()).unwrap();
+ let dichotomy_n = self.dichotomy_changelist(txn, &remote_ref.lock()).await?;
+ let ours_ge_dichotomy: Vec<(u64, CS)> = txn
replacement in pijul/src/remote/mod.rs at line 634
[11.12221]→[11.12221:12265](∅→∅) + Some((k, CS::Change(hash)))
edit in pijul/src/remote/mod.rs at line 644
+ debug!("theirs_ge_dichotomy = {:?}", theirs_ge_dichotomy);
edit in pijul/src/remote/mod.rs at line 648
[11.12655]→[11.12655:12677](∅→∅),
[11.12677]→[11.12677:12718](∅→∅),
[11.12718]→[11.12718:12796](∅→∅),
[11.12796]→[11.927:962](∅→∅) − .copied()
− .collect::<HashSet<Hash>>();
− let theirs_ge_dichotomy_set = theirs_ge_dichotomy
− .iter()
− .map(|(_, h, _, _)| h)
replacement in pijul/src/remote/mod.rs at line 649
[11.12850]→[11.12850:12891](∅→∅),
[11.12891]→[11.12891:13257](∅→∅),
[11.13257]→[11.13257:13434](∅→∅),
[11.13434]→[11.13434:13455](∅→∅),
[11.13455]→[11.13455:13503](∅→∅) − .collect::<HashSet<Hash>>();
−
− // remote_unrecs = {x: (u64, Hash) | x \in ours_ge_dichot /\ ~(x \in theirs_ge_dichot) /\ x \in current_channel }
− let mut remote_unrecs = Vec::new();
− for (n, hash) in &ours_ge_dichotomy {
− if theirs_ge_dichotomy_set.contains(hash) {
− // If this change is still present in the remote, skip
− continue;
− } else if txn.get_revchanges(¤t_channel, &hash)?.is_none() {
− // If this unrecord wasn't in our current channel, skip
− continue;
− } else {
− remote_unrecs.push((*n, *hash))
+ .collect::<HashSet<CS>>();
+ let mut theirs_ge_dichotomy_set = HashSet::new();
+ for (_, h, m, is_tag) in theirs_ge_dichotomy.iter() {
+ theirs_ge_dichotomy_set.insert(CS::Change(*h));
+ if *is_tag {
+ theirs_ge_dichotomy_set.insert(CS::State(*m));
replacement in pijul/src/remote/mod.rs at line 657
[11.13527]→[11.13527:13611](∅→∅) − let should_cache = force_cache.unwrap_or_else(|| remote_unrecs.is_empty());
+
+ // remote_unrecs = {x: (u64, Hash) | x \in ours_ge_dichot /\ ~(x \in theirs_ge_dichot) /\ x \in current_channel }
+ let remote_unrecs = remote_unrecs(
+ txn,
+ current_channel,
+ &ours_ge_dichotomy,
+ &theirs_ge_dichotomy_set,
+ )?;
+ let should_cache = if let Some(true) = force_cache {
+ true
+ } else {
+ remote_unrecs.is_empty()
+ };
+ debug!(
+ "should_cache = {:?} {:?} {:?}",
+ force_cache, remote_unrecs, should_cache
+ );
replacement in pijul/src/remote/mod.rs at line 675
[11.13637]→[11.13637:13699](∅→∅),
[11.13699]→[11.13699:13752](∅→∅) − for (k, _) in ours_ge_dichotomy.iter().copied() {
− txn.del_remote(&mut remote_ref, k)?;
+ use libpijul::ChannelMutTxnT;
+ for (k, t) in ours_ge_dichotomy.iter().copied() {
+ match t {
+ CS::State(_) => txn.del_tags(&mut remote_ref.lock().tags, k)?,
+ CS::Change(_) => {
+ txn.del_remote(&mut remote_ref, k)?;
+ }
+ }
replacement in pijul/src/remote/mod.rs at line 684
[11.13766]→[11.963:1097](∅→∅) − for (n, h, m, t) in theirs_ge_dichotomy.iter().copied() {
− txn.put_remote(&mut remote_ref, n, (h, m, t))?;
+ for (n, h, m, is_tag) in theirs_ge_dichotomy.iter().copied() {
+ debug!("theirs: {:?} {:?} {:?}", n, h, m);
+ txn.put_remote(&mut remote_ref, n, (h, m))?;
+ if is_tag {
+ txn.put_tags(&mut remote_ref.lock().tags, n, &m)?;
+ }
edit in pijul/src/remote/mod.rs at line 692
[11.13918]→[11.13918:14140](∅→∅),
[11.14140]→[11.14140:14255](∅→∅),
[11.14255]→[11.14255:14281](∅→∅),
[11.14281]→[11.14281:14308](∅→∅),
[11.14308]→[11.14308:14319](∅→∅),
[11.14319]→[11.57522:57523](∅→∅),
[11.57522]→[11.57522:57523](∅→∅),
[11.57523]→[11.14320:14811](∅→∅) − let state_cond = |txn: &MutTxn<()>, merkle: &libpijul::pristine::SerializedMerkle| {
− txn.channel_has_state(txn.states(&*current_channel.read()), merkle)
− .map(|x| x.is_some())
− };
− let change_cond = |txn: &MutTxn<()>, hash: &Hash| {
− txn.get_revchanges(¤t_channel, hash)
− .unwrap()
− .is_none()
− };
−
− // IF:
− // The user only wanted to push/pull specific changes
− // ELIF:
− // The user specified no changes and there were no remote unrecords
− // effecting the current channel means we can auto-cache
− // the local remote cache
− // ELSE:
− // The user specified no changes but there were remote unrecords
− // effecting the current channel meaning we can't auto-cache
− // the local remote cache.
edit in pijul/src/remote/mod.rs at line 693
+ // Here, the user only wanted to push/pull specific changes
replacement in pijul/src/remote/mod.rs at line 696
[11.14924]→[11.14924:14981](∅→∅) − .map(|h| Ok(txn.hash_from_prefix(h)?.0))
+ .map(|h| {
+ if is_tag {
+ Ok(CS::State(
+ txn.state_from_prefix(&*current_channel.read(), h)?.0,
+ ))
+ } else {
+ Ok(CS::Change(txn.hash_from_prefix(h)?.0))
+ }
+ })
edit in pijul/src/remote/mod.rs at line 710
[11.15184]→[11.1098:1136](∅→∅) replacement in pijul/src/remote/mod.rs at line 715
[11.15347]→[11.15347:15380](∅→∅),
[11.15380]→[11.15380:15437](∅→∅),
[11.15437]→[11.1137:1180](∅→∅),
[11.1180]→[11.1180:1239](∅→∅),
[11.1239]→[11.1239:1719](∅→∅),
[11.1719]→[11.1719:1745](∅→∅) − } else if should_cache {
− let mut to_download: Vec<Hash> = Vec::new();
− let mut tags = HashSet::new();
− {
− let rem = remote_ref.lock();
− for thing in txn.iter_remote(&rem.remote, 0)? {
− let (n, libpijul::pristine::Pair { a: hash, b: merkle }) = thing?;
− if state_cond(txn, &merkle)? {
− break;
− } else if change_cond(txn, &hash.into()) {
− to_download.push(Hash::from(hash));
− if txn.is_tagged(&rem.tags, (*n).into())? {
− tags.insert(merkle.into());
− }
+ } else {
+ let mut to_download: Vec<CS> = Vec::new();
+ for (n, h, m, is_tag) in theirs_ge_dichotomy.iter() {
+ // In all cases, add this new change/state/tag to `to_download`.
+ let ch = CS::Change(*h);
+ if txn.get_revchanges(¤t_channel, h).unwrap().is_none() {
+ to_download.push(ch.clone());
+ if *is_tag {
+ to_download.push(CS::State(*m));
replacement in pijul/src/remote/mod.rs at line 725
[11.1767]→[11.15783:15815](∅→∅),
[11.15783]→[11.15783:15815](∅→∅),
[11.15816]→[11.15816:15944](∅→∅),
[11.15944]→[11.1768:1790](∅→∅),
[11.1790]→[11.15944:16124](∅→∅),
[11.15944]→[11.15944:16124](∅→∅),
[11.16124]→[11.16124:16595](∅→∅) − }
− }
− Ok(RemoteDelta {
− inodes,
− remote_ref: Some(remote_ref),
− to_download,
− tags,
− ours_ge_dichotomy_set,
− theirs_ge_dichotomy,
− theirs_ge_dichotomy_set,
− remote_unrecs,
− })
− } else {
− let mut to_download: Vec<Hash> = Vec::new();
− for thing in txn.iter_remote(&remote_ref.lock().remote, 0)? {
− let (n, libpijul::pristine::Pair { a: hash, b: merkle }) = thing?;
− if u64::from(*n) < dichotomy_n {
− if state_cond(txn, &merkle)? {
− continue;
− } else if change_cond(txn, &hash.into()) {
− to_download.push(Hash::from(hash));
+ } else if *is_tag {
+ let has_tag = if let Some(n) =
+ txn.channel_has_state(txn.states(¤t_channel.read()), &m.into())?
+ {
+ txn.is_tagged(txn.tags(¤t_channel.read()), n.into())?
+ } else {
+ false
+ };
+ if !has_tag {
+ to_download.push(CS::State(*m));
replacement in pijul/src/remote/mod.rs at line 737
[11.16635]→[11.16635:16649](∅→∅),
[11.16649]→[11.1791:1897](∅→∅),
[11.1897]→[11.16709:16793](∅→∅),
[11.16709]→[11.16709:16793](∅→∅),
[11.16793]→[11.16793:16902](∅→∅),
[11.16902]→[11.1898:1972](∅→∅) − }
− let mut tags = HashSet::new();
− for (_, hash, merkle, t) in &theirs_ge_dichotomy {
− if state_cond(txn, &merkle.into())? {
− continue;
− } else if change_cond(txn, &hash) {
− to_download.push(Hash::from(*hash));
− if *t {
− tags.insert(*merkle);
+ // Additionally, if there are no remote unrecords
+ // (i.e. if `should_cache`), cache.
+ if should_cache && ours_ge_dichotomy_set.get(&ch).is_none() {
+ use libpijul::ChannelMutTxnT;
+ txn.put_remote(&mut remote_ref, *n, (*h, *m))?;
+ if *is_tag {
+ let mut rem = remote_ref.lock();
+ txn.put_tags(&mut rem.tags, *n, m)?;
edit in pijul/src/remote/mod.rs at line 748
[11.16934]→[11.16934:16935](∅→∅) edit in pijul/src/remote/mod.rs at line 752
[11.17063]→[11.1995:2017](∅→∅) replacement in pijul/src/remote/mod.rs at line 769
[11.17675]→[11.2111:2182](∅→∅) − let f = |v: &mut Vec<(u64, Hash, Merkle, bool)>, n, h, m, t| {
+ let f = |v: &mut Vec<(u64, Hash, Merkle, bool)>, n, h, m, m2| {
replacement in pijul/src/remote/mod.rs at line 771
[11.17778]→[11.2183:2220](∅→∅) − Ok(v.push((n, h, m, t)))
+ Ok(v.push((n, h, m, m2)))
replacement in pijul/src/remote/mod.rs at line 789
[11.57606]→[11.57606:57634](∅→∅) + remote: &libpijul::pristine::Remote<T>,
replacement in pijul/src/remote/mod.rs at line 792
[11.57695]→[11.7253:7344](∅→∅) − let (mut b, state): (_, Merkle) = if let Some((u, v)) = txn.last_remote(remote)? {
+ let (mut b, state): (_, Merkle) = if let Some((u, v)) = txn.last_remote(&remote.remote)? {
replacement in pijul/src/remote/mod.rs at line 799
[11.57913]→[11.1721:1789](∅→∅),
[11.1789]→[11.57976:58004](∅→∅),
[11.57976]→[11.57976:58004](∅→∅) − if let Some((_, s)) = self.get_state(txn, Some(b)).await? {
− if s == state {
+ let last_statet = if let Some((_, _, v)) = txn.last_remote_tag(&remote.tags)? {
+ v.into()
+ } else {
+ Merkle::zero()
+ };
+ debug!("last_state: {:?} {:?}", state, last_statet);
+ if let Some((_, s, st)) = self.get_state(txn, Some(b)).await? {
+ debug!("remote last_state: {:?} {:?}", s, st);
+ if s == state && st == last_statet {
replacement in pijul/src/remote/mod.rs at line 817
[11.58358]→[11.7437:7513](∅→∅) − let (mid, state) = txn.get_remote_state(remote, mid)?.unwrap();
+ let (mid, state) = {
+ let (a, b) = txn.get_remote_state(&remote.remote, mid)?.unwrap();
+ (a, b.b)
+ };
+ let statet = if let Some((_, b)) = txn.get_remote_tag(&remote.tags, mid)? {
+ // There's still a tag at position >= mid in the
+ // sequence.
+ b.b.into()
+ } else {
+ // No tag at or after mid, the last state, `statet`,
+ // is the right answer in that case.
+ last_statet
+ };
+
replacement in pijul/src/remote/mod.rs at line 833
[11.58577]→[11.58577:58637](∅→∅),
[11.58637]→[11.7514:7559](∅→∅) − if let Some((_, remote_state)) = remote_state {
− if remote_state == state.b {
+ if let Some((_, remote_state, remote_statet)) = remote_state {
+ if remote_state == state && remote_statet == statet {
replacement in pijul/src/remote/mod.rs at line 856
[11.59114]→[11.59114:59170](∅→∅) − ) -> Result<Option<(u64, Merkle)>, anyhow::Error> {
+ ) -> Result<Option<(u64, Merkle, Merkle)>, anyhow::Error> {
replacement in pijul/src/remote/mod.rs at line 936
[11.1161]→[11.2221:2297](∅→∅) − let f = |a: &mut (&mut T, &mut RemoteRef<T>), n, h, m, is_tagged| {
+ let f = |a: &mut (&mut T, &mut RemoteRef<T>), n, h, m, is_tag| {
replacement in pijul/src/remote/mod.rs at line 938
[11.570]→[11.2298:2357](∅→∅) − txn.put_remote(remote, n, (h, m, is_tagged))?;
+ txn.put_remote(remote, n, (h, m))?;
+ if is_tag {
+ txn.put_tags(&mut remote.lock().tags, n, &m.into())?;
+ }
replacement in pijul/src/remote/mod.rs at line 966
[11.65261]→[11.65261:65287](∅→∅) replacement in pijul/src/remote/mod.rs at line 1001
[11.398]→[11.1589:1674](∅→∅),
[11.1589]→[11.1589:1674](∅→∅),
[11.1205]→[11.10700:10772](∅→∅),
[11.1674]→[11.10700:10772](∅→∅),
[11.10700]→[11.10700:10772](∅→∅) − hashes: &mut tokio::sync::mpsc::UnboundedReceiver<libpijul::pristine::Hash>,
− send: &mut tokio::sync::mpsc::Sender<libpijul::pristine::Hash>,
+ hashes: &mut tokio::sync::mpsc::UnboundedReceiver<CS>,
+ send: &mut tokio::sync::mpsc::Sender<CS>,
replacement in pijul/src/remote/mod.rs at line 1047
[11.68892]→[11.160:187](∅→∅) replacement in pijul/src/remote/mod.rs at line 1050
[11.68948]→[11.1363:1407](∅→∅) − ) -> Result<Vec<Hash>, anyhow::Error> {
+ ) -> Result<Vec<CS>, anyhow::Error> {
replacement in pijul/src/remote/mod.rs at line 1085
[11.259]→[11.259:402](∅→∅),
[11.402]→[11.3096:3173](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut change_path_, h);
− if std::fs::metadata(&change_path_).is_err() {
− hash_send.send(*h)?;
− to_download.insert(*h);
+ if let CS::Change(h) = h {
+ libpijul::changestore::filesystem::push_filename(&mut change_path_, h);
+ if std::fs::metadata(&change_path_).is_err() {
+ hash_send.send(CS::Change(*h))?;
+ to_download.insert(CS::Change(*h));
+ }
+ libpijul::changestore::filesystem::pop_filename(&mut change_path_);
edit in pijul/src/remote/mod.rs at line 1093
[11.454]→[11.454:534](∅→∅) − libpijul::changestore::filesystem::pop_filename(&mut change_path_);
replacement in pijul/src/remote/mod.rs at line 1113
[11.1641]→[11.1641:2262](∅→∅) − 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
− }
+ if let CS::Change(h) = h {
+ 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
+ }
+ })
replacement in pijul/src/remote/mod.rs at line 1129
[11.2289]→[11.2289:2312](∅→∅) replacement in pijul/src/remote/mod.rs at line 1133
[11.2330]→[11.2330:2392](∅→∅) − || { inodes.iter().any(|i| i.change == *h) };
+ || { inodes.iter().any(|i| CS::Change(i.change) == *h) };
replacement in pijul/src/remote/mod.rs at line 1145
[11.3600]→[11.478:529](∅→∅),
[11.529]→[11.60:139](∅→∅),
[11.60]→[11.60:139](∅→∅) − let mut channel = channel.write();
− txn.apply_change_ws(&repo.changes, &mut channel, h, &mut ws)?;
+ if let CS::Change(h) = h {
+ let mut channel = channel.write();
+ txn.apply_change_ws(&repo.changes, &mut channel, h, &mut ws)?;
+ }
replacement in pijul/src/remote/mod.rs at line 1199
[11.71974]→[11.4069:4101](∅→∅) + send_hash.send(CS::Change(h))?;
replacement in pijul/src/remote/mod.rs at line 1205
[11.72174]→[11.72174:72533](∅→∅),
[11.72533]→[11.4102:4140](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut change_path, &hash);
− std::fs::create_dir_all(change_path.parent().unwrap())?;
− use libpijul::changestore::ChangeStore;
− hashes.push(hash);
− for dep in repo.changes.get_dependencies(&hash)? {
− let dep: libpijul::pristine::Hash = dep;
− send_hash.send(dep)?;
+ if let CS::Change(hash) = hash {
+ libpijul::changestore::filesystem::push_filename(&mut change_path, &hash);
+ std::fs::create_dir_all(change_path.parent().unwrap())?;
+ use libpijul::changestore::ChangeStore;
+ hashes.push(CS::Change(hash));
+ for dep in repo.changes.get_dependencies(&hash)? {
+ let dep: libpijul::pristine::Hash = dep;
+ send_hash.send(CS::Change(dep))?;
+ }
+ libpijul::changestore::filesystem::pop_filename(&mut change_path);
edit in pijul/src/remote/mod.rs at line 1216
[11.72591]→[11.72591:72670](∅→∅) − libpijul::changestore::filesystem::pop_filename(&mut change_path);
replacement in pijul/src/remote/mod.rs at line 1223
[11.247]→[11.247:330](∅→∅) − txn.apply_change_ws(&repo.changes, &mut channel_, hash, &mut ws)?;
+ if let CS::Change(hash) = hash {
+ txn.apply_change_ws(&repo.changes, &mut channel_, hash, &mut ws)?;
+ }
replacement in pijul/src/remote/mod.rs at line 1254
[11.7876]→[11.7876:7914](∅→∅) − to_pull.push(p.a.into());
+ to_pull.push(CS::Change(p.a.into()));
replacement in pijul/src/remote/mod.rs at line 1277
[11.74955]→[11.74955:74981](∅→∅) edit in pijul/src/remote/mod.rs at line 1303
+ let c = if let CS::Change(c) = c {
+ c
+ } else {
+ unreachable!()
+ };
replacement in pijul/src/remote/mod.rs at line 1318
[11.76328]→[11.4513:4550](∅→∅) + send_hash.send(CS::Change(*c))?;
replacement in pijul/src/remote/mod.rs at line 1342
[11.2672]→[11.4551:4592](∅→∅) + send_hash.send(CS::Change(*c))?;
replacement in pijul/src/remote/mod.rs at line 1373
[11.8353]→[11.8353:8395](∅→∅) − pullable.push(p.a.into())
+ pullable.push(CS::Change(p.a.into()))
replacement in pijul/src/remote/mod.rs at line 1403
[11.2588]→[11.2588:2613](∅→∅) replacement in pijul/src/remote/mod.rs at line 1420
[11.3818]→[11.2621:2676](∅→∅) − is_tagged: caps.name("tag").is_some(),
+ tag: caps.name("tag").is_some(),
edit in pijul/src/remote/mod.rs at line 1442
+ }
+
+ /// Compare the remote set (theirs_ge_dichotomy) with our current
+ /// version of that (ours_ge_dichotomy) and return the changes in our
+ /// current version that are not in the remote anymore.
+ fn remote_unrecs<T: TxnTExt + ChannelTxnT>(
+ txn: &T,
+ current_channel: &ChannelRef<T>,
+ ours_ge_dichotomy: &[(u64, CS)],
+ theirs_ge_dichotomy_set: &HashSet<CS>,
+ ) -> Result<Vec<(u64, CS)>, anyhow::Error> {
+ let mut remote_unrecs = Vec::new();
+ for (n, hash) in ours_ge_dichotomy {
+ debug!("ours_ge_dichotomy: {:?} {:?}", n, hash);
+ if theirs_ge_dichotomy_set.contains(hash) {
+ // If this change is still present in the remote, skip
+ debug!("still present");
+ continue;
+ } else {
+ let has_it = match hash {
+ CS::Change(hash) => txn.get_revchanges(¤t_channel, &hash)?.is_some(),
+ CS::State(state) => {
+ let ch = current_channel.read();
+ if let Some(n) = txn.channel_has_state(txn.states(&*ch), &state.into())? {
+ txn.is_tagged(txn.tags(&*ch), n.into())?
+ } else {
+ false
+ }
+ }
+ };
+ if has_it {
+ remote_unrecs.push((*n, *hash))
+ } else {
+ // If this unrecord wasn't in our current channel, skip
+ continue;
+ }
+ }
+ }
+ Ok(remote_unrecs)
edit in pijul/src/remote/local.rs at line 9
+
+ use crate::remote::CS;
replacement in pijul/src/remote/local.rs at line 25
[11.3106]→[11.9863:9915](∅→∅),
[11.9915]→[11.3135:3164](∅→∅),
[11.3135]→[11.3135:3164](∅→∅),
[11.3164]→[11.9916:9983](∅→∅) − ) -> Result<Option<(u64, Merkle)>, anyhow::Error> {
− if let Some(mid) = mid {
− Ok(txn.get_changes(&channel, mid)?.map(|(_, m)| (mid, m)))
+ ) -> Result<Option<(u64, Merkle, Merkle)>, anyhow::Error> {
+ if let Some(x) = txn.reverse_log(&*channel.read(), mid)?.next() {
+ let (n, (_, m)) = x?;
+ if let Some(m2) = txn
+ .rev_iter_tags(txn.tags(&*channel.read()), Some(n.into()))?
+ .next()
+ {
+ let (_, m2) = m2?;
+ Ok(Some((n, m.into(), m2.b.into())))
+ } else {
+ Ok(Some((n, m.into(), Merkle::zero())))
+ }
replacement in pijul/src/remote/local.rs at line 38
[11.3239]→[11.939:1008](∅→∅),
[11.909]→[11.10054:10096](∅→∅),
[11.1008]→[11.10054:10096](∅→∅),
[11.10054]→[11.10054:10096](∅→∅),
[11.10096]→[11.8666:8692](∅→∅),
[11.8692]→[11.10115:10127](∅→∅),
[11.10115]→[11.10115:10127](∅→∅) − Ok(txn.reverse_log(&*channel.read(), None)?.next().map(|n| {
− let (n, (_, m)) = n.unwrap();
− (n, m.into())
− }))
replacement in pijul/src/remote/local.rs at line 43
[11.80117]→[11.80117:80217](∅→∅) − pub fn get_state(&mut self, mid: Option<u64>) -> Result<Option<(u64, Merkle)>, anyhow::Error> {
+ pub fn get_state(
+ &mut self,
+ mid: Option<u64>,
+ ) -> Result<Option<(u64, Merkle, Merkle)>, anyhow::Error> {
replacement in pijul/src/remote/local.rs at line 107
[11.8962]→[11.1113:1179](∅→∅) − for x in remote_txn.log(&*remote_channel.read(), from)? {
+
+ let rem = remote_channel.read();
+ let tags: Vec<u64> = remote_txn
+ .iter_tags(remote_txn.tags(&*rem), from)?
+ .map(|k| (*k.unwrap().0).into())
+ .collect();
+ let mut tagsi = 0;
+
+ for x in remote_txn.log(&*rem, from)? {
replacement in pijul/src/remote/local.rs at line 128
[11.9387]→[11.2758:2978](∅→∅) − f(
− a,
− n,
− h.into(),
− m.into(),
− remote_txn.is_tagged(&remote_channel.read().tags, n)?,
− )?;
+ if tags.get(tagsi) == Some(&n) {
+ f(a, n, h.into(), m.into(), true)?;
+ tagsi += 1;
+ } else {
+ f(a, n, h.into(), m.into(), false)?;
+ }
replacement in pijul/src/remote/local.rs at line 144
[11.82205]→[11.82205:82231](∅→∅) replacement in pijul/src/remote/local.rs at line 155
[11.82584]→[11.82584:82751](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut local, &c);
− libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
+ match c {
+ CS::Change(c) => {
+ libpijul::changestore::filesystem::push_filename(&mut local, &c);
+ libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
+ }
+ CS::State(c) => {
+ libpijul::changestore::filesystem::push_tag_filename(&mut local, &c);
+ libpijul::changestore::filesystem::push_tag_filename(&mut self.changes_dir, &c);
+ }
+ }
edit in pijul/src/remote/local.rs at line 172
+ debug!("hard link done");
+ libpijul::changestore::filesystem::pop_filename(&mut local);
+ libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
replacement in pijul/src/remote/local.rs at line 196
[11.2860]→[11.4665:4750](∅→∅),
[11.4665]→[11.4665:4750](∅→∅),
[11.2841]→[11.11767:11839](∅→∅),
[11.4750]→[11.11767:11839](∅→∅),
[11.11767]→[11.11767:11839](∅→∅) − hashes: &mut tokio::sync::mpsc::UnboundedReceiver<libpijul::pristine::Hash>,
− send: &mut tokio::sync::mpsc::Sender<libpijul::pristine::Hash>,
+ hashes: &mut tokio::sync::mpsc::UnboundedReceiver<CS>,
+ send: &mut tokio::sync::mpsc::Sender<CS>,
replacement in pijul/src/remote/local.rs at line 201
[11.2892]→[11.2892:3058](∅→∅),
[11.3058]→[11.2861:2926](∅→∅),
[11.270]→[11.12057:12157](∅→∅),
[11.2926]→[11.12057:12157](∅→∅),
[11.3058]→[11.12057:12157](∅→∅),
[11.4807]→[11.12057:12157](∅→∅),
[11.12057]→[11.12057:12157](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
− libpijul::changestore::filesystem::push_filename(&mut path, &c);
− super::PROGRESS.borrow_mut().unwrap()[pro_n].incr();
− if std::fs::metadata(&path).is_ok() {
− debug!("metadata {:?} ok", path);
+ if let CS::Change(c) = c {
+ libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
+ libpijul::changestore::filesystem::push_filename(&mut path, &c);
+ super::PROGRESS.borrow_mut().unwrap()[pro_n].incr();
+ if std::fs::metadata(&path).is_ok() {
+ debug!("metadata {:?} ok", path);
+ libpijul::changestore::filesystem::pop_filename(&mut path);
+ continue;
+ }
+ std::fs::create_dir_all(&path.parent().unwrap())?;
+ if std::fs::hard_link(&self.changes_dir, &path).is_err() {
+ std::fs::copy(&self.changes_dir, &path)?;
+ }
+ debug!("hard link done");
+ libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
edit in pijul/src/remote/local.rs at line 217
[11.12233]→[11.943:969](∅→∅),
[11.969]→[11.12258:12272](∅→∅),
[11.12258]→[11.12258:12272](∅→∅),
[11.12272]→[11.12272:12464](∅→∅) − continue;
− }
− std::fs::create_dir_all(&path.parent().unwrap())?;
− if std::fs::hard_link(&self.changes_dir, &path).is_err() {
− std::fs::copy(&self.changes_dir, &path)?;
edit in pijul/src/remote/local.rs at line 218
[11.12478]→[11.12478:12672](∅→∅) − debug!("hard link done");
− libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
− libpijul::changestore::filesystem::pop_filename(&mut path);
replacement in pijul/src/remote/local.rs at line 263
[11.394]→[11.3988:4010](∅→∅),
[11.3988]→[11.3988:4010](∅→∅) replacement in pijul/src/remote/local.rs at line 268
[11.4116]→[11.444:508](∅→∅) − txn.apply_change_ws(store, &mut *channel, c, &mut ws)?;
+ match c {
+ CS::Change(c) => {
+ txn.apply_change_ws(store, &mut *channel, c, &mut ws)?;
+ }
+ CS::State(c) => {
+ if let Some(n) = txn.channel_has_state(txn.states(&*channel), &c.into())? {
+ let tags = txn.tags_mut(&mut *channel);
+ txn.put_tags(tags, n.into(), c)?;
+ } else {
+ bail!(
+ "Cannot add tag {}: channel {:?} does not have that state",
+ c.to_base32(),
+ txn.name(&*channel)
+ )
+ }
+ }
+ }
edit in pijul/src/remote/local.rs at line 289
[11.3543]→[11.82954:83149](∅→∅),
[11.82954]→[11.82954:83149](∅→∅) − debug!("hard link done");
− libpijul::changestore::filesystem::pop_filename(&mut local);
− libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
resolve order conflict in pijul/src/remote/local.rs at line 289
edit in pijul/src/remote/http.rs at line 9
+
+ use crate::remote::CS;
replacement in pijul/src/remote/http.rs at line 25
[11.124]→[11.124:157](∅→∅),
[11.157]→[11.0:55](∅→∅),
[11.55]→[11.190:259](∅→∅),
[11.190]→[11.190:259](∅→∅) − c: libpijul::pristine::Hash,
− ) -> Result<libpijul::pristine::Hash, anyhow::Error> {
− libpijul::changestore::filesystem::push_filename(&mut path, &c);
+ c: CS,
+ ) -> Result<CS, anyhow::Error> {
+ let (req, c32) = match c {
+ CS::Change(c) => {
+ libpijul::changestore::filesystem::push_filename(&mut path, &c);
+ ("change", c.to_base32())
+ }
+ CS::State(c) => {
+ libpijul::changestore::filesystem::push_tag_filename(&mut path, &c);
+ if std::fs::metadata(&path).is_ok() {
+ bail!("Tag already downloaded: {}", c.to_base32())
+ }
+ ("tag", c.to_base32())
+ }
+ };
edit in pijul/src/remote/http.rs at line 43
[11.89]→[11.406:499](∅→∅),
[11.406]→[11.406:499](∅→∅) − libpijul::changestore::filesystem::pop_filename(&mut path);
− let c32 = c.to_base32();
replacement in pijul/src/remote/http.rs at line 67
[11.139]→[11.139:179](∅→∅) − .query(&[("change", &c32)])
replacement in pijul/src/remote/http.rs at line 121
[11.1318]→[11.1318:1385](∅→∅) − std::fs::rename(&path_, &path_.with_extension("change"))?;
+ match c {
+ CS::Change(_) => {
+ std::fs::rename(&path_, &path)?;
+ }
+ CS::State(_) => {
+ std::fs::rename(&path_, &path)?;
+ }
+ }
replacement in pijul/src/remote/http.rs at line 139
[11.2949]→[11.4891:4976](∅→∅),
[11.4891]→[11.4891:4976](∅→∅),
[11.3169]→[11.1180:1252](∅→∅),
[11.4976]→[11.1180:1252](∅→∅),
[11.1180]→[11.1180:1252](∅→∅) − hashes: &mut tokio::sync::mpsc::UnboundedReceiver<libpijul::pristine::Hash>,
− send: &mut tokio::sync::mpsc::Sender<libpijul::pristine::Hash>,
+ hashes: &mut tokio::sync::mpsc::UnboundedReceiver<CS>,
+ send: &mut tokio::sync::mpsc::Sender<CS>,
replacement in pijul/src/remote/http.rs at line 190
[11.938]→[11.938:974](∅→∅) − changes: &[libpijul::Hash],
edit in pijul/src/remote/http.rs at line 193
[11.1148]→[11.1148:1226](∅→∅) − libpijul::changestore::filesystem::push_filename(&mut local, &c);
edit in pijul/src/remote/http.rs at line 203
[11.1541]→[11.1289:1338](∅→∅),
[11.1289]→[11.1289:1338](∅→∅) − let change = std::fs::read(&local)?;
replacement in pijul/src/remote/http.rs at line 208
[11.1506]→[11.1506:1585](∅→∅) − let c = c.to_base32();
− to_channel.push(("apply", &c));
+ let base32;
+ let body = match c {
+ CS::Change(c) => {
+ libpijul::changestore::filesystem::push_filename(&mut local, &c);
+ let change = std::fs::read(&local)?;
+ base32 = c.to_base32();
+ to_channel.push(("apply", &base32));
+ change
+ }
+ CS::State(c) => {
+ libpijul::changestore::filesystem::push_tag_filename(&mut local, &c);
+ let mut tag_file = libpijul::tag::OpenTagFile::open(&local, &c)?;
+ let mut v = Vec::new();
+ tag_file.short(&mut v)?;
+ base32 = c.to_base32();
+ to_channel.push(("tagup", &base32));
+ v
+ }
+ };
+ libpijul::changestore::filesystem::pop_filename(&mut local);
replacement in pijul/src/remote/http.rs at line 234
[11.355]→[11.1727:1757](∅→∅),
[11.1727]→[11.1727:1757](∅→∅) edit in pijul/src/remote/http.rs at line 250
[7.597]→[11.1835:1908](∅→∅),
[11.1835]→[11.1835:1908](∅→∅) − libpijul::changestore::filesystem::pop_filename(&mut local);
replacement in pijul/src/remote/http.rs at line 303
[11.6079]→[11.3070:3171](∅→∅) − super::ListLine::Change { n, m, h, is_tagged } => f(a, n, h, m, is_tagged)?,
+ super::ListLine::Change { n, m, h, tag } => f(a, n, h, m, tag)?,
replacement in pijul/src/remote/http.rs at line 323
[11.242]→[11.242:308](∅→∅) − ) -> Result<Option<(u64, libpijul::Merkle)>, anyhow::Error> {
+ ) -> Result<Option<(u64, libpijul::Merkle, libpijul::Merkle)>, anyhow::Error> {
replacement in pijul/src/remote/http.rs at line 348
[3.45]→[11.1028:1066](∅→∅),
[11.1028]→[11.1028:1066](∅→∅) − if let (Some(n), Some(m)) = (
+ if let (Some(n), Some(m), Some(m2)) = (
edit in pijul/src/remote/http.rs at line 352
+ s.next()
+ .and_then(|m| libpijul::Merkle::from_base32(m.as_bytes())),
replacement in pijul/src/remote/http.rs at line 355
[11.1226]→[11.1226:1255](∅→∅) edit in pijul/src/commands/unrecord.rs at line 4
+ use crate::remote::CS;
+ use crate::repository::Repository;
edit in pijul/src/commands/unrecord.rs at line 12
[11.95786]→[11.1252:1287](∅→∅),
[11.1287]→[11.1287:1288](∅→∅) − use crate::repository::Repository;
−
replacement in pijul/src/commands/unrecord.rs at line 74
[11.1926]→[11.3416:3466](∅→∅),
[11.3416]→[11.3416:3466](∅→∅) − .map(|h| (h.unwrap().1).0.into())
+ .map(|h| CS::Change((h.unwrap().1).0.into()))
replacement in pijul/src/commands/unrecord.rs at line 79
[11.3695]→[11.3695:3769](∅→∅) − hashes.push((*h, *txn.get_internal(&h.into())?.unwrap()))
+ if let CS::Change(h) = h {
+ hashes.push((*h, *txn.get_internal(&h.into())?.unwrap()))
+ }
edit in pijul/src/commands/tag.rs at line 16
+ #[clap(long = "repository")]
+ repo_path: Option<PathBuf>,
+ #[clap(long = "channel")]
+ channel: Option<String>,
replacement in pijul/src/commands/tag.rs at line 187
[11.268]→[11.690:747](∅→∅) − let repo = Repository::find_root(None)?;
+ let repo = Repository::find_root(self.repo_path)?;
replacement in pijul/src/commands/tag.rs at line 189
[11.494]→[11.602:769](∅→∅) − let channel_name = txn
− .current_channel()
− .unwrap_or(crate::DEFAULT_CHANNEL)
− .to_string();
+ let channel_name = self.channel.unwrap_or_else(|| {
+ txn.current_channel()
+ .unwrap_or(crate::DEFAULT_CHANNEL)
+ .to_string()
+ });
replacement in pijul/src/commands/tag.rs at line 202
[11.3209]→[11.821:936](∅→∅) − let t = (*t?).into();
− let (_, m) = txn.get_changes(&channel, t)?.unwrap();
+ let (t, _) = t?;
+ let (_, m) = txn.get_changes(&channel, (*t).into())?.unwrap();
replacement in pijul/src/commands/pushpull.rs at line 17
[11.4805]→[11.18517:18574](∅→∅) − use crate::remote::{PushDelta, RemoteDelta, RemoteRepo};
+ use crate::remote::{PushDelta, RemoteDelta, RemoteRepo, CS};
edit in pijul/src/commands/pushpull.rs at line 94
+ /// Push tags instead of regular changes.
+ #[clap(long = "tag")]
+ is_tag: bool,
edit in pijul/src/commands/pushpull.rs at line 131
+ /// Pull tags instead of regular changes.
+ #[clap(long = "tag")]
+ is_tag: bool,
edit in pijul/src/commands/pushpull.rs at line 153
edit in pijul/src/commands/pushpull.rs at line 163
replacement in pijul/src/commands/pushpull.rs at line 234
[11.20360]→[11.20360:20436](∅→∅) − .to_upload(&mut *txn.write(), &mut channel, &repo, &mut remote)
+ .to_upload(
+ &mut *txn.write(),
+ &mut channel,
+ &repo,
+ &mut remote,
+ self.is_tag,
+ )
replacement in pijul/src/commands/pushpull.rs at line 255
[11.426]→[11.11039:11096](∅→∅) − let mut u: Vec<libpijul::Hash> = Vec::new();
+ let mut u: Vec<CS> = Vec::new();
replacement in pijul/src/commands/pushpull.rs at line 261
− if to_upload.contains(&hash) {
− u.push(hash);
+ if to_upload.contains(&CS::Change(hash)) {
+ u.push(CS::Change(hash));
replacement in pijul/src/commands/pushpull.rs at line 273
[11.913]→[11.673:884](∅→∅) − u.sort_by(|a, b| {
− let na = txn.get_revchanges(&channel, a).unwrap().unwrap();
− let nb = txn.get_revchanges(&channel, b).unwrap().unwrap();
− na.cmp(&nb)
+ u.sort_by(|a, b| match (a, b) {
+ (CS::Change(a), CS::Change(b)) => {
+ let na = txn.get_revchanges(&channel, a).unwrap().unwrap();
+ let nb = txn.get_revchanges(&channel, b).unwrap().unwrap();
+ na.cmp(&nb)
+ }
+ (CS::State(a), CS::State(b)) => {
+ let na = txn
+ .channel_has_state(txn.states(&*channel.read()), &a.into())
+ .unwrap()
+ .unwrap();
+ let nb = txn
+ .channel_has_state(txn.states(&*channel.read()), &b.into())
+ .unwrap()
+ .unwrap();
+ na.cmp(&nb)
+ }
+ _ => unreachable!(),
edit in pijul/src/commands/pushpull.rs at line 344
edit in pijul/src/commands/pushpull.rs at line 359
edit in pijul/src/commands/pushpull.rs at line 424
[11.21985]→[9.107:125](∅→∅) replacement in pijul/src/commands/pushpull.rs at line 426
[11.22017]→[11.22017:22099](∅→∅) − .to_download(&mut *txn.write(), &mut channel, &mut repo, &mut remote)
+ .to_download(
+ &mut *txn.write(),
+ &mut channel,
+ &mut repo,
+ &mut remote,
+ self.is_tag,
+ )
replacement in pijul/src/commands/pushpull.rs at line 479
[11.197]→[11.11789:11872](∅→∅) − txn.apply_change_rec_ws(&repo.changes, &mut channel, h, &mut ws)?;
+ match h {
+ CS::Change(h) => {
+ txn.apply_change_rec_ws(&repo.changes, &mut channel, h, &mut ws)?;
+ }
+ CS::State(s) => {
+ if let Some(n) = txn.channel_has_state(&channel.states, &s.into())? {
+ txn.put_tags(&mut channel.tags, n.into(), s)?;
+ } else {
+ bail!(
+ "Cannot add tag {}: channel {:?} does not have that state",
+ s.to_base32(),
+ channel.name
+ )
+ }
+ }
+ }
replacement in pijul/src/commands/pushpull.rs at line 510
[11.839]→[11.10396:10518](∅→∅),
[11.10518]→[11.952:1144](∅→∅),
[11.952]→[11.952:1144](∅→∅),
[11.1144]→[11.1144:1166](∅→∅),
[11.1166]→[11.1166:1227](∅→∅),
[11.1227]→[11.10519:10602](∅→∅),
[11.10602]→[11.1301:1432](∅→∅),
[11.12018]→[11.1301:1432](∅→∅),
[11.1301]→[11.1301:1432](∅→∅),
[11.1432]→[11.16143:16191](∅→∅) − if let Some(int) = txn_.get_internal(&d.into())? {
− for inode in txn_.iter_rev_touched(int)? {
− let (int_, inode) = inode?;
− if int_ < int {
− continue;
− } else if int_ > int {
− break;
− }
− let ext = libpijul::pristine::Position {
− change: txn_.get_external(&inode.change)?.unwrap().into(),
− pos: inode.pos,
− };
− if inodes.is_empty() || inodes.contains(&ext) {
− touched.insert(*inode);
+ match d {
+ CS::Change(d) => {
+ if let Some(int) = txn_.get_internal(&d.into())? {
+ for inode in txn_.iter_rev_touched(int)? {
+ let (int_, inode) = inode?;
+ if int_ < int {
+ continue;
+ } else if int_ > int {
+ break;
+ }
+ let ext = libpijul::pristine::Position {
+ change: txn_.get_external(&inode.change)?.unwrap().into(),
+ pos: inode.pos,
+ };
+ if inodes.is_empty() || inodes.contains(&ext) {
+ touched.insert(*inode);
+ }
+ }
edit in pijul/src/commands/pushpull.rs at line 529
+ }
+ CS::State(_) => {
+ // No need to do anything for now here, we don't
+ // output after downloading a tag.
replacement in pijul/src/commands/pushpull.rs at line 552
− if touched_paths.is_empty() {
+ if touched_paths.is_empty() && !self.is_tag {
replacement in pijul/src/commands/pushpull.rs at line 602
[11.854]→[4.203:236](∅→∅),
[4.236]→[11.2859:2937](∅→∅),
[11.2859]→[11.2859:2937](∅→∅) − original: &[libpijul::Hash],
− now: &[libpijul::Hash],
− ) -> Result<Vec<libpijul::Hash>, anyhow::Error> {
+ original: &[CS],
+ now: &[CS],
+ ) -> Result<Vec<CS>, anyhow::Error> {
replacement in pijul/src/commands/pushpull.rs at line 612
[4.567]→[11.1171:1214](∅→∅),
[11.1171]→[11.1171:1214](∅→∅),
[11.1214]→[4.568:638](∅→∅) − for d in c.get_dependencies(&h)? {
− if original.get(&d).is_some() && now_.get(&d).is_none() {
+ let hh = if let CS::Change(h) = h {
+ h
+ } else {
+ stack.pop();
+ result.push(h);
+ continue;
+ };
+ for d in c.get_dependencies(&hh)? {
+ if original.get(&CS::Change(d)).is_some() && now_.get(&CS::Change(d)).is_none() {
replacement in pijul/src/commands/pushpull.rs at line 622
+ stack.push(CS::Change(d));
replacement in pijul/src/commands/pushpull.rs at line 636
[11.1487]→[11.122682:122724](∅→∅),
[11.122682]→[11.122682:122724](∅→∅),
[11.122724]→[11.2938:2999](∅→∅),
[11.2999]→[11.122805:122838](∅→∅),
[11.122805]→[11.122805:122838](∅→∅) − fn check_deps<C: ChangeStore>(
− c: &C,
− original: &[libpijul::Hash],
− now: &[libpijul::Hash],
− ) -> Result<(), anyhow::Error> {
+ fn check_deps<C: ChangeStore>(c: &C, original: &[CS], now: &[CS]) -> Result<(), anyhow::Error> {
edit in pijul/src/commands/pushpull.rs at line 641
+ let n = if let CS::Change(n) = n { n } else { continue };
replacement in pijul/src/commands/pushpull.rs at line 643
[11.123079]→[11.123079:123150](∅→∅) − if original_.get(&d).is_some() && now_.get(&d).is_none() {
+ if original_.get(&CS::Change(d)).is_some() && now_.get(&CS::Change(d)).is_none() {
replacement in pijul/src/commands/pushpull.rs at line 651
[11.22311]→[11.22311:22390](∅→∅) − fn notify_remote_unrecords(repo: &Repository, remote_unrecs: &[(u64, Hash)]) {
+ fn notify_remote_unrecords(repo: &Repository, remote_unrecs: &[(u64, crate::remote::CS)]) {
replacement in pijul/src/commands/pushpull.rs at line 660
[11.22751]→[11.22751:22824](∅→∅) − let header = &repo.changes.get_change(hash).unwrap().header;
+ let header = match hash {
+ CS::Change(hash) => repo.changes.get_header(hash).unwrap(),
+ CS::State(hash) => repo.changes.get_tag_header(hash).unwrap(),
+ };
replacement in pijul/src/commands/pushpull.rs at line 665
[11.22855]→[11.22855:23141](∅→∅) − writeln!(&mut s, "# {}", header.message).expect("Infallible write to String");
− writeln!(&mut s, "# {}", header.timestamp).expect("Infallible write to String");
− writeln!(&mut s, "# {}", hash.to_base32()).expect("Infallible write to String");
+ writeln!(&mut s, "# {}", header.message).unwrap();
+ writeln!(&mut s, "# {}", header.timestamp).unwrap();
+ match hash {
+ CS::Change(hash) => {
+ writeln!(&mut s, "# {}", hash.to_base32()).unwrap();
+ }
+ CS::State(hash) => {
+ writeln!(&mut s, "# {}", hash.to_base32()).unwrap();
+ }
+ }
replacement in pijul/src/commands/pushpull.rs at line 685
[11.23354]→[11.23354:23408](∅→∅) − fn notify_unknown_changes(unknown_changes: &[Hash]) {
+ fn notify_unknown_changes(unknown_changes: &[crate::remote::CS]) {
replacement in pijul/src/commands/pushpull.rs at line 695
[11.23767]→[11.23767:23864](∅→∅) − writeln!(&mut s, "# {}", hash.to_base32()).expect("Infallible write to String");
+ let hash = match hash {
+ CS::Change(hash) => hash.to_base32(),
+ CS::State(hash) => hash.to_base32(),
+ };
+ writeln!(&mut s, "# {}", hash).expect("Infallible write to String");
replacement in pijul/src/commands/protocol.rs at line 34
[11.124152]→[8.0:90](∅→∅) − static ref TAG: Regex = Regex::new(r#"^tag\s+(\S+)\s+(\S+)\s+([0-9]+)\s+"#).unwrap();
+ static ref TAG: Regex = Regex::new(r#"^tag\s+(\S+)\s+"#).unwrap();
+ static ref TAGUP: Regex = Regex::new(r#"^tagup\s+(\S+)\s+(\S+)\s+([0-9]+)\s+"#).unwrap();
replacement in pijul/src/commands/protocol.rs at line 81
[11.125737]→[11.11597:11667](∅→∅) − for x in txn.read().log(&*channel.read(), pos)? {
+ let txn = txn.read();
+ for x in txn.log(&*channel.read(), pos)? {
replacement in pijul/src/commands/protocol.rs at line 92
[11.12250]→[11.1272:1345](∅→∅),
[11.1272]→[11.1272:1345](∅→∅) − writeln!(o, "{} {}", n, m.to_base32())?;
+ let m2 = if let Some(x) = txn
+ .rev_iter_tags(txn.tags(&*channel.read()), Some(n))?
+ .next()
+ {
+ x?.1.b.into()
+ } else {
+ Merkle::zero()
+ };
+ writeln!(o, "{} {} {}", n, m.to_base32(), m2.to_base32())?;
edit in pijul/src/commands/protocol.rs at line 105
[11.126196]→[11.11668:11765](∅→∅),
[11.11765]→[11.15540:15582](∅→∅),
[11.17836]→[11.15540:15582](∅→∅),
[11.15540]→[11.15540:15582](∅→∅),
[11.15582]→[11.12251:12297](∅→∅),
[11.12297]→[11.1515:1575](∅→∅),
[11.15582]→[11.1515:1575](∅→∅),
[11.1515]→[11.1515:1575](∅→∅) − } else if let Some(x) = txn.read().reverse_log(&*channel.read(), None)?.next() {
− let (n, (_, m)) = x?;
− let m: Merkle = m.into();
− writeln!(o, "{} {}", n, m.to_base32())?
replacement in pijul/src/commands/protocol.rs at line 106
[11.126221]→[11.1576:1615](∅→∅) + let txn = txn.read();
+ if let Some(x) = txn.reverse_log(&*channel.read(), None)?.next() {
+ let (n, (_, m)) = x?;
+ let m: Merkle = m.into();
+ let m2 = if let Some(x) = txn
+ .rev_iter_tags(txn.tags(&*channel.read()), Some(n))?
+ .next()
+ {
+ x?.1.b.into()
+ } else {
+ Merkle::zero()
+ };
+ writeln!(o, "{} {} {}", n, m.to_base32(), m2.to_base32())?
+ } else {
+ writeln!(o, "-")?;
+ }
edit in pijul/src/commands/protocol.rs at line 150
+ let tags: Vec<u64> = txn
+ .iter_tags(txn.tags(&*channel.read()), from)?
+ .map(|k| (*k.unwrap().0).into())
+ .collect();
+ let mut tagsi = 0;
replacement in pijul/src/commands/protocol.rs at line 166
[11.12631]→[11.3172:3328](∅→∅) − if txn.is_tagged(&channel.read().tags, n)? {
− writeln!(o, "{}.{}.{}.", n, h.to_base32(), m.to_base32())?
+ if paths.is_empty() && tags.get(tagsi) == Some(&n) {
+ writeln!(o, "{}.{}.{}.", n, h.to_base32(), m.to_base32(),)?;
+ tagsi += 1;
replacement in pijul/src/commands/protocol.rs at line 170
[11.3361]→[11.3361:3447](∅→∅) − writeln!(o, "{}.{}.{}", n, h.to_base32(), m.to_base32())?
+ writeln!(o, "{}.{}.{}", n, h.to_base32(), m.to_base32())?;
edit in pijul/src/commands/protocol.rs at line 178
+ let mut tag_path = repo.changes_dir.clone();
+ libpijul::changestore::filesystem::push_tag_filename(&mut tag_path, &state);
+ let mut tag = libpijul::tag::OpenTagFile::open(&tag_path, &state)?;
+ let mut buf = Vec::new();
+ tag.short(&mut buf)?;
+ o.write_u64::<BigEndian>(buf.len() as u64)?;
+ o.write_all(&buf)?;
+ o.flush()?;
+ }
+ } else if let Some(cap) = TAGUP.captures(&buf) {
+ if let Some(state) = Merkle::from_base32(cap[1].as_bytes()) {
edit in pijul/src/commands/protocol.rs at line 192
+ let mut tag_path = repo.changes_dir.clone();
+ libpijul::changestore::filesystem::push_tag_filename(&mut tag_path, &m);
+ if std::fs::metadata(&tag_path).is_ok() {
+ bail!("Tag for state {} already exists", m.to_base32());
+ }
+
edit in pijul/src/commands/protocol.rs at line 209
[11.848]→[11.848:1162](∅→∅) − let mut tag_path = repo.changes_dir.clone();
− std::fs::create_dir_all(&tag_path)?;
−
− let mut temp_path = tag_path.clone();
− temp_path.push("tmp");
−
− let mut w = std::fs::File::create(&temp_path)?;
−
replacement in pijul/src/commands/protocol.rs at line 213
[11.1332]→[11.1332:1398](∅→∅) − let header = bincode::deserialize(&buf)?;
+ let header = libpijul::tag::read_short(std::io::Cursor::new(&buf[..]), &m)?;
+
+ let temp_path = tag_path.with_extension("tmp");
+
+ std::fs::create_dir_all(temp_path.parent().unwrap())?;
+ let mut w = std::fs::File::create(&temp_path)?;
replacement in pijul/src/commands/protocol.rs at line 220
[11.1492]→[11.1492:1667](∅→∅) − libpijul::changestore::filesystem::push_tag_filename(&mut tag_path, &m);
− std::fs::create_dir_all(tag_path.parent().unwrap())?;
edit in pijul/src/commands/mod.rs at line 151
+
+ use crate::remote::CS;
replacement in pijul/src/commands/mod.rs at line 158
[11.3136]→[11.3136:3169](∅→∅) − pullable: &[libpijul::Hash],
replacement in pijul/src/commands/mod.rs at line 180
[11.3733]→[11.3733:4003](∅→∅) − writeln!(v, "{}\n", p.to_base32()).unwrap();
− let deps = changes.get_dependencies(&p)?;
− if !deps.is_empty() {
− write!(v, " Dependencies:").unwrap();
− for d in deps {
− write!(v, " {}", d.to_base32()).unwrap();
+ let header = match p {
+ CS::Change(p) => {
+ writeln!(v, "{}\n", p.to_base32()).unwrap();
+ let deps = changes.get_dependencies(&p)?;
+ if !deps.is_empty() {
+ write!(v, " Dependencies:").unwrap();
+ for d in deps {
+ write!(v, " {}", d.to_base32()).unwrap();
+ }
+ writeln!(v).unwrap();
+ }
+ changes.get_header(&p)?
+ }
+ CS::State(p) => {
+ writeln!(v, "t{}\n", p.to_base32()).unwrap();
+ changes.get_tag_header(&p)?
replacement in pijul/src/commands/mod.rs at line 197
[11.4017]→[11.4017:4107](∅→∅) − writeln!(v).unwrap();
− }
− let change = changes.get_header(&p)?;
replacement in pijul/src/commands/mod.rs at line 200
[11.4180]→[11.4180:4221](∅→∅) − for a in change.authors.iter() {
+ for a in header.authors.iter() {
replacement in pijul/src/commands/mod.rs at line 212
[11.4414]→[11.4414:4520](∅→∅) − writeln!(v, " Date: {}\n", change.timestamp).unwrap();
− for l in change.message.lines() {
+ writeln!(v, " Date: {}\n", header.timestamp).unwrap();
+ for l in header.message.lines() {
replacement in pijul/src/commands/mod.rs at line 216
[11.4577]→[11.4577:4626](∅→∅) − if let Some(desc) = change.description {
+ if let Some(desc) = header.description {
replacement in pijul/src/commands/mod.rs at line 229
[11.4940]→[11.4940:4995](∅→∅) − fn parse_changelist(o: &[u8]) -> Vec<libpijul::Hash> {
+ fn parse_changelist(o: &[u8]) -> Vec<crate::remote::CS> {
replacement in pijul/src/commands/mod.rs at line 233
[11.5083]→[11.5083:5154](∅→∅) − .filter_map(|l| libpijul::Hash::from_base32(l.as_bytes()))
+ .filter_map(|l| {
+ ::log::debug!(
+ "l = {:?} {:?}",
+ l,
+ libpijul::Merkle::from_base32(l.as_bytes())
+ );
+ if l.starts_with("t") {
+ libpijul::Merkle::from_base32(&l.as_bytes()[1..]).map(crate::remote::CS::State)
+ } else {
+ libpijul::Hash::from_base32(l.as_bytes()).map(crate::remote::CS::Change)
+ }
+ })
edit in libpijul/src/tag.rs at line 100
+
+ pub fn short<W: std::io::Write>(&mut self, mut w: W) -> Result<(), TagError> {
+ let mut header_buf = vec![0u8; (self.header.channel - self.header.header) as usize];
+
+ self.file.seek(SeekFrom::Start(self.header.header))?;
+ self.file.read_exact(&mut header_buf)?;
+ debug!("header_buf = {:?}", header_buf);
+ let mut off = FileHeader {
+ version: VERSION,
+ header: 0,
+ channel: 0,
+ unhashed: 0,
+ total: 0,
+ offsets: DbOffsets::default(),
+ state: self.header.state.clone(),
+ };
+ off.header = bincode::serialized_size(&off)?;
+ off.channel = off.header + header_buf.len() as u64;
+ off.total = off.channel;
+ let mut off_buf = Vec::with_capacity(off.header as usize);
+ bincode::serialize_into(&mut off_buf, &off)?;
+ w.write_all(&off_buf)?;
+ w.write_all(&header_buf)?;
+ Ok(())
+ }
+ }
+
+ pub fn read_short<R: std::io::Read + std::io::Seek>(mut file: R, expected: &Merkle) -> Result<crate::change::ChangeHeader, TagError> {
+ let mut off = [0u8; std::mem::size_of::<FileHeader>() as usize];
+ file.seek(SeekFrom::Start(0))?;
+ file.read_exact(&mut off)?;
+ let header: FileHeader = bincode::deserialize(&off).map_err(TagError::BincodeDe)?;
+ debug!("header = {:?}", header);
+ if &header.state == expected {
+ file.seek(SeekFrom::Start(header.header))?;
+ Ok(bincode::deserialize_from(file).map_err(TagError::BincodeDe)?)
+ } else {
+ Err(TagError::WrongHash {
+ expected: *expected,
+ got: header.state,
+ })
+ }
replacement in libpijul/src/tag.rs at line 520
[11.19425]→[10.0:124](∅→∅) − let tags = copy::<L64, Pair<SerializedMerkle, SerializedMerkle>, UP<L64, Pair<SerializedMerkle, SerializedMerkle>>, _>(
+ debug!("copying tags");
+ let tags = copy::<L64, Pair<SerializedMerkle, SerializedMerkle>, P<L64, Pair<SerializedMerkle, SerializedMerkle>>, _>(
replacement in libpijul/src/tag/txn.rs at line 227
[11.6778]→[11.6778:6952](∅→∅) − type Changeset = u64; // Db<ChangeId, L64>;
− type RevChangeset = u64; // UDb<L64, Pair<ChangeId, SerializedMerkle>>;
− type Tags = u64; // UDb<L64, SerializedHash>;
+ type Changeset = u64;
+ type RevChangeset = u64;
+ type Tags = u64;
replacement in libpijul/src/tag/txn.rs at line 231
[11.6953]→[11.6953:7007](∅→∅) − type States = u64; // UDb<SerializedMerkle, L64>;
replacement in libpijul/src/tag/txn.rs at line 406
[11.2335]→[11.2335:2400](∅→∅) − ::sanakirja::btree::cursor::Cursor<L64, (), P<L64, ()>>;
+ ::sanakirja::btree::cursor::Cursor<L64, Pair<SerializedMerkle, SerializedMerkle>, P<L64, Pair<SerializedMerkle, SerializedMerkle>>>;
replacement in libpijul/src/tag/txn.rs at line 410
[11.2540]→[11.2540:2592](∅→∅) − let db: Db<L64, ()> = Db::from_page(*tags);
+ let db: Db<L64, Pair<SerializedMerkle, SerializedMerkle>> = Db::from_page(*tags);
replacement in libpijul/src/tag/txn.rs at line 423
[11.13339]→[11.2754:2832](∅→∅) − crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/tag/txn.rs at line 427
[11.2877]→[11.2877:2932](∅→∅) − let db: Db<L64, ()> = Db::from_page(*channel);
+ let db: Db<L64, Pair<SerializedMerkle, SerializedMerkle>> = Db::from_page(*channel);
replacement in libpijul/src/tag/txn.rs at line 443
[11.14025]→[11.2933:2991](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/tag/txn.rs at line 445
[11.14145]→[11.2992:3026](∅→∅) replacement in libpijul/src/tag/txn.rs at line 454
[11.14340]→[11.3027:3085](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/tag/txn.rs at line 456
[11.14460]→[11.3086:3120](∅→∅) replacement in libpijul/src/tag/txn.rs at line 467
[11.14675]→[11.3121:3194](∅→∅) − crate::pristine::Cursor<Self, &Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/tag/txn.rs at line 478
[11.14973]→[11.3195:3271](∅→∅) − crate::pristine::RevCursor<Self, &Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::RevCursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/tag/txn.rs at line 482
[11.3316]→[11.3316:3371](∅→∅) − let db: Db<L64, ()> = Db::from_page(*channel);
+ let db: Db<L64, Pair<SerializedMerkle, SerializedMerkle>> = Db::from_page(*channel);
replacement in libpijul/src/tag/txn.rs at line 752
[11.23017]→[11.3511:3589](∅→∅) − crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/tag/txn.rs at line 760
[11.23298]→[11.3590:3648](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/tag/txn.rs at line 767
[11.23503]→[11.3649:3707](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/tag/txn.rs at line 776
[11.23728]→[11.3708:3781](∅→∅) − crate::pristine::Cursor<Self, &Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/tag/txn.rs at line 787
[11.24038]→[11.3782:3858](∅→∅) − crate::pristine::RevCursor<Self, &Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::RevCursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/pristine/sanakirja.rs at line 947
[11.23676]→[11.4233:4311](∅→∅) − crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/pristine/sanakirja.rs at line 965
[11.24249]→[11.4312:4370](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/pristine/sanakirja.rs at line 967
[11.24374]→[11.4371:4405](∅→∅) replacement in libpijul/src/pristine/sanakirja.rs at line 976
[11.24562]→[11.4406:4464](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/pristine/sanakirja.rs at line 978
[11.24687]→[11.4465:4499](∅→∅) replacement in libpijul/src/pristine/sanakirja.rs at line 988
[11.2167]→[9.809:906](∅→∅) − ) -> Result<super::Cursor<Self, &Self, Self::TagsCursor, L64, ()>, TxnErr<Self::GraphError>>
+ ) -> Result<super::Cursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>, TxnErr<Self::GraphError>>
replacement in libpijul/src/pristine/sanakirja.rs at line 997
[11.2455]→[9.913:1013](∅→∅) − ) -> Result<super::RevCursor<Self, &Self, Self::TagsCursor, L64, ()>, TxnErr<Self::GraphError>>
+ ) -> Result<super::RevCursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>, TxnErr<Self::GraphError>>
edit in libpijul/src/pristine/sanakirja.rs at line 1231
+ fn state_from_prefix(
+ &self,
+ channel: &Self::Channel,
+ s: &str,
+ ) -> Result<(Merkle, L64), super::HashPrefixError<Self::GraphError>> {
+ let h: SerializedMerkle = if let Some(ref h) = Merkle::from_prefix(s) {
+ h.into()
+ } else {
+ return Err(super::HashPrefixError::Parse(s.to_string()));
+ };
+ let mut result = None;
+ debug!("h = {:?}", h);
+ for x in btree::iter(&self.txn, &channel.states, Some((&h, None)))
+ .map_err(|e| super::HashPrefixError::Txn(e.into()))?
+ {
+ let (e, i) = x.map_err(|e| super::HashPrefixError::Txn(e.into()))?;
+ debug!("{:?} {:?}", e, i);
+ if e < &h {
+ continue;
+ } else {
+ let e: Merkle = e.into();
+ let b32 = e.to_base32();
+ debug!("{:?}", b32);
+ let (b32, _) = b32.split_at(s.len().min(b32.len()));
+ if b32 != s {
+ break;
+ } else if result.is_none() {
+ result = Some((e, *i))
+ } else {
+ return Err(super::HashPrefixError::Ambiguous(s.to_string()));
+ }
+ }
+ }
+ if let Some(result) = result {
+ Ok(result)
+ } else {
+ Err(super::HashPrefixError::NotFound(s.to_string()))
+ }
+ }
+
edit in libpijul/src/pristine/sanakirja.rs at line 1431
[11.554746]→[9.1095:1457](∅→∅) − sanakirja_cursor!(remotetags, L64, Pair<SerializedMerkle, SerializedMerkle>);
− sanakirja_rev_cursor!(remotetags, L64, Pair<SerializedMerkle, SerializedMerkle>);
− type RemotetagsCursor = ::sanakirja::btree::cursor::Cursor<
− L64,
− Pair<SerializedMerkle, SerializedMerkle>,
− UP<L64, Pair<SerializedMerkle, SerializedMerkle>>,
− >;
−
edit in libpijul/src/pristine/sanakirja.rs at line 1498
+ debug!("last_remote: {:?}", remote);
replacement in libpijul/src/pristine/sanakirja.rs at line 1509
[9.1497]→[9.1497:1532](∅→∅) − remote: &Self::Remotetags,
edit in libpijul/src/pristine/sanakirja.rs at line 1533
+ }
+
+ fn get_remote_tag(
+ &self,
+ remote: &Self::Tags,
+ n: u64,
+ ) -> Result<Option<(u64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>>
+ {
+ let n = n.into();
+ if let Some(x) = btree::rev_iter(&self.txn, remote, Some((&n, None)))?.next() {
+ let (&k, m) = x?;
+ Ok(Some((k.into(), m)))
+ } else {
+ Ok(None)
+ }
replacement in libpijul/src/pristine/sanakirja.rs at line 1564
[11.82186]→[11.49635:49685](∅→∅),
[11.49635]→[11.49635:49685](∅→∅) − ) -> Result<bool, TxnErr<Self::GraphError>> {
+ ) -> Result<Option<u64>, TxnErr<Self::GraphError>> {
replacement in libpijul/src/pristine/sanakirja.rs at line 1566
[11.63625]→[11.82263:82311](∅→∅),
[11.99032]→[11.82263:82311](∅→∅),
[11.82263]→[11.82263:82311](∅→∅),
[11.82311]→[11.10272:10300](∅→∅) − Some((k, _)) if k == m => Ok(true),
− _ => Ok(false),
+ Some((k, v)) if k == m => Ok(Some((*v).into())),
+ _ => Ok(None),
replacement in libpijul/src/pristine/sanakirja.rs at line 1856
[9.3270]→[9.3270:3318](∅→∅) − debug!("del_changes {:?} {:?}", t_, p);
+ debug!("del_tags {:?} {:?}", t_, p);
replacement in libpijul/src/pristine/sanakirja.rs at line 1904
[11.562292]→[11.3610:3643](∅→∅) − v: (Hash, Merkle, bool),
edit in libpijul/src/pristine/sanakirja.rs at line 1915
+ debug!("remote.remote after put: {:?}", remote.remote);
replacement in libpijul/src/pristine/sanakirja.rs at line 1917
[11.86001]→[11.3644:3661](∅→∅),
[11.3661]→[9.3593:3648](∅→∅),
[9.3648]→[11.3735:3745](∅→∅),
[11.3735]→[11.3735:3745](∅→∅) − if v.2 {
− self.put_tags(&mut remote.tags, k, &v.1)?;
− }
+ // if v.2 {
+ // self.put_tags(&mut remote.tags, k, &v.1)?;
+ // }
edit in libpijul/src/pristine/sanakirja.rs at line 2369
+ _tags: r.tags.db.into(),
edit in libpijul/src/pristine/sanakirja.rs at line 2518
+
+ const REMOTE_LEN: usize = 40;
replacement in libpijul/src/pristine/sanakirja.rs at line 2525
[11.33448]→[11.33448:33477](∅→∅) + REMOTE_LEN + 1 + self.path.len()
replacement in libpijul/src/pristine/sanakirja.rs at line 2528
[11.33534]→[11.33534:33569](∅→∅) − 33 + (*p.add(32)) as usize
+ REMOTE_LEN + 1 + (*p.add(REMOTE_LEN)) as usize
replacement in libpijul/src/pristine/sanakirja.rs at line 2531
[11.33644]→[11.33644:33683](∅→∅) − let len = *p.add(32) as usize;
+ let len = *p.add(REMOTE_LEN) as usize;
replacement in libpijul/src/pristine/sanakirja.rs at line 2540
[11.33957]→[11.33957:33991](∅→∅) + REMOTE_LEN + 1 + self.path.len(),
replacement in libpijul/src/pristine/sanakirja.rs at line 2544
[11.34053]→[11.34053:34117](∅→∅) − std::slice::from_raw_parts(p, 33 + self.path.len())
+ std::slice::from_raw_parts(p, REMOTE_LEN + 1 + self.path.len())
edit in libpijul/src/pristine/sanakirja.rs at line 2555
replacement in libpijul/src/pristine/sanakirja.rs at line 2562
[11.34405]→[11.34405:34455](∅→∅) − let len = 33 + self._path.len() as usize;
+ let len = REMOTE_LEN + 1 + self._path.len() as usize;
replacement in libpijul/src/pristine/mod.rs at line 257
[11.35468]→[11.35468:35536](∅→∅) − #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+ #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
edit in libpijul/src/pristine/mod.rs at line 292
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(fmt, "{}", data_encoding::BASE32_NOPAD.encode(&self.0))
+ }
+ }
+
+ impl std::fmt::Debug for RemoteId {
replacement in libpijul/src/pristine/mod.rs at line 467
[11.26829]→[11.5033:5111](∅→∅) − crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, ()>,
+ crate::pristine::Cursor<Self, &'txn Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
replacement in libpijul/src/pristine/mod.rs at line 474
[11.27039]→[11.5112:5169](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>>;
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>>;
replacement in libpijul/src/pristine/mod.rs at line 479
[11.27195]→[11.5170:5227](∅→∅) − ) -> Result<Option<&L64>, TxnErr<Self::GraphError>>;
+ ) -> Result<Option<(&L64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>>;
replacement in libpijul/src/pristine/mod.rs at line 485
[11.3189]→[11.5228:5319](∅→∅) − ) -> Result<Cursor<Self, &Self, Self::TagsCursor, L64, ()>, TxnErr<Self::GraphError>>;
+ ) -> Result<Cursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>, TxnErr<Self::GraphError>>;
replacement in libpijul/src/pristine/mod.rs at line 492
[11.3427]→[11.5320:5379](∅→∅) − RevCursor<Self, &Self, Self::TagsCursor, L64, ()>,
+ RevCursor<Self, &Self, Self::TagsCursor, L64, Pair<SerializedMerkle, SerializedMerkle>>,
edit in libpijul/src/pristine/mod.rs at line 652
+
+ fn state_from_prefix(
+ &self,
+ channel: &Self::Channel,
+ s: &str,
+ ) -> Result<(Merkle, L64), HashPrefixError<Self::GraphError>>;
+
edit in libpijul/src/pristine/mod.rs at line 695
[11.103300]→[9.3725:3873](∅→∅) − cursor!(remotetags, L64, Pair<SerializedMerkle, SerializedMerkle>);
− rev_cursor!(remotetags, L64, Pair<SerializedMerkle, SerializedMerkle>);
replacement in libpijul/src/pristine/mod.rs at line 732
[9.3913]→[9.3913:3948](∅→∅) − remote: &Self::Remotetags,
edit in libpijul/src/pristine/mod.rs at line 735
+ /// Find the last state greater than or equal to n.
edit in libpijul/src/pristine/mod.rs at line 741
+
+ /// Find the last tag less than or equal to n (opposite of get_remote_state).
+ fn get_remote_tag(
+ &self,
+ remote: &Self::Tags,
+ n: u64,
+ ) -> Result<Option<(u64, &Pair<SerializedMerkle, SerializedMerkle>)>, TxnErr<Self::GraphError>>;
replacement in libpijul/src/pristine/mod.rs at line 758
[11.103794]→[11.60067:60116](∅→∅),
[11.60067]→[11.60067:60116](∅→∅) − ) -> Result<bool, TxnErr<Self::GraphError>>;
+ ) -> Result<Option<u64>, TxnErr<Self::GraphError>>;
edit in libpijul/src/pristine/mod.rs at line 1487
+ initialized_cursor!(tags, L64, Pair<SerializedMerkle, SerializedMerkle>, ChannelTxnT, GraphError);
+ initialized_rev_cursor!(tags, L64, Pair<SerializedMerkle, SerializedMerkle>, ChannelTxnT, GraphError);
edit in libpijul/src/pristine/mod.rs at line 1532
[11.22745]→[11.5380:5769](∅→∅) −
− impl<'a, T: ChannelTxnT> Iterator for crate::pristine::RevCursor<T, &'a T, T::TagsCursor, L64, ()>
− {
− type Item = Result<&'a L64, TxnErr<T::GraphError>>;
− fn next(&mut self) -> Option<Self::Item> {
− match self.txn.cursor_tags_prev(&mut self.cursor) {
− Ok(Some(x)) => Some(Ok(x)),
− Ok(None) => None,
− Err(e) => Some(Err(e)),
− }
− }
− }
edit in libpijul/src/pristine/mod.rs at line 1533
[11.5770]→[11.5770:6520](∅→∅),
[11.1515]→[11.621548:621549](∅→∅),
[11.3690]→[11.621548:621549](∅→∅),
[11.6520]→[11.621548:621549](∅→∅),
[11.68729]→[11.621548:621549](∅→∅),
[11.621548]→[11.621548:621549](∅→∅) − impl<'a, T: ChannelTxnT>
− crate::pristine::Cursor<T, &'a T, T::TagsCursor, L64, ()>
− {
− pub fn prev(&mut self) -> Option<Result<u64, TxnErr<T::GraphError>>> {
− match self.txn.cursor_tags_prev(&mut self.cursor) {
− Ok(Some(x)) => Some(Ok((*x).into())),
− Ok(None) => None,
− Err(e) => Some(Err(e)),
− }
− }
− }
−
− impl<'a, T: ChannelTxnT> Iterator for crate::pristine::Cursor<T, &'a T, T::TagsCursor, L64, ()>
− {
− type Item = Result<u64, TxnErr<T::GraphError>>;
− fn next(&mut self) -> Option<Self::Item> {
− match self.txn.cursor_tags_next(&mut self.cursor) {
− Ok(Some(x)) => Some(Ok((*x).into())),
− Ok(None) => None,
− Err(e) => Some(Err(e)),
− }
− }
− }
−
replacement in libpijul/src/pristine/mod.rs at line 1868
[11.638332]→[11.3929:3962](∅→∅) − v: (Hash, Merkle, bool),
edit in libpijul/src/pristine/merkle.rs at line 3
+
+ pub(crate) const BASE32_BYTES: usize = 53;
edit in libpijul/src/pristine/merkle.rs at line 31
+ impl std::fmt::Debug for SerializedMerkle {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ Merkle::from(self).fmt(fmt)
+ }
+ }
+
edit in libpijul/src/pristine/merkle.rs at line 96
+ }
+ }
+
+ pub fn from_prefix(s: &str) -> Option<Self> {
+ let mut b32 = [b'A'; BASE32_BYTES];
+ if s.len() > BASE32_BYTES {
+ return None;
edit in libpijul/src/pristine/merkle.rs at line 104
+ (&mut b32[..s.len()]).clone_from_slice(s.as_bytes());
+ let bytes = if let Ok(bytes) = data_encoding::BASE32_NOPAD.decode(&b32) {
+ bytes
+ } else {
+ return None;
+ };
+ curve25519_dalek::edwards::CompressedEdwardsY::from_slice(&bytes[..32])
+ .decompress()
+ .map(Merkle::Ed25519)
replacement in libpijul/src/pristine/merkle.rs at line 156
[11.112517]→[11.101552:101614](∅→∅) − #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+ #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
edit in libpijul/src/changestore/mod.rs at line 39
+ fn get_tag_header(&self, h: &crate::Merkle) -> Result<ChangeHeader, Self::Error>;
replacement in libpijul/src/changestore/memory.rs at line 2
[11.820772]→[11.820772:820799](∅→∅) − use crate::change::Change;
+ use crate::change::{Change, ChangeHeader};
edit in libpijul/src/changestore/memory.rs at line 11
+ tags: Arc<RwLock<HashMap<crate::Merkle, ChangeHeader>>>,
edit in libpijul/src/changestore/memory.rs at line 41
+
+ fn get_tag_header(&self, h: &crate::Merkle) -> Result<ChangeHeader, Self::Error> {
+ let changes = self.tags.read().unwrap();
+ Ok(changes.get(&h).unwrap().clone())
+ }
+
edit in libpijul/src/changestore/filesystem.rs at line 33
+ #[error(transparent)]
+ Tag(#[from] crate::tag::TagError),
edit in libpijul/src/changestore/filesystem.rs at line 62
+ path
+ }
+
+ pub fn tag_filename(&self, hash: &Merkle) -> PathBuf {
+ let mut path = self.changes_dir.clone();
+ push_tag_filename(&mut path, hash);
edit in libpijul/src/changestore/filesystem.rs at line 166
+ fn get_tag_header(&self, h: &Merkle) -> Result<ChangeHeader, Self::Error> {
+ let path = self.tag_filename(h);
+ let mut p = crate::tag::OpenTagFile::open(&path, h)?;
+ Ok(p.header()?)
+ }
+