Skip to content

Commit

Permalink
Merge pull request #6 from steineggerlab/cfgmodule
Browse files Browse the repository at this point in the history
Add config module
  • Loading branch information
endixk authored Feb 11, 2025
2 parents 50b0e25 + 2dcbcdb commit 77863df
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 11 deletions.
5 changes: 3 additions & 2 deletions path.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
mmseqs=mmseqs
foldseek=foldseek
foldmason=foldmason
mafft=mafft
mafft-linsi=mafft-linsi
foldmason=foldmason
iqtree=iqtree
#fasttree=fasttree
#fasttree=
#raxml=
20 changes: 14 additions & 6 deletions src/envs/error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,30 @@ use crate::util::message;

pub const WRN_GENERAL: i32 = 0x00;
pub const ERR_GENERAL: i32 = 0x01;
pub const ERR_FILE_NOT_FOUND: i32 = 0x02;
pub const ERR_MODULE_NOT_IMPLEMENTED: i32 = 0x03;
pub const ERR_ARGPARSE: i32 = 0x04;
pub const ERR_BINARY_NOT_FOUND: i32 = 0x05;
pub const ERR_OUTPUT_EXISTS: i32 = 0x06;
pub const ERR_FILE_NOT_FOUND: i32 = 0x10;
pub const ERR_FILE_INVALID: i32 = 0x11;
pub const ERR_BINARY_NOT_FOUND: i32 = 0x20;
pub const ERR_BINARY_NOT_EXECUTABLE: i32 = 0x21;
pub const ERR_BINARY_INVALID: i32 = 0x22;
pub const ERR_MODULE_NOT_IMPLEMENTED: i32 = 0x30;
pub const ERR_ARGPARSE: i32 = 0x40;
pub const ERR_OUTPUT_EXISTS: i32 = 0x50;


fn build_message(code: i32, passed_object: Option<String>) -> String {
let object = passed_object.unwrap_or_else(|| "".to_string());
match code {
WRN_GENERAL => format!("Warning: {}", object),
ERR_GENERAL => format!("Error: {}", object),
ERR_FILE_NOT_FOUND => format!("File not found: {}", object),
ERR_FILE_INVALID => format!("Invalid file given: {}", object),
ERR_BINARY_NOT_FOUND => format!("Binary not found: {}", object),
ERR_BINARY_NOT_EXECUTABLE => format!("Binary not executable: {}", object),
ERR_BINARY_INVALID => format!("Invalid binary given: {}", object),
ERR_MODULE_NOT_IMPLEMENTED => format!("Module not implemented: {}", object),
ERR_ARGPARSE => format!("Argument parsing error: {}", object),
ERR_BINARY_NOT_FOUND => format!("Binary not found: {}", object),
ERR_OUTPUT_EXISTS => format!("Output file already exists: {}; use -o to overwrite", object),

_ => "Unknown error".to_string(),
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/envs/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,20 @@ pub fn locate_encoder_py() -> String {
}

// binary paths
const VALID_BINARY: [&str; 7] = [
"mmseqs", "foldseek", "mafft", "mafft-linsi", "foldmason", "iqtree", "fasttree",
pub const VALID_BINARY: [&str; 8] = [
"mmseqs", "foldseek", "mafft", "mafft-linsi", "foldmason", "iqtree", "fasttree", "raxml"
];
pub struct Binary {
name: String,
pub path: String,
pub set: bool,
}
impl Binary {
fn new(name: &str, path: &str) -> Self {
Binary {
name: name.to_string(),
path: path.to_string(),
set: false,
}
}
fn test(&self, args: Vec<&str>) -> bool {
Expand Down Expand Up @@ -129,8 +131,10 @@ impl BinaryPaths {
let mut split = line.split('=');
let name = split.next().unwrap_or("");
let path = split.next().unwrap_or("");
if path.len() == 0 { continue; }
if let Some(&i) = self.map.get(name) {
self.bin[i].path = path.to_string();
self.bin[i].set = true;
}
}
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ fn run(args: &parser::Args, bin: &var::BinaryPaths, test: bool) -> Result<(), Bo
Some(parser::Commands::EasySearch { .. }) => {
workflow::easy_search::run(args, bin).unwrap_or_else(|e| err::error(err::ERR_GENERAL, Some(e.to_string())));
}
Some(parser::Commands::Config { .. }) => {
modules::config::run(args, bin).unwrap_or_else(|e| err::error(err::ERR_GENERAL, Some(e.to_string())));
},
/* Some(_) => {
err::error(err::ERR_MODULE_NOT_IMPLEMENTED, std::env::args().nth(1));
} */
Expand Down
93 changes: 93 additions & 0 deletions src/modules/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::os::unix::fs::MetadataExt;
use std::io::Write;
use crate::envs::error_handler as err;
use crate::envs::variables as var;
use crate::envs::variables::BinaryPaths;
use crate::util::command as cmd;
use crate::util::message as msg;
use crate::util::arg_parser::Args;
use color_print::cstr;

fn task_check(bin: &BinaryPaths) -> Result<(), Box<dyn std::error::Error>> {
msg::println_message(&format!("{}", cstr!(r#"<bold><underline>System:</underline></bold>"#)), 3);
msg::println_message(&format!("Unicore version: {}", var::VERSION), 3);
msg::println_message(&format!("OS: {}", std::env::consts::OS), 3);
msg::println_message(&format!("Threads: {}", var::threads()), 3);
println!();
msg::println_message(&format!("{}", cstr!(r#"<bold><underline>Dependencies:</underline></bold>"#)), 3);
msg::println_message(&format!("MMseqs2: {} .. {}",
if let Some(&ref bin) = &bin.get("mmseqs") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("mmseqs") { if bin.set { if binary_run_test(&bin.path, "mmseqs") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("Foldseek: {} .. {}",
if let Some(&ref bin) = &bin.get("foldseek") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("foldseek") { if bin.set { if binary_run_test(&bin.path, "foldseek") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("FoldMason: {} .. {}",
if let Some(&ref bin) = &bin.get("foldmason") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("foldmason") { if bin.set { if binary_run_test(&bin.path, "foldmason") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("MAFFT: {} .. {}",
if let Some(&ref bin) = &bin.get("mafft") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("mafft") { if bin.set { if binary_run_test(&bin.path, "mafft") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("IQ-TREE: {} .. {}",
if let Some(&ref bin) = &bin.get("iqtree") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("iqtree") { if bin.set { if binary_run_test(&bin.path, "iqtree") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("FastTree: {} .. {}",
if let Some(&ref bin) = &bin.get("fasttree") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("fasttree") { if bin.set { if binary_run_test(&bin.path, "fasttree") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
msg::println_message(&format!("RAxML: {} .. {}",
if let Some(&ref bin) = &bin.get("raxml") { if bin.set { bin.path.clone() } else { "Unset".to_string() } } else { "Undefined".to_string() },
if let Some(&ref bin) = &bin.get("raxml") { if bin.set { if binary_run_test(&bin.path, "raxml") { cstr!(r#"<green>ok</green>"#) } else { cstr!(r#"<red>no</red>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) } } else { cstr!(r#"<dim>n/a</dim>"#) },
), 3);
Ok(())
}

fn binary_run_test(path: &str, sw: &str) -> bool {
if !var::VALID_BINARY.contains(&sw) { return false; }
let mut test_command = std::process::Command::new(path);
let test_command = match sw {
"mmseqs" | "foldseek" | "foldmason" => test_command.arg("version"),
"mafft" | "mafft-linsi" | "iqtree" => test_command.arg("--version"),
"fasttree" => &mut test_command,
"raxml" => test_command.arg("-v"),
_ => return false,
};
cmd::run_code(test_command) == 0
}

fn set_binary(bin: &BinaryPaths, path: &str, sw: &str) -> Result<(), Box<dyn std::error::Error>> {
if !std::fs::File::open(path).is_ok() { err::error(err::ERR_BINARY_NOT_FOUND, Some(format!("{}", path))); }
if std::fs::metadata(path)?.is_dir() { err::error(err::ERR_FILE_INVALID, Some(format!("{}", path))); }
if std::fs::metadata(path)?.mode() & 0o111 == 0 { err::error(err::ERR_BINARY_NOT_EXECUTABLE, Some(format!("{}", path))); }
if !binary_run_test(path, sw) { err::error(err::ERR_BINARY_INVALID, Some(format!("{}", path))); }

let path = std::fs::canonicalize(path)?.to_str().unwrap().to_string();
msg::println_message(&format!("Setting dependency {} to {}...", sw, path), 3);
let mut cfg = std::fs::File::create(var::locate_path_cfg())?;
for &prog in var::VALID_BINARY.iter() {
if prog == sw { cfg.write_all(format!("{}={}\n", prog, path).as_bytes())?; }
else if bin.get(prog).is_none() || !bin.get(prog).unwrap().set { cfg.write_all(format!("#{}=\n", prog).as_bytes())?; }
else { cfg.write_all(format!("{}={}\n", prog, bin.get(prog).unwrap().path).as_bytes())?; }
}
msg::println_message(&"Done. Please run \"unicore config -c\" to check".to_string(), 3);

Ok(())
}

pub fn run(args: &Args, bin: &BinaryPaths) -> Result<(), Box<dyn std::error::Error>> {
if args.config_check.is_some() && args.config_check.unwrap() { task_check(bin)?; }
else if args.config_set_mmseqs.is_some() { set_binary(bin, args.config_set_mmseqs.clone().unwrap().as_str(), "mmseqs")?; }
else if args.config_set_foldseek.is_some() { set_binary(bin, args.config_set_foldseek.clone().unwrap().as_str(), "foldseek")?; }
else if args.config_set_foldmason.is_some() { set_binary(bin, args.config_set_foldmason.clone().unwrap().as_str(), "foldmason")?; }
else if args.config_set_mafft.is_some() { set_binary(bin, args.config_set_mafft.clone().unwrap().as_str(), "mafft")?; }
else if args.config_set_mafft_linsi.is_some() { set_binary(bin, args.config_set_mafft_linsi.clone().unwrap().as_str(), "mafft-linsi")?; }
else if args.config_set_iqtree.is_some() { set_binary(bin, args.config_set_iqtree.clone().unwrap().as_str(), "iqtree")?; }
else if args.config_set_fasttree.is_some() { set_binary(bin, args.config_set_fasttree.clone().unwrap().as_str(), "fasttree")?; }
else if args.config_set_raxml.is_some() { set_binary(bin, args.config_set_raxml.clone().unwrap().as_str(), "raxml")?; }
else { err::error(err::ERR_ARGPARSE, Some("No task specified".to_string())) };
Ok(())
}
3 changes: 2 additions & 1 deletion src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod cluster;
pub mod search;
pub mod profile;
pub mod tree;
pub mod genetree;
pub mod genetree;
pub mod config;
74 changes: 74 additions & 0 deletions src/util/arg_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,40 @@ pub enum Commands {
#[arg(short='v', long, default_value="3")]
verbosity: u8,
},
/// Runtime environment configuration
#[clap(arg_required_else_help = true, allow_hyphen_values = true)]
Config {
/// Check current environment configuration
#[arg(short='c', long)]
check: bool,
/// Set mmseqs binary path
#[arg(long)]
set_mmseqs: Option<PathBuf>,
/// Set foldseek binary path
#[arg(long)]
set_foldseek: Option<PathBuf>,
/// Set foldmason binary path
#[arg(long)]
set_foldmason: Option<PathBuf>,
/// Set mafft binary path
#[arg(long)]
set_mafft: Option<PathBuf>,
/// Set mafft-linsi binary path
#[arg(long)]
set_mafft_linsi: Option<PathBuf>,
/// Set iqtree binary path
#[arg(long)]
set_iqtree: Option<PathBuf>,
/// Set fasttree binary path
#[arg(long)]
set_fasttree: Option<PathBuf>,
/// Set raxml binary path
#[arg(long)]
set_raxml: Option<PathBuf>,
/// Verbosity (0: quiet, 1: +errors, 2: +warnings, 3: +info, 4: +debug)
#[arg(short='v', long, default_value="3")]
verbosity: u8,
},
}

#[derive(Default)]
Expand Down Expand Up @@ -419,6 +453,16 @@ pub struct Args {
pub genetree_realign: Option<bool>,
pub genetree_aligner: Option<String>,
pub genetree_aligner_options: Option<Option<String>>,

pub config_check: Option<bool>,
pub config_set_mmseqs: Option<String>,
pub config_set_foldseek: Option<String>,
pub config_set_foldmason: Option<String>,
pub config_set_mafft: Option<String>,
pub config_set_mafft_linsi: Option<String>,
pub config_set_iqtree: Option<String>,
pub config_set_fasttree: Option<String>,
pub config_set_raxml: Option<String>,
}
fn own(path: &PathBuf) -> String { path.clone().to_string_lossy().into_owned() }
impl Args {
Expand All @@ -433,6 +477,7 @@ impl Args {
Some(GeneTree { verbosity, .. }) => *verbosity,
Some(EasyCore { verbosity, .. }) => *verbosity,
Some(EasySearch { verbosity, .. }) => *verbosity,
Some(Config { verbosity, .. }) => *verbosity,
_ => 3,
};
let threads = match &args.command {
Expand Down Expand Up @@ -641,6 +686,34 @@ impl Args {
Some(GeneTree { threshold, .. }) => Some(*threshold), _ => None,
};

let config_check = match &args.command {
Some(Config { check, .. }) => Some(*check), _ => None,
};
let config_set_mmseqs = match &args.command {
Some(Config { set_mmseqs, .. }) => match set_mmseqs { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_foldseek = match &args.command {
Some(Config { set_foldseek, .. }) => match set_foldseek { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_foldmason = match &args.command {
Some(Config { set_foldmason, .. }) => match set_foldmason { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_mafft = match &args.command {
Some(Config { set_mafft, .. }) => match set_mafft { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_mafft_linsi = match &args.command {
Some(Config { set_mafft_linsi, .. }) => match set_mafft_linsi { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_iqtree = match &args.command {
Some(Config { set_iqtree, .. }) => match set_iqtree { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_fasttree = match &args.command {
Some(Config { set_fasttree, .. }) => match set_fasttree { Some(p) => Some(own(p)), _ => None }, _ => None,
};
let config_set_raxml = match &args.command {
Some(Config { set_raxml, .. }) => match set_raxml { Some(p) => Some(own(p)), _ => None }, _ => None,
};

Args {
command: args.command, version: args.version, threads, verbosity,
createdb_input, createdb_output, createdb_model, createdb_keep, createdb_overwrite, createdb_max_len, createdb_gpu, createdb_use_python, createdb_use_foldseek, createdb_afdb_lookup, createdb_afdb_local,
Expand All @@ -649,6 +722,7 @@ impl Args {
cluster_input, cluster_output, cluster_tmp, cluster_keep_cluster_db, cluster_cluster_options,
tree_db, tree_input, tree_output, tree_aligner, tree_tree_builder, tree_aligner_options, tree_tree_options, tree_threshold,
genetree_input, genetree_names, genetree_tree_builder, genetree_tree_options, genetree_realign, genetree_aligner, genetree_aligner_options, genetree_threshold,
config_check, config_set_mmseqs, config_set_foldseek, config_set_foldmason, config_set_mafft, config_set_mafft_linsi, config_set_iqtree, config_set_fasttree, config_set_raxml,
}
}
}
20 changes: 20 additions & 0 deletions src/util/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ pub fn run(cmd: &mut std::process::Command) {
}
}

pub fn run_code(cmd: &mut std::process::Command) -> i32 {
let cmd = cmd.stdout(std::process::Stdio::null()).stderr(std::process::Stdio::null());
let cmdstr = format!("{:?}", cmd).replace("\"", "");
msg::println_message(&format!("Running command: {}", cmdstr), 4);
if let Ok(mut child) = cmd.spawn() {
let wait = child.wait();
if let Ok(status) = wait {
if let Some(code) = status.code() {
code
} else {
1
}
} else {
1
}
} else {
1
}
}

pub fn _run_at(cmd: &mut std::process::Command, path: &std::path::Path) {
let cmdstr = format!("{:?}", cmd);
if let Ok(mut child) = cmd.current_dir(path).spawn() {
Expand Down

0 comments on commit 77863df

Please sign in to comment.