Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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