diff --git a/Cargo.lock b/Cargo.lock index 6d9a627..b39bc1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "attohttpc" version = "0.25.0" @@ -111,6 +117,7 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" name = "bigtools" version = "0.5.2-dev" dependencies = [ + "anyhow", "attohttpc", "bincode", "byteorder", diff --git a/bigtools/Cargo.toml b/bigtools/Cargo.toml index e2c2f1e..2798f26 100644 --- a/bigtools/Cargo.toml +++ b/bigtools/Cargo.toml @@ -24,6 +24,7 @@ bincode = { version = "1.3", optional = true } attohttpc = { version = "0.25", optional = true, default_features = false, features = ["tls-rustls-native-roots"] } libdeflater = "0.13" thiserror = "1" +anyhow = { version = "1", optional = true } ryu = { version = "1.0", optional = true } ufmt = { version = "0.2", features = ["std"], optional = true } bytes = { version = "1.4.0", optional = true } @@ -80,6 +81,6 @@ required-features = ["cli"] [features] default = ["remote", "read", "write", "cli"] remote = ["attohttpc", "tempfile"] -cli = ["clap", "ryu", "ufmt", "read", "write"] +cli = ["anyhow", "clap", "ryu", "ufmt", "read", "write"] read = ["bytes", "itertools"] write = ["crossbeam-channel", "tempfile", "futures", "serde", "itertools", "bincode"] diff --git a/bigtools/src/bin/bigtools.rs b/bigtools/src/bin/bigtools.rs index d4ad24f..748c5ed 100644 --- a/bigtools/src/bin/bigtools.rs +++ b/bigtools/src/bin/bigtools.rs @@ -258,7 +258,10 @@ fn main() -> Result<(), Box> { args: ChromIntersectArgs { a, b, out }, } => chromintersect(a, b, out), SubCommands::BedGraphToBigWig { args } => bedgraphtobigwig(args), - SubCommands::BedToBigBed { args } => bedtobigbed(args), + SubCommands::BedToBigBed { args } => { + bedtobigbed(args)?; + Ok(()) + } SubCommands::BigBedInfo { args } => bigbedinfo(args), SubCommands::BigBedToBed { args } => bigbedtobed(args), SubCommands::BigWigAverageOverBed { args } => { diff --git a/bigtools/src/utils/cli/bedtobigbed.rs b/bigtools/src/utils/cli/bedtobigbed.rs index e0a0b3c..35272d9 100644 --- a/bigtools/src/utils/cli/bedtobigbed.rs +++ b/bigtools/src/utils/cli/bedtobigbed.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use std::error::Error; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::PathBuf; +use anyhow::Context; use clap::Parser; use tokio::runtime; @@ -51,7 +51,7 @@ pub struct BedToBigBedArgs { pub write_args: BBIWriteArgs, } -pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { +pub fn bedtobigbed(args: BedToBigBedArgs) -> anyhow::Result<()> { let bedpath = args.bed; let chrom_map = args.chromsizes; let bigwigpath = args.output; @@ -72,7 +72,9 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { } }; - let chrom_map: HashMap = BufReader::new(File::open(chrom_map)?) + let chrom_map = File::open(&chrom_map) + .with_context(|| format!("Failed to open chrom sizes file `{}`", &chrom_map))?; + let chrom_map: HashMap = BufReader::new(chrom_map) .lines() .filter(|l| match l { Ok(s) => !s.is_empty(), @@ -88,7 +90,8 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { }) .collect(); - let mut outb = BigBedWrite::create_file(bigwigpath, chrom_map)?; + let mut outb = BigBedWrite::create_file(bigwigpath, chrom_map) + .with_context(|| format!("Failed to create bigBed file."))?; outb.options.max_zooms = args.write_args.nzooms; outb.options.compress = !args.write_args.uncompressed; outb.options.input_sort_type = input_sort_type; @@ -103,23 +106,26 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { .unwrap() }; - let autosql = match args.autosql.as_ref() { - None => { - let infile = File::open(&bedpath)?; - let mut vals_iter = BedFileStream::from_bed_file(infile); - crate::bed::autosql::bed_autosql(&vals_iter.next().unwrap().unwrap().1.rest) - } - Some(file) => std::fs::read_to_string(file)?, - }; - outb.autosql = Some(autosql); - let allow_out_of_order_chroms = !matches!(outb.options.input_sort_type, InputSortType::ALL); if bedpath == "-" || bedpath == "stdin" { let stdin = std::io::stdin().lock(); let data = BedParserStreamingIterator::from_bed_file(stdin, allow_out_of_order_chroms); - outb.write(data, runtime)?; + outb.write(data, runtime) + .with_context(|| format!("Failed to write bigBed."))?; } else { - let infile = File::open(&bedpath)?; + let autosql = match args.autosql.as_ref() { + None => { + let infile = File::open(&bedpath) + .with_context(|| format!("Failed to open bed file `{}`", &bedpath))?; + let mut vals_iter = BedFileStream::from_bed_file(infile); + crate::bed::autosql::bed_autosql(&vals_iter.next().unwrap().unwrap().1.rest) + } + Some(file) => std::fs::read_to_string(file)?, + }; + outb.autosql = Some(autosql); + + let infile = File::open(&bedpath) + .with_context(|| format!("Failed to open bed file `{}`.", &bedpath))?; let (parallel, parallel_required) = match (nthreads, args.parallel.as_ref()) { (1, _) | (_, "no") => (false, false), (_, "auto") => (infile.metadata()?.len() >= 200_000_000, false), @@ -135,7 +141,8 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { let chrom_indices = match parallel { false => None, true => { - let index = index_chroms(infile)?; + let index = index_chroms(infile) + .with_context(|| format!("Failed to index chromosomes."))?; match (index, parallel_required) { (Some(index), _) => Some(index), (None, true) => { @@ -156,7 +163,8 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { PathBuf::from(bedpath), parse_bed, ); - outb.write(data, runtime)?; + outb.write(data, runtime) + .with_context(|| format!("Failed to write bigBed."))?; } else { outb.write_multipass( || { @@ -170,14 +178,17 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { Ok(data) }, runtime, - )?; + ) + .with_context(|| format!("Failed to write bigBed."))?; } } else { - let infile = File::open(&bedpath)?; if args.single_pass { + let infile = File::open(&bedpath) + .with_context(|| format!("Failed to open bed file `{}`.", &bedpath))?; let data = BedParserStreamingIterator::from_bed_file(infile, allow_out_of_order_chroms); - outb.write(data, runtime)?; + outb.write(data, runtime) + .with_context(|| format!("Failed to write bigBed."))?; } else { outb.write_multipass( || { @@ -190,7 +201,8 @@ pub fn bedtobigbed(args: BedToBigBedArgs) -> Result<(), Box> { Ok(data) }, runtime, - )?; + ) + .with_context(|| format!("Failed to write bigBed."))?; } } };