use super::RemoteRef;
use libpijul::pristine::{Base32, Hash, Merkle, MutTxnT, TxnT};
use libpijul::{MutTxnTExt, TxnTExt};
use std::path::{Path, PathBuf};
pub struct Local {
pub channel: String,
pub root: std::path::PathBuf,
pub changes_dir: std::path::PathBuf,
pub pristine: libpijul::pristine::sanakirja::Pristine,
pub name: String,
}
impl Local {
pub fn get_state(&mut self, mid: Option<u64>) -> Result<Option<(u64, Merkle)>, anyhow::Error> {
let txn = self.pristine.txn_begin()?;
let channel = txn.load_channel(&self.channel).unwrap();
if let Some(mid) = mid {
Ok(txn.get_changes(&channel, mid).map(|(_, m)| (mid, m)))
} else {
Ok(txn
.reverse_log(&channel.borrow(), None)
.next()
.map(|(n, (_, m))| (n, m)))
}
}
pub fn download_changelist<T: MutTxnT>(
&mut self,
txn: &mut T,
remote: &mut RemoteRef<T>,
from: u64,
paths: &[String],
) -> Result<(), anyhow::Error> {
let store = libpijul::changestore::filesystem::FileSystem::from_root(&self.root);
let remote_txn = self.pristine.txn_begin()?;
let remote_channel = if let Some(channel) = remote_txn.load_channel(&self.channel) {
channel
} else {
debug!("no remote channel named {:?}", self.channel);
return Ok(());
};
let mut paths_ = Vec::new();
for s in paths {
if let Ok((p, _ambiguous)) = remote_txn.follow_oldest_path(&store, &remote_channel, s) {
paths_.push(p)
}
}
for (n, (h, m)) in remote_txn.log(&remote_channel.borrow(), from) {
if n >= from {
debug!(
"downloading changelist item {:?} {:?} {:?}",
n,
h.to_base32(),
m.to_base32()
);
let h_int = remote_txn.get_internal(h).unwrap();
if paths_.is_empty()
|| paths_
.iter()
.any(|x| remote_txn.get_touched_files(*x, Some(h_int)).is_some())
{
txn.put_remote(remote, n, (h, m))?;
}
}
}
Ok(())
}
pub fn upload_changes(
&mut self,
mut local: PathBuf,
to_channel: Option<&str>,
changes: &[Hash],
) -> Result<(), anyhow::Error> {
let store = libpijul::changestore::filesystem::FileSystem::from_root(&self.root);
let mut txn = self.pristine.mut_txn_begin();
let mut channel = txn.open_or_create_channel(to_channel.unwrap_or(&self.channel))?;
let mut ws = libpijul::ApplyWorkspace::new();
for c in changes {
libpijul::changestore::filesystem::push_filename(&mut local, &c);
libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
std::fs::create_dir_all(&self.changes_dir.parent().unwrap())?;
debug!("hard link {:?} {:?}", local, self.changes_dir);
std::fs::hard_link(&local, &self.changes_dir)?;
debug!("hard link done");
libpijul::changestore::filesystem::pop_filename(&mut local);
libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
txn.apply_change_ws(&store, &mut channel, *c, &mut ws)?;
}
let mut repo = libpijul::working_copy::filesystem::FileSystem::from_root(&self.root);
txn.output_repository_no_pending(&mut repo, &store, &mut channel, "", true)?;
txn.commit()?;
Ok(())
}
pub async fn start_change_download(
&mut self,
c: libpijul::pristine::Hash,
path: &Path,
) -> Result<(), anyhow::Error> {
libpijul::changestore::filesystem::push_filename(&mut self.changes_dir, &c);
debug!("hard link {:?} {:?}", self.changes_dir, path);
std::fs::hard_link(&self.changes_dir, path)?;
debug!("hard link done");
libpijul::changestore::filesystem::pop_filename(&mut self.changes_dir);
debug!("sent");
Ok(())
}
}