use std::path::PathBuf;
use std::io::Write;
use clap::Parser;
use libpijul::*;
use crate::repository::*;
#[derive(Parser, Debug)]
pub struct Dependents {
/// Use the repository at PATH instead of the current directory
#[clap(long = "repository", value_name = "PATH")]
repo_path: Option<PathBuf>,
/// The hash of the change to show, or an unambiguous prefix thereof
#[clap(value_name = "HASH")]
hash: Option<String>,
}
impl Dependents {
pub fn run(self) -> Result<(), anyhow::Error> {
let repo = Repository::find_root(self.repo_path.clone())?;
let txn = repo.pristine.txn_begin()?;
let channel_name = txn.current_channel().unwrap_or(crate::DEFAULT_CHANNEL);
let channel = if let Some(channel) = txn.load_channel(&channel_name)? {
channel
} else {
return Ok(());
};
let channelr = channel.read();
let hash = if let Some(hash) = self.hash {
let h = if let Some(h) = Hash::from_base32(hash.as_bytes()) {
h
} else {
txn.hash_from_prefix(&hash)?.0
};
if txn.has_change(&channel, &h.into())?.is_none() {
return Ok(())
}
h
} else {
if let Some(h) = txn.reverse_log(&*channelr, None)?.next() {
(h?.1).0.into()
} else {
return Ok(());
}
};
if let Hash::None = hash {
eprintln!("Warning: listing dependents of the root change")
}
let mut ids = vec![(txn.get_internal(&hash.into())?.unwrap(), 0u64, false)];
let mut seen = HashSet::new();
let mut stdout = std::io::stdout();
while let Some((id, n, v)) = ids.pop() {
if v {
let h: Hash = txn.get_external(&id)?.unwrap().into();
writeln!(stdout, "{}", h.to_base32())?;
} else if seen.insert(id) {
ids.push((id, n, true));
let l = ids.len();
for t in txn.iter_revdep(&id).unwrap() {
let (id_, t) = t?;
if id_ > id {
break
}
if let Some(n) = txn.get_changeset(txn.changes(&channelr), t)? {
ids.push((t, (*n).into(), false));
}
}
(&mut ids[l..]).sort_by(|a, b| a.1.cmp(&b.1));
}
}
Ok(())
}
}