Pārlūkot izejas kodu

keep ancient mtime when modifying BAM header for adding SM tag in Mutect2

Thomas 3 nedēļas atpakaļ
vecāks
revīzija
63632f0b37
3 mainītis faili ar 30 papildinājumiem un 5 dzēšanām
  1. 3 3
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 26 2
      src/io/bam.rs

+ 3 - 3
Cargo.lock

@@ -1002,14 +1002,13 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
 
 [[package]]
 name = "filetime"
-version = "0.2.26"
+version = "0.2.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
 dependencies = [
  "cfg-if",
  "libc",
  "libredox",
- "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1957,6 +1956,7 @@ dependencies = [
  "directories 6.0.0",
  "dirs",
  "env_logger",
+ "filetime",
  "flatbuffers",
  "glob",
  "hashbrown 0.16.1",

+ 1 - 0
Cargo.toml

@@ -54,6 +54,7 @@ noodles-bgzf = "0.45.0"
 triple_accel = "0.4.0"
 chainfile = "0.3.0"
 omics = "0.2.0"
+filetime = "0.2.27"
 
 [profile.dev]
 opt-level = 0

+ 26 - 2
src/io/bam.rs

@@ -771,6 +771,22 @@ pub fn fb_inv_from_record(
 //     anyhow::bail!("No SM tag found in @RG header of {bam_path}")
 // }
 
+// fn ensure_bam_sm_tag(id: &str, config: &Config) -> anyhow::Result<()> {
+//     for bam in [config.normal_bam(id), config.tumoral_bam(id)] {
+//         if read_sm_tag(&bam).is_err() {
+//             let sample = Path::new(&bam)
+//                 .file_stem()
+//                 .unwrap_or_default()
+//                 .to_string_lossy()
+//                 .to_string();
+//             info!("Injecting missing @RG SM:{sample} into {bam}");
+//             SamtoolsReheader::from_config(config, &bam, &sample).run()?;
+//             SamtoolsIndex::from_config(config, &bam).run()?;
+//         }
+//     }
+//     Ok(())
+// }
+
 pub fn read_sm_tag_or_inject(
     bam_path: &str,
     fallback_sample: &str,
@@ -780,7 +796,6 @@ pub fn read_sm_tag_or_inject(
         .with_context(|| format!("Failed to open BAM: {bam_path}"))?;
     let header = bam::Header::from_template(reader.header());
     let header_text = String::from_utf8_lossy(&header.to_bytes()).to_string();
-
     for line in header_text.lines() {
         if line.starts_with("@RG") {
             for field in line.split('\t') {
@@ -791,9 +806,14 @@ pub fn read_sm_tag_or_inject(
         }
     }
 
+    // Preserve original mtime before modifying header
+    let original_mtime = filetime::FileTime::from_last_modification_time(
+        &std::fs::metadata(bam_path)
+            .with_context(|| format!("Failed to stat BAM: {bam_path}"))?,
+    );
+
     // SM missing (dorado/MinKNOW unclassified barcode) — inject it
     info!("No @RG SM tag in {bam_path}, injecting SM:{fallback_sample}");
-
     let mut reheader = SamtoolsReheader::from_config(config, bam_path, fallback_sample);
     reheader
         .run()
@@ -804,5 +824,9 @@ pub fn read_sm_tag_or_inject(
         .run()
         .with_context(|| format!("Failed to re-index {bam_path}"))?;
 
+    // Restore original mtime so is_file_older() doesn't re-trigger downstream callers
+    filetime::set_file_mtime(bam_path, original_mtime)
+        .with_context(|| format!("Failed to restore mtime on {bam_path}"))?;
+
     Ok(fallback_sample.to_string())
 }