use std::path::PathBuf;
use clap::Clap;
use libpijul::{MutTxnT, MutTxnTExt, TxnT};
use log::debug;
use crate::repository::Repository;
#[derive(Clap, Debug)]
pub struct Unrecord {
/// Set the repository where this command should run Defaults to the first ancestor of the current directory that contains a `.pijul` directory.
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
/// Unrecord changes from this channel instead of the current channel
#[clap(long = "channel")]
channel: Option<String>,
/// Identifier of the change (unambiguous prefixes are accepted)
#[clap(multiple = true)]
change_id: Vec<String>,
}
impl Unrecord {
pub fn run(self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path)?;
debug!("{:?}", repo.config);
let channel_name = repo.config.get_current_channel(self.channel.as_ref());
let mut txn = repo.pristine.mut_txn_begin();
if let Some(mut channel) = txn.load_channel(channel_name) {
let mut changes = Vec::new();
let channel_ = channel.borrow();
for c in self.change_id {
let (hash, change_id) = txn.hash_from_prefix(&c)?;
let n = txn
.get_changeset(&channel_.changes, change_id, None)
.unwrap();
changes.push((hash, change_id, n, c))
}
std::mem::drop(channel_);
changes.sort_by(|a, b| b.2.cmp(&a.2));
for (hash, change_id, _, c) in changes {
let channel_ = channel.borrow();
for (p, d) in txn.iter_revdep(change_id) {
if p < change_id {
continue;
} else if p > change_id {
break;
}
if txn.get_changeset(&channel_.changes, d, None).is_some() {
return Err((crate::Error::CannotUnrecord {
change: c,
dep: txn.get_external(d).unwrap(),
})
.into());
}
}
std::mem::drop(channel_);
txn.unrecord(&repo.changes, &mut channel, &hash)?;
}
}
txn.commit()?;
Ok(())
}
}