diff --git a/README.md b/README.md index ae475b4..1e885ce 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Commands: Global Arguments: --compress-level set gzip/bzip2/xz compression level 1 (compress faster) - 9 (compress better) for gzip/bzip2/xz output file, just work with option -o/--out [default: 6] + --output-type output type for stdout: 'g' gzip; 'b' bzip2; 'x' xz; 'u' uncompressed txt format [default: u --log if file name specified, write log message to this file, or write to stderr -v, --verbosity... control verbosity of logging, [-v: Error, -vv: Warn, -vvv: Info, -vvvv: Debug, -vvvvv: Trace, defalut: Debug] diff --git a/src/cli/check.rs b/src/cli/check.rs index 9103cf5..29489e4 100644 --- a/src/cli/check.rs +++ b/src/cli/check.rs @@ -9,6 +9,7 @@ pub fn check_fastq( save: bool, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -21,7 +22,8 @@ pub fn check_fastq( } if save { - let mut out_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut out_writer = + file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fp_reader.records().map_while(Result::ok) { total += 1; match rec.check() { diff --git a/src/cli/concat.rs b/src/cli/concat.rs index eebf792..aaac82e 100644 --- a/src/cli/concat.rs +++ b/src/cli/concat.rs @@ -10,6 +10,7 @@ pub fn concat_fqstq_lane( out_r1: &String, out_r2: &String, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -37,8 +38,10 @@ pub fn concat_fqstq_lane( info!("outout read1 in file: {}", out_r1); info!("outout read1 in file: {}", out_r2); - let mut out_writer1 = file_writer(Some(out_r1), compression_level).map(fastq::Writer::new)?; - let mut out_writer2 = file_writer(Some(out_r2), compression_level).map(fastq::Writer::new)?; + let mut out_writer1 = + file_writer(Some(out_r1), compression_level, stdout_type).map(fastq::Writer::new)?; + let mut out_writer2 = + file_writer(Some(out_r2), compression_level, stdout_type).map(fastq::Writer::new)?; let mut pe_read = 0; for pe in vec1.iter().zip(vec2.iter()) { info!("concat pe reads from file {} and {}", pe.0, pe.1); diff --git a/src/cli/cutadapter.rs b/src/cli/cutadapter.rs index a75747d..738249a 100644 --- a/src/cli/cutadapter.rs +++ b/src/cli/cutadapter.rs @@ -13,6 +13,7 @@ pub fn cut_adapter( miss: usize, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -43,7 +44,7 @@ pub fn cut_adapter( } let fq_reader = file_reader(input).map(fastq::Reader::new)?; - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; let mut flag = false; for rec in fq_reader.records().map_while(Result::ok) { let read_len = rec.seq().len(); diff --git a/src/cli/filter.rs b/src/cli/filter.rs index d1ec29a..40289e0 100644 --- a/src/cli/filter.rs +++ b/src/cli/filter.rs @@ -20,6 +20,7 @@ pub fn filter_fastq( out1: &String, out2: &String, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); info!("read forward reads from file: {}", read1); @@ -38,9 +39,12 @@ pub fn filter_fastq( let fq_reader1 = file_reader(Some(read1)).map(fastq::Reader::new)?; let fq_reader2 = file_reader(Some(read2)).map(fastq::Reader::new)?; - let mut out_writer1 = file_writer(Some(out1), compression_level).map(fastq::Writer::new)?; - let mut out_writer2 = file_writer(Some(out2), compression_level).map(fastq::Writer::new)?; - let mut failed_writer = file_writer(Some(failed), compression_level).map(fastq::Writer::new)?; + let mut out_writer1 = + file_writer(Some(out1), compression_level, stdout_type).map(fastq::Writer::new)?; + let mut out_writer2 = + file_writer(Some(out2), compression_level, stdout_type).map(fastq::Writer::new)?; + let mut failed_writer = + file_writer(Some(failed), compression_level, stdout_type).map(fastq::Writer::new)?; let complex = complexity as usize; let (mut pe_ok, mut pe_fail) = (0usize, 0usize); diff --git a/src/cli/flatten.rs b/src/cli/flatten.rs index 223b424..036c170 100644 --- a/src/cli/flatten.rs +++ b/src/cli/flatten.rs @@ -14,6 +14,7 @@ pub fn flatten_fq( len: bool, gc: bool, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -31,7 +32,7 @@ pub fn flatten_fq( } let fields = get_flag(flag); - let mut out_writer = file_writer(out, compression_level)?; + let mut out_writer = file_writer(out, compression_level, stdout_type)?; for rec in fq_reader.records().map_while(Result::ok) { let read = [rec.id().as_bytes(), rec.seq(), "+".as_bytes(), rec.qual()]; diff --git a/src/cli/fq2fa.rs b/src/cli/fq2fa.rs index e2606a6..5febb9c 100644 --- a/src/cli/fq2fa.rs +++ b/src/cli/fq2fa.rs @@ -10,6 +10,7 @@ pub fn fq2fa( remove: bool, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -21,7 +22,7 @@ pub fn fq2fa( info!("reading from stdin"); } - let mut fo = fasta::Writer::new(file_writer(out, compression_level)?); + let mut fo = fasta::Writer::new(file_writer(out, compression_level, stdout_type)?); if remove { for rec in fq_reader.records().map_while(Result::ok) { num += 1; diff --git a/src/cli/fq2sam.rs b/src/cli/fq2sam.rs index a0c095e..5a27612 100644 --- a/src/cli/fq2sam.rs +++ b/src/cli/fq2sam.rs @@ -14,6 +14,7 @@ pub fn fastq2sam( pl: Option, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); if let Some(r2) = r2 { @@ -24,7 +25,7 @@ pub fn fastq2sam( } info!("sample name set: {}", sm); - let mut sam = file_writer(out, compression_level)?; + let mut sam = file_writer(out, compression_level, stdout_type)?; let rg = if let Some(x) = rg { x } else { diff --git a/src/cli/fqscore.rs b/src/cli/fqscore.rs index 33f2b92..06b097f 100644 --- a/src/cli/fqscore.rs +++ b/src/cli/fqscore.rs @@ -10,6 +10,7 @@ pub fn phred_score( to33: bool, to64: bool, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -36,7 +37,7 @@ pub fn phred_score( std::process::exit(1); } - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fq_reader.records().map_while(Result::ok) { let mut qual = vec![]; if to33 { diff --git a/src/cli/gcplot.rs b/src/cli/gcplot.rs index 651867e..7f6b301 100644 --- a/src/cli/gcplot.rs +++ b/src/cli/gcplot.rs @@ -19,6 +19,7 @@ pub fn gc_content( ylim: usize, types: &str, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -29,7 +30,7 @@ pub fn gc_content( info!("reading from stdin"); } - let mut fo = file_writer(output, compression_level)?; + let mut fo = file_writer(output, compression_level, stdout_type)?; let mut df_hash = HashMap::new(); for rec in fq_reader.records().map_while(Result::ok) { diff --git a/src/cli/grep.rs b/src/cli/grep.rs index eeb2867..be1c5cf 100644 --- a/src/cli/grep.rs +++ b/src/cli/grep.rs @@ -12,6 +12,7 @@ pub fn grep_fastq( full_name: bool, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -39,7 +40,7 @@ pub fn grep_fastq( } else { info!("reads write to stdout"); } - let mut fo = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fo = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fq_reader.records().map_while(Result::ok) { let name = if full_name { if let Some(desc) = rec.desc() { diff --git a/src/cli/kmer.rs b/src/cli/kmer.rs index 0cb7b96..afb797f 100644 --- a/src/cli/kmer.rs +++ b/src/cli/kmer.rs @@ -11,6 +11,7 @@ pub fn kmer_count( header: bool, output: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); let reader = file_reader(input).map(fastq::Reader::new)?; @@ -20,7 +21,7 @@ pub fn kmer_count( info!("reading from stdin"); } - let mut writer = file_writer(output, compression_level)?; + let mut writer = file_writer(output, compression_level, stdout_type)?; let mut kmers = HashMap::new(); for rec in reader.records().map_while(Result::ok) { diff --git a/src/cli/length.rs b/src/cli/length.rs index 0f73b4b..923e264 100644 --- a/src/cli/length.rs +++ b/src/cli/length.rs @@ -10,6 +10,7 @@ pub fn fq_length( rev: bool, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -22,7 +23,7 @@ pub fn fq_length( info!("reading from stdin"); } - let mut fo = file_writer(out, compression_level)?; + let mut fo = file_writer(out, compression_level, stdout_type)?; for rec in fp_reader.records().map_while(Result::ok) { let rlen = rec.seq().len(); *reads_len.entry(rlen).or_insert(0usize) += 1; diff --git a/src/cli/mask.rs b/src/cli/mask.rs index 692e899..d9c6bed 100644 --- a/src/cli/mask.rs +++ b/src/cli/mask.rs @@ -11,6 +11,7 @@ pub fn mask_fastq( nt: char, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -24,7 +25,7 @@ pub fn mask_fastq( info!("low quality value: {}", qual_limit); info!("mask low quality bases with: {}", nt); - let mut fp_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fp_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fp_reader.records().map_while(Result::ok) { let score_min = rec.qual().iter().min().unwrap() - phred; if score_min > qual_limit { diff --git a/src/cli/merge.rs b/src/cli/merge.rs index 5672d67..576b1fa 100644 --- a/src/cli/merge.rs +++ b/src/cli/merge.rs @@ -9,6 +9,7 @@ pub fn interleaved( file2: &String, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -18,7 +19,7 @@ pub fn interleaved( info!("reading from file: {}", file1); info!("reading from file: {}", file2); - let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level)?); + let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level, stdout_type)?); for (rec1, rec2) in fq1_reader .records() .map_while(Result::ok) diff --git a/src/cli/range.rs b/src/cli/range.rs index 2724826..a13c4c7 100644 --- a/src/cli/range.rs +++ b/src/cli/range.rs @@ -10,6 +10,7 @@ pub fn range_fastq( take: usize, output: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -22,7 +23,8 @@ pub fn range_fastq( info!("skip first {} records", skip); info!("get {} records", take); - let mut fp_writer = file_writer(output, compression_level).map(fastq::Writer::new)?; + let mut fp_writer = + file_writer(output, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fp_reader .records() .skip(skip) diff --git a/src/cli/remove.rs b/src/cli/remove.rs index c68630f..eb1b11f 100644 --- a/src/cli/remove.rs +++ b/src/cli/remove.rs @@ -12,6 +12,7 @@ pub fn remove_read( save: &String, rm: bool, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -37,7 +38,7 @@ pub fn remove_read( info!("removed reads in file: {}", save); } - let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level)?); + let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level, stdout_type)?); if rm { for rec in fq_reader.records().map_while(Result::ok) { if !ids.contains(&rec.id().to_string()) { @@ -46,7 +47,8 @@ pub fn remove_read( } fq_writer.flush()?; } else { - let mut rm_writer = fastq::Writer::new(file_writer(Some(save), compression_level)?); + let mut rm_writer = + fastq::Writer::new(file_writer(Some(save), compression_level, stdout_type)?); for rec in fq_reader.records().map_while(Result::ok) { if !ids.contains(&rec.id().to_string()) { fq_writer.write(rec.id(), rec.desc(), rec.seq(), rec.qual())?; diff --git a/src/cli/rename.rs b/src/cli/rename.rs index 9c2a310..f13c611 100644 --- a/src/cli/rename.rs +++ b/src/cli/rename.rs @@ -4,6 +4,7 @@ use bio::io::fastq::{self, Record}; use log::*; use std::time::Instant; +#[allow(clippy::too_many_arguments)] pub fn rename_fastq( input: Option<&String>, keep: bool, @@ -12,6 +13,7 @@ pub fn rename_fastq( before: bool, output: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -22,7 +24,7 @@ pub fn rename_fastq( info!("reading from stdin"); } - let mut fo = fastq::Writer::new(file_writer(output, compression_level)?); + let mut fo = fastq::Writer::new(file_writer(output, compression_level, stdout_type)?); let mut n: usize = 0; if let Some(pre) = prefix { diff --git a/src/cli/reverse.rs b/src/cli/reverse.rs index f81d4ca..ae15b79 100644 --- a/src/cli/reverse.rs +++ b/src/cli/reverse.rs @@ -10,6 +10,7 @@ pub fn reverse_comp_seq( out: Option<&String>, rev: bool, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -27,7 +28,8 @@ pub fn reverse_comp_seq( (b'C', b'G'), (b'N', b'N'), ]); - let mut out_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut out_writer = + file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in fq_reader.records().map_while(Result::ok) { let rev_seq = rec.seq().iter().copied().rev().collect::>(); diff --git a/src/cli/search.rs b/src/cli/search.rs index 2e915d2..353f938 100644 --- a/src/cli/search.rs +++ b/src/cli/search.rs @@ -16,6 +16,7 @@ pub fn search_fq( out: Option<&String>, ncpu: usize, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -42,7 +43,7 @@ pub fn search_fq( ); } let mut num = 0usize; - let mut fo = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fo = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; if let Some(out) = out { info!("reads write to file: {}", out); } else { diff --git a/src/cli/select.rs b/src/cli/select.rs index accd7cf..789d218 100644 --- a/src/cli/select.rs +++ b/src/cli/select.rs @@ -10,6 +10,7 @@ pub fn select_pe_fastq( out_r1: &String, out_r2: &String, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -30,8 +31,10 @@ pub fn select_pe_fastq( } info!("output selected read1 file: {}", out_r1); info!("output selected read2 file: {}", out_r2); - let mut out_writer1 = file_writer(Some(out_r1), compression_level).map(fastq::Writer::new)?; - let mut out_writer2 = file_writer(Some(out_r2), compression_level).map(fastq::Writer::new)?; + let mut out_writer1 = + file_writer(Some(out_r1), compression_level, stdout_type).map(fastq::Writer::new)?; + let mut out_writer2 = + file_writer(Some(out_r2), compression_level, stdout_type).map(fastq::Writer::new)?; let (mut pe_r1, mut pe_r2) = (0usize, 0usize); let fq_reader1 = file_reader(Some(fq1)).map(fastq::Reader::new)?; diff --git a/src/cli/shuffle.rs b/src/cli/shuffle.rs index afc7ce7..6435226 100644 --- a/src/cli/shuffle.rs +++ b/src/cli/shuffle.rs @@ -11,6 +11,7 @@ pub fn shuffle_fastq( seed: u64, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -32,7 +33,7 @@ pub fn shuffle_fastq( vec_reads.shuffle(&mut rng); info!("shuffle done, start write to output ..."); - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in vec_reads { fq_writer.write_record(&rec)?; } diff --git a/src/cli/size.rs b/src/cli/size.rs index 685a5bc..23551bd 100644 --- a/src/cli/size.rs +++ b/src/cli/size.rs @@ -34,6 +34,7 @@ pub fn size_fastq( chunk: usize, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -59,7 +60,7 @@ pub fn size_fastq( } else { info!("output result write to stdout"); } - let mut fo = file_writer(out, compression_level)?; + let mut fo = file_writer(out, compression_level, stdout_type)?; let mut base = Base::new(); let mut bases = 0usize; diff --git a/src/cli/slide.rs b/src/cli/slide.rs index 9c45e92..1feb20b 100644 --- a/src/cli/slide.rs +++ b/src/cli/slide.rs @@ -11,6 +11,7 @@ pub fn slide_fastq( out: Option<&String>, suffix: &str, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -22,7 +23,7 @@ pub fn slide_fastq( } info!("window size : {}", wind); info!("step size: {}", step); - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; let mut window = wind; for rec in fq_reader.records().map_while(Result::ok) { let seq = rec.seq(); diff --git a/src/cli/sort.rs b/src/cli/sort.rs index ab50443..77ca4ac 100644 --- a/src/cli/sort.rs +++ b/src/cli/sort.rs @@ -14,6 +14,7 @@ pub fn sort_fastq( reverse: bool, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -140,7 +141,7 @@ pub fn sort_fastq( } info!("sort done, start to output ..."); - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; for rec in vec_reads { fq_writer.write_record(&rec)?; } diff --git a/src/cli/split2.rs b/src/cli/split2.rs index 0e12d1b..f30e102 100644 --- a/src/cli/split2.rs +++ b/src/cli/split2.rs @@ -14,6 +14,7 @@ pub fn split_chunk( out_pre: &str, out_dir: &str, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -56,6 +57,7 @@ pub fn split_chunk( let mut fh = vec![fastq::Writer::new(file_writer( Some(&out), compression_level, + stdout_type, )?)]; info!("start to write file: {:?}", out); @@ -78,6 +80,7 @@ pub fn split_chunk( fh.push(fastq::Writer::new(file_writer( Some(&out), compression_level, + stdout_type, )?)); let fhthis = fh.get_mut(index).unwrap(); diff --git a/src/cli/stats.rs b/src/cli/stats.rs index 98b08bd..cc4ce16 100644 --- a/src/cli/stats.rs +++ b/src/cli/stats.rs @@ -91,6 +91,7 @@ pub fn stat_fq( pre_cyc: Option<&String>, phred: u8, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); if ![33u8, 64u8].contains(&phred) { @@ -111,8 +112,8 @@ pub fn stat_fq( info!("cycle result write to stdout"); } - let mut fo = file_writer(Some(pre_sum), compression_level)?; - let mut fc = file_writer(pre_cyc, compression_level)?; + let mut fo = file_writer(Some(pre_sum), compression_level, stdout_type)?; + let mut fc = file_writer(pre_cyc, compression_level, stdout_type)?; let mut stat = info::new(); let mut max_qva = 0; diff --git a/src/cli/subfq.rs b/src/cli/subfq.rs index 1808ee0..5b62386 100644 --- a/src/cli/subfq.rs +++ b/src/cli/subfq.rs @@ -13,6 +13,7 @@ fn select_fastq( seed: u64, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { let start = Instant::now(); @@ -40,7 +41,7 @@ fn select_fastq( } } - let fo = file_writer(out, compression_level)?; + let fo = file_writer(out, compression_level, stdout_type)?; let mut w = fastq::Writer::new(fo); let fq_reader2 = fastq::Reader::new(file_reader(file)?); for (order, rec) in fq_reader2.records().map_while(Result::ok).enumerate() { @@ -61,6 +62,7 @@ fn select_fastq2( seed: u64, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { if let Some(file) = file { info!("reading from file: {}", file); @@ -87,7 +89,7 @@ fn select_fastq2( } } - let fo = file_writer(out, compression_level)?; + let fo = file_writer(out, compression_level, stdout_type)?; let mut w = fastq::Writer::new(fo); for rec in get { w.write(rec.id(), rec.desc(), rec.seq(), rec.qual())?; @@ -105,15 +107,16 @@ pub fn subset_fastq( seed: u64, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<(), Error> { if rdc { if file.is_none() { error!("opt -r used, fastq data can't from stdin."); std::process::exit(1); } - select_fastq(file, n, seed, out, compression_level)?; + select_fastq(file, n, seed, out, compression_level, stdout_type)?; } else { - select_fastq2(file, n, seed, out, compression_level)?; + select_fastq2(file, n, seed, out, compression_level, stdout_type)?; } Ok(()) diff --git a/src/cli/tail.rs b/src/cli/tail.rs index f0768de..e9c06cf 100644 --- a/src/cli/tail.rs +++ b/src/cli/tail.rs @@ -10,6 +10,7 @@ pub fn tail_n_records( rdc: bool, output: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -21,7 +22,7 @@ pub fn tail_n_records( } info!("get tail {} records", number); - let mut fo = fastq::Writer::new(file_writer(output, compression_level)?); + let mut fo = fastq::Writer::new(file_writer(output, compression_level, stdout_type)?); if rdc { let mut total = 0usize; for _ in fp.records() { diff --git a/src/cli/top.rs b/src/cli/top.rs index 6820775..90773df 100644 --- a/src/cli/top.rs +++ b/src/cli/top.rs @@ -9,6 +9,7 @@ pub fn top_n_records( number: usize, output: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -20,7 +21,7 @@ pub fn top_n_records( } info!("get top {} records", number); - let mut fo = fastq::Writer::new(file_writer(output, compression_level)?); + let mut fo = fastq::Writer::new(file_writer(output, compression_level, stdout_type)?); for rec in fp.records().take(number).map_while(Result::ok) { fo.write_record(&rec)?; } diff --git a/src/cli/trimfq.rs b/src/cli/trimfq.rs index 2e80fd1..31860e4 100644 --- a/src/cli/trimfq.rs +++ b/src/cli/trimfq.rs @@ -11,6 +11,7 @@ pub fn trim_fq( len: usize, out: Option<&String>, compression_level: u32, + stdout_type: char, ) -> Result<()> { let start = Instant::now(); @@ -22,7 +23,7 @@ pub fn trim_fq( info!("reading from stdin"); } - let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level)?); + let mut fq_writer = fastq::Writer::new(file_writer(out, compression_level, stdout_type)?); for (idx, rec) in fq_reader.records().map_while(Result::ok).enumerate() { let rlen = rec.seq().len(); if left >= rlen || right >= rlen || length >= rlen { diff --git a/src/cli/view.rs b/src/cli/view.rs index 836738f..0f67a9e 100644 --- a/src/cli/view.rs +++ b/src/cli/view.rs @@ -7,7 +7,12 @@ use std::io; use std::time::Instant; use term_size::dimensions; -pub fn view_fq(file: Option<&String>, out: Option<&String>, compression_level: u32) -> Result<()> { +pub fn view_fq( + file: Option<&String>, + out: Option<&String>, + compression_level: u32, + stdout_type: char, +) -> Result<()> { let time = Instant::now(); if file.is_none() { error!("do not read file from stdin."); @@ -15,7 +20,7 @@ pub fn view_fq(file: Option<&String>, out: Option<&String>, compression_level: u } let fq_reader = file_reader(file).map(fastq::Reader::new)?; - let mut fq_writer = file_writer(out, compression_level).map(fastq::Writer::new)?; + let mut fq_writer = file_writer(out, compression_level, stdout_type).map(fastq::Writer::new)?; let mut iter_fq = fq_reader.records().map_while(Result::ok).peekable(); let (mut page, mut start, mut end) = (0usize, 1usize, 0usize); diff --git a/src/command.rs b/src/command.rs index a6d701b..3303fdd 100644 --- a/src/command.rs +++ b/src/command.rs @@ -38,6 +38,10 @@ pub struct Args { )] pub compression_level: u32, + /// output type for stdout: 'g' gzip; 'b' bzip2; 'x' xz; 'u' uncompressed txt format + #[arg(long = "output-type", global = true, help_heading = Some("Global Arguments"), value_name = "u|g|b|x", default_value_t = 'u')] + pub stdout_type: char, + /// if file name specified, write log message to this file, or write to stderr #[arg(long = "log", global = true, help_heading = Some("Global Arguments"), value_name = "FILE")] pub logfile: Option, diff --git a/src/main.rs b/src/main.rs index bf88d9f..a9bd445 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,13 @@ fn main() -> Result<(), Error> { match arg.command { Subcli::topn { input, num, out } => { - top_n_records(input.as_ref(), num, out.as_ref(), arg.compression_level)?; + top_n_records( + input.as_ref(), + num, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::tail { input, @@ -36,6 +42,7 @@ fn main() -> Result<(), Error> { rdc, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::subfq { @@ -52,6 +59,7 @@ fn main() -> Result<(), Error> { seed, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::select { @@ -60,7 +68,14 @@ fn main() -> Result<(), Error> { out1, out2, } => { - select_pe_fastq(&read1, &read2, &out1, &out2, arg.compression_level)?; + select_pe_fastq( + &read1, + &read2, + &out1, + &out2, + arg.compression_level, + arg.stdout_type, + )?; } Subcli::trim { input, @@ -76,6 +91,7 @@ fn main() -> Result<(), Error> { len, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::adapter { @@ -92,6 +108,7 @@ fn main() -> Result<(), Error> { miss, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::range { @@ -106,6 +123,7 @@ fn main() -> Result<(), Error> { take, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::search { @@ -126,6 +144,7 @@ fn main() -> Result<(), Error> { out.as_ref(), thread, arg.compression_level, + arg.stdout_type, )?; } Subcli::grep { @@ -140,10 +159,17 @@ fn main() -> Result<(), Error> { full, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::fq2fa { input, remove, out } => { - fq2fa(input.as_ref(), remove, out.as_ref(), arg.compression_level)?; + fq2fa( + input.as_ref(), + remove, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::fq2sam { r1, @@ -163,6 +189,7 @@ fn main() -> Result<(), Error> { pl, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::fqscore { @@ -177,6 +204,7 @@ fn main() -> Result<(), Error> { to33, to64, arg.compression_level, + arg.stdout_type, )?; } Subcli::flatten { @@ -197,6 +225,7 @@ fn main() -> Result<(), Error> { len, gc, arg.compression_level, + arg.stdout_type, )?; } Subcli::plot { @@ -212,7 +241,13 @@ fn main() -> Result<(), Error> { let _x = plot_line(df, show, prefix, width, height, ylim, &types); } Subcli::check { input, save, out } => { - check_fastq(input.as_ref(), save, out.as_ref(), arg.compression_level)?; + check_fastq( + input.as_ref(), + save, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::stats { input, @@ -226,10 +261,17 @@ fn main() -> Result<(), Error> { cyc.as_ref(), phred, arg.compression_level, + arg.stdout_type, )?; } Subcli::shuffle { input, seed, out } => { - shuffle_fastq(input.as_ref(), seed, out.as_ref(), arg.compression_level)?; + shuffle_fastq( + input.as_ref(), + seed, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::size { input, @@ -243,6 +285,7 @@ fn main() -> Result<(), Error> { chunk, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::slide { @@ -259,6 +302,7 @@ fn main() -> Result<(), Error> { out.as_ref(), &suffix, arg.compression_level, + arg.stdout_type, )?; } Subcli::sort { @@ -279,6 +323,7 @@ fn main() -> Result<(), Error> { reverse, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::barcode { @@ -335,6 +380,7 @@ fn main() -> Result<(), Error> { &out1, &out2, arg.compression_level, + arg.stdout_type, )?; } Subcli::concat { @@ -343,7 +389,14 @@ fn main() -> Result<(), Error> { out1, out2, } => { - concat_fqstq_lane(&read1, &read2, &out1, &out2, arg.compression_level)?; + concat_fqstq_lane( + &read1, + &read2, + &out1, + &out2, + arg.compression_level, + arg.stdout_type, + )?; } Subcli::remove { input, @@ -359,6 +412,7 @@ fn main() -> Result<(), Error> { &save, rm, arg.compression_level, + arg.stdout_type, )?; } Subcli::rename { @@ -377,10 +431,17 @@ fn main() -> Result<(), Error> { before, output.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::reverse { input, rev, out } => { - reverse_comp_seq(input.as_ref(), out.as_ref(), rev, arg.compression_level)?; + reverse_comp_seq( + input.as_ref(), + out.as_ref(), + rev, + arg.compression_level, + arg.stdout_type, + )?; } Subcli::split { input, @@ -401,7 +462,13 @@ fn main() -> Result<(), Error> { )?; } Subcli::merge { read1, read2, out } => { - interleaved(&read1, &read2, out.as_ref(), arg.compression_level)?; + interleaved( + &read1, + &read2, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::mask { input, @@ -417,6 +484,7 @@ fn main() -> Result<(), Error> { chars, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } Subcli::split2 { @@ -437,6 +505,7 @@ fn main() -> Result<(), Error> { &name, &outdir, arg.compression_level, + arg.stdout_type, )?; } Subcli::gcplot { @@ -459,6 +528,7 @@ fn main() -> Result<(), Error> { ylim, &types, arg.compression_level, + arg.stdout_type, )?; } Subcli::length { @@ -466,10 +536,21 @@ fn main() -> Result<(), Error> { reverse, out, } => { - fq_length(input.as_ref(), reverse, out.as_ref(), arg.compression_level)?; + fq_length( + input.as_ref(), + reverse, + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::view { input, out } => { - view_fq(input.as_ref(), out.as_ref(), arg.compression_level)?; + view_fq( + input.as_ref(), + out.as_ref(), + arg.compression_level, + arg.stdout_type, + )?; } Subcli::kmer { input, @@ -483,6 +564,7 @@ fn main() -> Result<(), Error> { header, out.as_ref(), arg.compression_level, + arg.stdout_type, )?; } } diff --git a/src/utils.rs b/src/utils.rs index 3e522ac..eede5e7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -97,7 +97,11 @@ where } } -pub fn file_writer

(file_out: Option

, compression_level: u32) -> Result> +pub fn file_writer

( + file_out: Option

, + compression_level: u32, + stdout_format: char, +) -> Result> where P: AsRef + Copy, { @@ -134,7 +138,28 @@ where } else { Ok(Box::new(BufWriter::with_capacity(BUFF_SIZE, fp))) } + } else if stdout_format == 'g' { + Ok(Box::new(BufWriter::with_capacity( + BUFF_SIZE, + flate2::write::GzEncoder::new( + io::stdout(), + flate2::Compression::new(compression_level), + ), + ))) + } else if stdout_format == 'b' { + Ok(Box::new(BufWriter::with_capacity( + BUFF_SIZE, + bzip2::write::BzEncoder::new(io::stdout(), bzip2::Compression::new(compression_level)), + ))) + } else if stdout_format == 'x' { + Ok(Box::new(BufWriter::with_capacity( + BUFF_SIZE, + xz2::write::XzEncoder::new(io::stdout(), compression_level), + ))) + } else if stdout_format == 'u' { + Ok(Box::new(BufWriter::new(io::stdout()))) } else { + warn!("invalid output type option, write uncompressed result in stdout"); Ok(Box::new(BufWriter::new(io::stdout()))) } }