QMTANHVNRPQ5IX66FYQBFRBDCTN6YKMNCO6OHTQ6QCUASPWWXJKAC
GHO6DWPILBBTL6CVZKERJBTFL3EY6ZT4YM4E5R4S6YPGVFKFHCVAC
3KRGVQFUWFHPOGZOXVTJYNCM4XBRVYITAEOVPKBSAZ5GZIUO5KVQC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC
I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC
WZVCLZKY34KQBQU6YBGJLQCDADBQ67LQVDNRVCMQVY3O3C3EIWSQC
VQPAUKBQ2POZKL7CZFAZK5ZQKEBYL27XZYZWYUSH5AH25KK6DWKAC
CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC
76PCXGML77EZWTRI5E6KHLVRAFTJ2AB5YRN5EKOYNAPKTWY2KCGAC
if !overwrite_changes {
// No need to change channel, no need to reset.
return Ok(());
if overwrite_changes {
txn.output_repository_no_pending(
&mut repo.working_copy,
&repo.changes,
&mut channel,
&mut HashMap::new(),
"",
true,
)?;
txn.commit()?;
txn.output_repository_no_pending(
&mut repo.working_copy,
&repo.changes,
&mut channel,
&mut HashMap::new(),
"",
true,
)?;
let mut inodes = HashSet::new();
if let Some(cur) = txn.load_channel(current_channel)? {
let mut changediff = HashSet::new();
let (a, b, s) = libpijul::pristine::last_common_state(
&txn,
&cur.borrow(),
&channel.borrow(),
)?;
debug!("last common state {:?}", s);
changes_after(&txn, &cur.borrow(), a, &mut changediff, &mut inodes)?;
changes_after(&txn, &channel.borrow(), b, &mut changediff, &mut inodes)?;
}
if self.channel.is_some() {
repo.config.current_channel = self.channel;
repo.save_config()?;
}
for pos in inodes.iter() {
let (path, _) = libpijul::fs::find_path(
&repo.changes,
&txn,
&channel.borrow(),
false,
*pos,
)?;
debug!("resetting {:?}", path);
txn.output_repository_no_pending(
&mut repo.working_copy,
&repo.changes,
&mut channel,
&mut HashMap::new(),
&path,
true,
)?;
}
}
}
fn changes_after<T: ChannelTxnT + DepsTxnT>(
txn: &T,
chan: &T::Channel,
from: u64,
changediff: &mut HashSet<ChangeId>,
inodes: &mut HashSet<Position<ChangeId>>,
) -> Result<(), anyhow::Error> {
for x in libpijul::pristine::changeid_log(txn, chan, from)? {
let (n, (u, _)) = x?;
debug!("{:?} {:?} {:?}", n, u, from);
if n <= from {
continue;
}
if changediff.insert(u) {
for y in txn.iter_rev_touched_files(u, None)? {
let (uu, pos) = y?;
if uu < u {
continue;
} else if uu > u {
break;
}
inodes.insert(pos);
}
}
}
fn first_state_after<T: ChannelTxnT>(txn: &T, c: &T::Channel, pos: u64) -> Result<Option<(u64, Merkle)>, TxnErr<T::GraphError>> {
for x in T::cursor_revchangeset_ref(txn, T::rev_changes(&c), Some(pos))? {
let (n, (_, m)) = x?;
if n >= pos {
return Ok(Some((n, m)))
}
}
Ok(None)
}
fn last_state<T: ChannelTxnT>(txn: &T, c: &T::Channel) -> Result<Option<(u64, Merkle)>, TxnErr<T::GraphError>> {
if let Some(e) = txn
.rev_cursor_revchangeset(T::rev_changes(&c), None)?
.next()
{
let (b, (_, state)) = e?;
Ok(Some((b, state)))
} else {
Ok(None)
}
}
/// Find the last state of c1 that is also in c0.
pub fn last_common_state<T: ChannelTxnT>(txn: &T, c0: &T::Channel, c1: &T::Channel) -> Result<(u64, u64, Merkle), TxnErr<T::GraphError>> {
let mut a = 0;
let (mut b, mut state) = if let Some(x) = last_state(txn, c1)? {
x
} else {
return Ok((0, 0, Merkle::zero()))
};
if let Some(aa) = txn.channel_has_state(c0, state)? {
return Ok((aa, b, state))
}
let mut aa = 0;
while a < b {
let mid = (a+b) / 2;
let (_, s) = first_state_after(txn, c1, mid)?.unwrap();
state = s;
if let Some(aa_) = txn.channel_has_state(c0, state)? {
aa = aa_;
a = mid
} else {
b = mid
}
}
Ok((aa, a, state))