use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use anyhow::bail;
use clap::Clap;
use libpijul::changestore::ChangeStore;
use libpijul::{DepsTxnT, GraphTxnT, MutTxnT, MutTxnTExt, TxnT};
use crate::repository::Repository;
#[derive(Clap, Debug)]
pub struct Apply {
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
#[clap(long = "channel")]
channel: Option<String>,
#[clap(long = "deps-only")]
deps_only: bool,
change: Vec<String>,
}
impl Apply {
pub fn run(self) -> Result<(), anyhow::Error> {
let mut repo = Repository::find_root(self.repo_path)?;
let mut txn = repo.pristine.mut_txn_begin();
let channel_name = repo.config.get_current_channel(self.channel.as_ref());
let mut channel = if let Some(channel) = txn.load_channel(&channel_name)? {
channel
} else {
txn.open_or_create_channel(&channel_name)?
};
let mut hashes = Vec::new();
for ch in self.change.iter() {
hashes.push(if let Ok(h) = txn.hash_from_prefix(ch) {
h.0
} else {
let change = libpijul::change::Change::deserialize(&ch, None)?;
repo.changes.save_change(&change)?
})
}
if hashes.is_empty() {
let mut change = std::io::BufReader::new(std::io::stdin());
let change = libpijul::change::Change::read(&mut change, &mut HashMap::new())?;
hashes.push(repo.changes.save_change(&change)?)
}
if self.deps_only {
if hashes.len() > 1 {
bail!("--deps-only is only applicable to a single change")
}
txn.apply_deps_rec(&repo.changes, &mut channel, hashes.pop().unwrap())?;
} else {
for hash in hashes.drain(..) {
txn.apply_change_rec(&repo.changes, &mut channel, hash)?;
}
}
let mut touched = HashSet::new();
for d in hashes.iter() {
if let Some(int) = txn.get_internal(*d)? {
for inode in txn.iter_rev_touched(int)? {
let (int_, inode) = inode?;
if int_ < int {
continue;
} else if int_ > int {
break;
}
touched.insert(inode);
}
}
}
let mut done = HashMap::new();
for i in touched {
let (path, _) =
libpijul::fs::find_path(&repo.changes, &txn, &channel.borrow(), false, i)?;
txn.output_repository_no_pending(
&mut repo.working_copy,
&repo.changes,
&mut channel,
&mut done,
&path,
true,
None,
)?;
}
txn.commit()?;
Ok(())
}
}