From 611bb70432ab95c859d01013d6d80e43741a86ac Mon Sep 17 00:00:00 2001 From: James Webber Date: Wed, 13 Mar 2024 10:35:17 -0400 Subject: [PATCH 1/4] add new example for full PG entry --- noodles-bam/examples/bam_add_tag_to_header.rs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 noodles-bam/examples/bam_add_tag_to_header.rs diff --git a/noodles-bam/examples/bam_add_tag_to_header.rs b/noodles-bam/examples/bam_add_tag_to_header.rs new file mode 100644 index 000000000..6851ddc4a --- /dev/null +++ b/noodles-bam/examples/bam_add_tag_to_header.rs @@ -0,0 +1,73 @@ +//! Add a PG tag to the SAM header of a BAM file. +//! +//! This is a demonstration of how to construct a full PG entry. +//! +//! Verify the output by piping to `samtools view --with-header`. + +use std::{env, io}; + +use noodles_bam as bam; +use noodles_sam::header::record::value::{ + map::{Program, Tag}, + Map, +}; +use noodles_sam::Header; + +const NAME: &str = "bam_add_tag"; +const VERSION: &str = env!("CARGO_PKG_VERSION"); + +fn add_pg(mut header: Header) -> Header { + // standard PG tags PN, VN, PP, CL + let pn = match Tag::try_from([b'P', b'N']) { + Ok(Tag::Other(tag)) => tag, + _ => unreachable!(), + }; + let vn = match Tag::try_from([b'V', b'N']) { + Ok(Tag::Other(tag)) => tag, + _ => unreachable!(), + }; + let pp = match Tag::try_from([b'P', b'P']) { + Ok(Tag::Other(tag)) => tag, + _ => unreachable!(), + }; + let cl = match Tag::try_from([b'C', b'L']) { + Ok(Tag::Other(tag)) => tag, + _ => unreachable!(), + }; + // the command-line to insert into the CL tag + let cmd_str = env::args().collect::>().join(" "); + + let program = Map::::builder().insert(pn, NAME); + + let program = if let Some(last_pg) = header.programs().iter().last() { + program.insert(pp, last_pg.0.clone()) + } else { + program + }; + + let program = program + .insert(vn, VERSION) + .insert(cl, cmd_str) + .build() + .unwrap(); + header.programs_mut().insert(NAME.into(), program); + + header +} + +fn main() -> io::Result<()> { + let src = env::args().nth(1).expect("missing src"); + + let mut reader = bam::io::reader::Builder.build_from_path(src)?; + + let header = add_pg(reader.read_header()?); + + let stdout = io::stdout().lock(); + let mut writer = bam::io::Writer::new(stdout); + + writer.write_header(&header)?; + + io::copy(reader.get_mut(), writer.get_mut())?; + + Ok(()) +} From d67bc78f84a25f0dbf8894a20fa755f9116b2a64 Mon Sep 17 00:00:00 2001 From: James Webber Date: Wed, 13 Mar 2024 10:48:20 -0400 Subject: [PATCH 2/4] small cleanup --- noodles-bam/examples/bam_add_tag_to_header.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/noodles-bam/examples/bam_add_tag_to_header.rs b/noodles-bam/examples/bam_add_tag_to_header.rs index 6851ddc4a..7969ca0e1 100644 --- a/noodles-bam/examples/bam_add_tag_to_header.rs +++ b/noodles-bam/examples/bam_add_tag_to_header.rs @@ -13,10 +13,10 @@ use noodles_sam::header::record::value::{ }; use noodles_sam::Header; -const NAME: &str = "bam_add_tag"; -const VERSION: &str = env!("CARGO_PKG_VERSION"); - fn add_pg(mut header: Header) -> Header { + const NAME: &str = "bam_add_tag"; + const VERSION: &str = env!("CARGO_PKG_VERSION"); + // standard PG tags PN, VN, PP, CL let pn = match Tag::try_from([b'P', b'N']) { Ok(Tag::Other(tag)) => tag, @@ -39,8 +39,8 @@ fn add_pg(mut header: Header) -> Header { let program = Map::::builder().insert(pn, NAME); - let program = if let Some(last_pg) = header.programs().iter().last() { - program.insert(pp, last_pg.0.clone()) + let program = if let Some(last_pg) = header.programs().keys().last() { + program.insert(pp, last_pg.clone()) } else { program }; From ec3993a711c81cb654c34d5bbb8b57c042cb0b52 Mon Sep 17 00:00:00 2001 From: James Webber Date: Wed, 13 Mar 2024 10:50:35 -0400 Subject: [PATCH 3/4] name should match example name --- noodles-bam/examples/bam_add_tag_to_header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noodles-bam/examples/bam_add_tag_to_header.rs b/noodles-bam/examples/bam_add_tag_to_header.rs index 7969ca0e1..9700227c9 100644 --- a/noodles-bam/examples/bam_add_tag_to_header.rs +++ b/noodles-bam/examples/bam_add_tag_to_header.rs @@ -14,7 +14,7 @@ use noodles_sam::header::record::value::{ use noodles_sam::Header; fn add_pg(mut header: Header) -> Header { - const NAME: &str = "bam_add_tag"; + const NAME: &str = "bam_add_tag_to_header"; const VERSION: &str = env!("CARGO_PKG_VERSION"); // standard PG tags PN, VN, PP, CL From e1a8c546b7b066a3e83bbf076da801220583460f Mon Sep 17 00:00:00 2001 From: James Webber Date: Thu, 14 Mar 2024 16:00:09 -0400 Subject: [PATCH 4/4] use existing program tags --- noodles-bam/examples/bam_add_tag_to_header.rs | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/noodles-bam/examples/bam_add_tag_to_header.rs b/noodles-bam/examples/bam_add_tag_to_header.rs index 9700227c9..bc2579b9a 100644 --- a/noodles-bam/examples/bam_add_tag_to_header.rs +++ b/noodles-bam/examples/bam_add_tag_to_header.rs @@ -8,7 +8,7 @@ use std::{env, io}; use noodles_bam as bam; use noodles_sam::header::record::value::{ - map::{Program, Tag}, + map::{program::tag, Program}, Map, }; use noodles_sam::Header; @@ -17,37 +17,20 @@ fn add_pg(mut header: Header) -> Header { const NAME: &str = "bam_add_tag_to_header"; const VERSION: &str = env!("CARGO_PKG_VERSION"); - // standard PG tags PN, VN, PP, CL - let pn = match Tag::try_from([b'P', b'N']) { - Ok(Tag::Other(tag)) => tag, - _ => unreachable!(), - }; - let vn = match Tag::try_from([b'V', b'N']) { - Ok(Tag::Other(tag)) => tag, - _ => unreachable!(), - }; - let pp = match Tag::try_from([b'P', b'P']) { - Ok(Tag::Other(tag)) => tag, - _ => unreachable!(), - }; - let cl = match Tag::try_from([b'C', b'L']) { - Ok(Tag::Other(tag)) => tag, - _ => unreachable!(), - }; // the command-line to insert into the CL tag let cmd_str = env::args().collect::>().join(" "); - let program = Map::::builder().insert(pn, NAME); + let program = Map::::builder().insert(tag::NAME, NAME); let program = if let Some(last_pg) = header.programs().keys().last() { - program.insert(pp, last_pg.clone()) + program.insert(tag::PREVIOUS_PROGRAM_ID, last_pg.clone()) } else { program }; let program = program - .insert(vn, VERSION) - .insert(cl, cmd_str) + .insert(tag::VERSION, VERSION) + .insert(tag::COMMAND_LINE, cmd_str) .build() .unwrap(); header.programs_mut().insert(NAME.into(), program);