use anyhow::{Result, bail};
use clap::Args;
use bob::db::Database;
use super::util::pkg_pattern;
use super::{Col, Formatter, OutputFormat};
#[derive(Debug, Args)]
pub struct HistoryArgs {
#[arg(short = 'H')]
no_header: bool,
#[arg(short = 'l', long)]
long: bool,
#[arg(short = 'r', long)]
raw: bool,
#[arg(short = 'f', long, value_enum, default_value_t = OutputFormat::Table)]
format: OutputFormat,
#[arg(short = 'o', value_delimiter = ',')]
columns: Option<Vec<String>>,
package: Option<String>,
}
pub fn run(db: &Database, args: HistoryArgs) -> Result<()> {
print_history(
db,
args.columns.as_deref(),
args.no_header,
args.long,
args.raw,
args.format,
args.package.as_deref(),
)
}
fn print_history(
db: &Database,
columns: Option<&[String]>,
no_header: bool,
long: bool,
raw: bool,
format: OutputFormat,
package: Option<&str>,
) -> Result<()> {
let all_cols = bob::HistoryKind::all_columns();
let default_cols = bob::HistoryKind::default_names();
let cols: Vec<&str> = if columns.is_some() {
columns
.map(|c| c.iter().map(|s| s.as_str()).collect())
.unwrap_or_default()
} else if long {
all_cols.iter().map(|(s, _)| s.as_str()).collect()
} else {
default_cols
};
for col in &cols {
if !all_cols.iter().any(|(c, _)| c == col) {
let names: Vec<&str> = all_cols.iter().map(|(n, _)| n.as_str()).collect();
bail!(
"Unknown column '{}'. Valid columns: {}",
col,
names.join(", ")
);
}
}
let pattern = package.map(pkg_pattern).transpose()?;
let records = db.query_history(pattern.as_ref())?;
if records.is_empty() {
if package.is_some() {
bail!("No history matches the pattern");
} else {
println!("No build history recorded");
}
return Ok(());
}
let fmt_cols: Vec<Col> = cols
.iter()
.map(|&name| {
let (_, align) = all_cols.iter().find(|(n, _)| n == name).expect("validated");
Col::new(name, *align)
})
.collect();
let mut fmt = Formatter::new(fmt_cols);
for rec in &records {
let row = cols
.iter()
.map(|&col| {
if raw {
rec.format_col_raw(col)
} else {
rec.format_col(col)
}
})
.collect();
fmt.push(row);
}
fmt.print(format, no_header);
Ok(())
}