feat: add obisys crate for standardized CLI progress reporting

This commit introduces the `obisys` crate, which wraps `indicatif` to provide reusable `spinner` and `progress_bar` utilities with consistent styling and tick intervals. It refactors progress reporting across `obikindex`, `obikpartitionner`, and `obikmer` to use these shared functions, eliminating inline UI configuration and ensuring uniform terminal feedback.
This commit is contained in:
Eric Coissac
2026-06-03 15:33:15 +02:00
parent 4677d6f177
commit 02cb30c0ef
10 changed files with 59 additions and 89 deletions
+2 -7
View File
@@ -4,10 +4,9 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use indicatif::{ProgressBar, ProgressStyle};
use obikpartitionner::{KmerPartition, KmerSpectrum};
use obilayeredmap;
use obisys::{Reporter, Stage};
use obisys::{Reporter, Stage, progress_bar};
use rayon::prelude::*;
use tracing::info;
@@ -155,11 +154,7 @@ impl KmerIndex {
let block_bits = self.meta.config.block_bits;
let total_kmers = AtomicUsize::new(0);
let pb = Arc::new(Mutex::new(
ProgressBar::new(n as u64).with_style(
ProgressStyle::with_template("index — [{bar:20}] {pos}/{len} | {msg}").unwrap(),
),
));
let pb = Arc::new(Mutex::new(progress_bar("index", n as u64, "partitions")));
(0..n).into_par_iter().for_each(|i| {
match self.partition.build_index_layer(i, min_ab, max_ab, with_counts, &evidence, block_bits) {
+8 -32
View File
@@ -2,10 +2,7 @@ use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::Path;
use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle};
use obisys::{Reporter, Stage};
use obisys::{Reporter, Stage, progress_bar, spinner};
use rayon::prelude::*;
use tracing::info;
@@ -124,7 +121,8 @@ impl KmerIndex {
sources[0].meta.genomes.len(),
);
let t = Stage::start("bootstrap");
let pb = spinner("bootstrap — copying index …");
let pb = spinner("bootstrap");
pb.set_message("copying index …");
copy_dir_all(&sources[0].root_path, output)?;
// Rewrite index.meta with final genome labels and the effective mode.
@@ -146,7 +144,8 @@ impl KmerIndex {
// Drop the spectrums/ that were copied from source_0 and rebuild from scratch.
info!("rebuilding spectrums for {} source(s)", sources.len());
let t = Stage::start("spectrums");
let pb = spinner("spectrums — copying …");
let pb = spinner("spectrums");
pb.set_message("copying …");
let spectrums_dir = output.join("spectrums");
if spectrums_dir.exists() {
fs::remove_dir_all(&spectrums_dir)?;
@@ -172,7 +171,7 @@ impl KmerIndex {
n_partitions, n_src_genomes, n_dst_genomes,
);
let t = Stage::start("merge_partitions");
let pb = partition_bar(n_partitions as u64);
let pb = progress_bar("merge", n_partitions as u64, "partitions");
let dst_partition = &dst.partition;
let block_bits = dst.meta.config.block_bits;
@@ -199,7 +198,8 @@ impl KmerIndex {
// ── Pack matrices after merge ─────────────────────────────────────────
{
let t = Stage::start("pack");
let pb = spinner("pack — consolidating column files …");
let pb = spinner("pack");
pb.set_message("consolidating column files …");
let dst2 = KmerIndex::open(output)?;
dst2.pack_matrices()?;
pb.finish_and_clear();
@@ -285,30 +285,6 @@ fn remove_dirs_named(root: &Path, name: &str) -> io::Result<()> {
Ok(())
}
fn spinner(msg: &'static str) -> ProgressBar {
let pb = ProgressBar::new_spinner();
pb.set_style(
ProgressStyle::with_template("{spinner} {msg} {elapsed}")
.unwrap()
.tick_strings(&["", "", "", "", "", "", "", "", "", ""]),
);
pb.set_message(msg);
pb.enable_steady_tick(Duration::from_millis(100));
pb
}
fn partition_bar(n: u64) -> ProgressBar {
let pb = ProgressBar::new(n);
pb.set_style(
ProgressStyle::with_template(
"{spinner} merge — {bar:40.cyan/blue} {pos}/{len} partitions {elapsed}",
)
.unwrap()
.tick_strings(&["", "", "", "", "", "", "", "", "", ""]),
);
pb.enable_steady_tick(Duration::from_millis(100));
pb
}
fn format_evidence(ev: &IndexMode) -> String {
match ev {
+2 -9
View File
@@ -1,11 +1,9 @@
use std::fs;
use std::io;
use std::path::Path;
use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle};
use obikpartitionner::{KmerFilter, KmerPartition, MergeMode};
use obisys::{Reporter, Stage};
use obisys::{Reporter, Stage, progress_bar};
use rayon::prelude::*;
use tracing::info;
@@ -80,12 +78,7 @@ impl KmerIndex {
);
let t = Stage::start("rebuild");
let pb = ProgressBar::new(n_partitions as u64).with_style(
ProgressStyle::with_template("rebuild — [{bar:20}] {pos}/{len} | {msg}")
.unwrap()
.progress_chars("=> "),
);
pb.enable_steady_tick(Duration::from_millis(100));
let pb = progress_bar("rebuild", n_partitions as u64, "partitions");
let src_partition = &src.partition;
let block_bits = meta.config.block_bits;
+2 -12
View File
@@ -1,11 +1,8 @@
use std::fs;
use std::path::Path;
use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle};
use obilayeredmap::{IndexMode, layer::Layer};
use obilayeredmap::meta::PartitionMeta;
use obisys::{Reporter, Stage};
use obisys::{Reporter, Stage, progress_bar};
use rayon::prelude::*;
use tracing::info;
@@ -46,14 +43,7 @@ impl KmerIndex {
);
let t = Stage::start("reindex");
let pb = ProgressBar::new(n as u64).with_style(
ProgressStyle::with_template(
"reindex — [{bar:20}] {pos}/{len} | {msg}",
)
.unwrap()
.tick_strings(&["","","","","","","","","",""]),
);
pb.enable_steady_tick(Duration::from_millis(80));
let pb = progress_bar("reindex", n as u64, "partitions");
let errors: Vec<String> = (0..n)
.into_par_iter()