Start of a huge refactoring

This commit is contained in:
Eric Coissac
2026-08-22 17:03:53 +02:00
parent 1261aeba86
commit 5048f43eea
1040 changed files with 1050 additions and 270 deletions
+1
View File
@@ -15,6 +15,7 @@ obisys = { path = "../obisys" }
obikindex = { path = "../obikindex", default-features = false }
obikindexer = { path = "../obikindexer" }
obikalgorithm = { path = "../obikalgorithm" }
obikmerge = { path = "../obikmerge" }
obifastwrite = { path = "../obifastwrite" }
obiskbuilder = { path = "../obiskbuilder" }
clap = { version = "4", features = ["derive"] }
+104
View File
@@ -0,0 +1,104 @@
use std::path::PathBuf;
use clap::Args;
use obikalgorithm::Algorithm;
use obikindex::KmerIndex;
use obikmerge::{Merge, MergeMode};
use obisys::{Progress, Reporter, Stage, progress_bar};
use tracing::info;
#[derive(Args)]
pub struct MergeArgs {
/// Source index directories to merge
#[arg(required = true)]
pub sources: Vec<PathBuf>,
/// Output index directory
#[arg(short, long)]
pub output: PathBuf,
/// Overwrite output directory if it already exists
#[arg(long, default_value_t = false)]
pub force: bool,
/// Force presence/absence mode even if all sources have count data
#[arg(long, default_value_t = false)]
pub force_presence: bool,
/// Disambiguate duplicate genome labels by appending .1, .2, … instead of erroring
#[arg(long, default_value_t = false)]
pub rename_duplicates: bool,
}
pub fn run(args: MergeArgs) {
let sources: Vec<KmerIndex> = args
.sources
.iter()
.map(|p| {
info!("opening source index: {}", p.display());
KmerIndex::open(p).unwrap_or_else(|e| {
eprintln!("error opening source index {}: {e}", p.display());
std::process::exit(1);
})
})
.collect();
// Auto-detect mode: count if all sources have count data, presence otherwise.
// --force-presence overrides to presence regardless.
let all_have_counts = sources.iter().all(|s| s.meta().config.with_counts);
let mode = if !args.force_presence && all_have_counts {
MergeMode::Count
} else {
MergeMode::Presence
};
info!(
"merge mode: {}",
if mode == MergeMode::Count {
"count"
} else {
"presence/absence"
}
);
let source_refs: Vec<&KmerIndex> = sources.iter().collect();
let n_genomes: usize = sources
.iter()
.map(|s| {
s.meta()
.genomes()
.unwrap_or_else(|e| {
eprintln!("error reading index metadata: {e}");
std::process::exit(1);
})
.len()
})
.sum();
info!(
"merging {} index(es), {} genome(s) total → {}",
sources.len(),
n_genomes,
args.output.display()
);
let mut rep = Reporter::new();
let t = Stage::start("merge");
let n_partitions = source_refs.first().map(|s| s.n_partitions()).unwrap_or(0);
let pb = progress_bar("merge", n_partitions as u64, "partitions");
let mut merge = Merge::new(&source_refs, &args.output, mode)
.force(args.force)
.rename_duplicates(args.rename_duplicates)
.on_progress(|_: Progress| pb.inc(1));
let dst = merge.run().unwrap_or_else(|e| {
eprintln!("error merging: {e}");
std::process::exit(1);
});
pb.finish_and_clear();
rep.push(t.stop());
info!("merge done — output at {}", dst.dir().display());
merge.reporter().print();
rep.print();
}
+1
View File
@@ -1,2 +1,3 @@
pub mod index;
pub mod merge;
pub mod superkmer;
+3
View File
@@ -17,6 +17,8 @@ enum Commands {
Index(cmd::index::IndexArgs),
/// Extract super-k-mers from input sequences and scatter them by partition
Superkmer(cmd::superkmer::SuperkmerArgs),
/// Merge multiple genome indexes into one
Merge(cmd::merge::MergeArgs),
}
fn main() {
@@ -31,5 +33,6 @@ fn main() {
match cli.command {
Commands::Index(args) => cmd::index::run(args),
Commands::Superkmer(args) => cmd::superkmer::run(args),
Commands::Merge(args) => cmd::merge::run(args),
}
}