use crate::git::git_interop::{create_new_write_ref, delete_reference, get_write_refs};
use crate::status::gather_pending_status;
use anyhow::{Context, Result};
use std::io::{self, Write};
#[derive(Debug)]
pub struct ResetPlan {
pub refs_to_delete: Vec<String>,
pub measurement_count: usize,
pub commit_count: usize,
}
pub fn reset_measurements(dry_run: bool, force: bool) -> Result<()> {
let new_write_ref = create_new_write_ref().context("Failed to create fresh write ref")?;
let plan = plan_reset(&new_write_ref)?;
if plan.refs_to_delete.is_empty() {
println!("No pending measurements to reset.");
return Ok(());
}
display_reset_plan(&plan)?;
if !dry_run && !force && !confirm_reset()? {
println!("Reset cancelled.");
return Ok(());
}
if dry_run {
println!();
println!("Dry run - no changes made.");
} else {
execute_reset(&plan)?;
println!();
let ref_word = if plan.refs_to_delete.len() == 1 {
"ref"
} else {
"refs"
};
println!(
"Reset complete. {} write {} deleted.",
plan.refs_to_delete.len(),
ref_word
);
}
Ok(())
}
fn plan_reset(new_write_ref: &str) -> Result<ResetPlan> {
let refs = get_write_refs()?;
let refs_to_delete: Vec<String> = refs
.into_iter()
.map(|(refname, _)| refname)
.filter(|refname| refname != new_write_ref)
.collect();
if refs_to_delete.is_empty() {
return Ok(ResetPlan {
refs_to_delete: vec![],
measurement_count: 0,
commit_count: 0,
});
}
let status = gather_pending_status(false)?;
Ok(ResetPlan {
refs_to_delete,
measurement_count: status.measurement_count,
commit_count: status.commit_count,
})
}
fn execute_reset(plan: &ResetPlan) -> Result<()> {
for ref_name in &plan.refs_to_delete {
delete_reference(ref_name)
.with_context(|| format!("Failed to delete reference: {}", ref_name))?;
}
Ok(())
}
fn display_reset_plan(plan: &ResetPlan) -> Result<()> {
let status = gather_pending_status(false)?;
println!("Will reset:");
let commit_word = if plan.commit_count == 1 {
"commit"
} else {
"commits"
};
println!(" {} {} with measurements", plan.commit_count, commit_word);
let measurement_word = if status.measurement_names.len() == 1 {
"measurement"
} else {
"measurements"
};
println!(
" {} unique {}",
status.measurement_names.len(),
measurement_word
);
println!();
if !status.measurement_names.is_empty() {
println!("Measurement names:");
let mut sorted_names: Vec<_> = status.measurement_names.iter().collect();
sorted_names.sort();
for name in sorted_names {
println!(" - {}", name);
}
println!();
}
Ok(())
}
fn confirm_reset() -> Result<bool> {
print!("Are you sure you want to discard these pending measurements? [y/N] ");
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
let response = input.trim().to_lowercase();
Ok(response == "y" || response == "yes")
}