1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
extern crate scoped_threadpool;
extern crate getopts;
extern crate bio;
extern crate time;

use scoped_threadpool::Pool;
use getopts::Options;
use std::process::Command;
use std::path::Path;
use bio::io::fasta;
use time::now;

type ThrdNm = u32;

pub fn rn_riblast_in_prll(args: &Vec<String>) {
  let prgrm = args[0].clone();
  let mut opts = Options::new();
  opts.reqopt("i", "", "RNA seqs in single file of FASTA format", "STR");
  opts.reqopt("o", "", "Path to output dir.", "STR");
  opts.reqopt("d", "", "Path to database", "STR");
  opts.optopt("l", "", "Max size of seed length (Default: 20)", "UINT");
  opts.optopt("e", "", "Interaction energy threshold for seed search (Default: -6.5)", "FLOAT");
  opts.optopt("f", "", "Hybridization energy threshold for removal of interaction candidates before gapped extension (Default: -3.05)", "FLOAT");
  opts.optopt("x", "", "Dropout length in gapped extension (Default: 18)", "UINT");
  opts.optopt("y", "", "Dropout length in gapless extension (Default: 5)", "UINT");
  opts.optopt("t", "", "# of threads in multithreading (Default: system val.)", "UINT");
  opts.optopt("b", "", "Path to RIblast binary (Default: system val.)", "STR");
  opts.optflag("h", "help", "Print help menu");
  let mtchs = match opts.parse(&args[1 ..]) {
    Ok(mtch) => {mtch}
    Err(fl) => {prnt_usg(&prgrm, &opts); panic!(fl.to_string())}
  };
  if mtchs.opt_present("h") {
    prnt_usg(&prgrm, &opts);
    return;
  }
  let mut thrd_nm = 0;
  if mtchs.opt_present("t") {
    thrd_nm = mtchs.opt_str("t").expect("Retrieving num. of threads from command args failed. ").parse().expect("Parsing num. of threads failed. ");
  } else {
    gt_sys_thrd_nm(&mut thrd_nm);
  };
  let riblast_pth = if mtchs.opt_present("b") {
    mtchs.opt_str("b").expect("Retrieving path to RIblast from command args failed. ")
  } else {
    String::from("RIblast")
  };
  let tm_stmp = now();
  let tm_stmp = (tm_stmp.tm_year + 1900).to_string() + "-" + &(tm_stmp.tm_mon + 1).to_string() + "-" + &tm_stmp.tm_mday.to_string() + "-" + &tm_stmp.tm_hour.to_string() + ":" + &tm_stmp.tm_min.to_string() + ":" + &tm_stmp.tm_sec.to_string();
  let tmp = String::from("/tmp/prll_ri_") + &tm_stmp;
  let tmp = Path::new(&tmp);
  if !tmp.exists() {
    Command::new("mkdir").arg(tmp.to_str().expect("Parsing temporary dir. path failed. ")).output().expect("Creating temporary dir. failed. ");
  }
  let inpt = mtchs.opt_str("i").expect("Retrieving input file path from command args failed. ");
  let otpt_dr = mtchs.opt_str("o").expect("Retrieving output dir. path from command args failed. ");
  let otpt_dr = Path::new(&otpt_dr);
  if !otpt_dr.exists() {
    Command::new("mkdir").arg(otpt_dr.to_str().expect("Parsing output dir. path failed. ")).output().expect("Creating output dir. failed. ");
  }
  let mut args = Vec::new();
  let opts = vec!["d", "l", "e", "f", "x", "y"];
  let opt_dflt_vls = vec!["", "20", "-6.5", "-3.05", "18", "5"];
  for itr_pr in opts.iter().zip(opt_dflt_vls.iter()) {
    let (opt, opt_dflt_vl) = itr_pr;
    let mut arg = String::from("-");
    arg.push_str(opt);
    args.push(arg);
    if mtchs.opt_present(opt) {
      args.push(String::from(mtchs.opt_str(opt).expect("Retrieving option failed. ")));
    } else {
      args.push(String::from(*opt_dflt_vl));
    }
  }
  let mut thrd_pl = Pool::new(thrd_nm);
  let _grd = thrd_pl.scoped(|scoped| {
    let fasta_rdr = fasta::Reader::from_file(Path::new(&inpt)).ok().expect("Reading FASTA file failed. ");
    for (_i, rc) in fasta_rdr.records().enumerate() {
      scoped.execute(|| {
        let dt = rc.ok().expect("Reading FASTA record failed. ");
        let dt_id = dt.id().expect("Record ID is missing. ");
        let tmp_otpt = tmp.join(String::from(dt_id) + ".fa");
        let otpt = otpt_dr.join(dt_id);
        let mut fasta_wrtr = fasta::Writer::to_file(Path::new(&tmp_otpt)).ok().expect("Writing into FASTA file is blocked. ");
        let _rslt = fasta_wrtr.write_record(&dt);
        let _rslt = fasta_wrtr.flush();
        let mut riblast_args = args.clone();
        riblast_args.insert(0, String::from("ris"));
        riblast_args.push(String::from("-i"));
        riblast_args.push(String::from(tmp_otpt.to_str().expect("Parsing temporary file path failed. ")));
        riblast_args.push(String::from("-o"));
        riblast_args.push(String::from(otpt.to_str().expect("Parsing output dir. path failed. ")));
        let mut riblast_arg_slcs = Vec::new();
        for riblast_arg in &riblast_args {
          riblast_arg_slcs.push(riblast_arg.as_str());
        }
        let otpt = Command::new(&riblast_pth).args(&riblast_arg_slcs).output().expect("RIblast failed. ");
        println!("Status: {}", otpt.status);
        println!("stdout: {}", String::from_utf8_lossy(&otpt.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&otpt.stderr));
        assert!(otpt.status.success());
      });
    }
  });
  Command::new("rm").args(&["-rf", tmp.to_str().expect("Parsing temporary dir. path failed. ")]).output().expect("Removing temporary dir. failed. ");
}

pub fn prnt_usg(prgrm: &str, opts: &Options) {
  let brf = format!("Usage: {} [options]", prgrm);
  print!("{}", opts.usage(&brf));
}

fn gt_sys_thrd_nm(thrd_nm: &mut ThrdNm) {
  let otpt = Command::new("nproc").output().expect("Counting system threads failed. ");
  *thrd_nm = String::from_utf8_lossy(&otpt.stdout).trim().parse().expect("Parsing num. of threads failed. ");
}