use fnv::FnvHashMap;
use std::env;
use std::fs;
use std::path::PathBuf;
use crate::argparse;
use crate::db;
use crate::logger;
use crate::table;
#[cfg(target_os = "macos")]
static SYSTEM_OS: &str = "Darwin64";
#[cfg(target_os = "linux")]
static SYSTEM_OS: &str = "Linux64";
fn setup_table(
product_version: &String,
product_table: &table::Table,
env_vars: &mut FnvHashMap<String, String>,
keep: bool,
flavor: &String,
db_path: PathBuf,
) {
let mut setup_var = String::from("SETUP_");
let mut prod_dir_label = product_table.name.clone();
prod_dir_label = prod_dir_label.replace(" ", "_");
prod_dir_label = prod_dir_label.to_uppercase();
setup_var.push_str(prod_dir_label.as_str());
prod_dir_label.push_str("_DIR");
let prod_dir_env = env::var(&prod_dir_label);
if keep && (env_vars.contains_key(&prod_dir_label) || prod_dir_env.is_ok()) {
return;
}
let mut setup_string_vec = vec![product_table.name.clone(), product_version.clone()];
setup_string_vec.push("-f".to_string());
if flavor.is_empty() {
setup_string_vec.push(SYSTEM_OS.to_string());
} else {
setup_string_vec.push(flavor.clone());
}
setup_string_vec.push("-Z".to_string());
if db_path.to_str().unwrap().is_empty() {
setup_string_vec.push("\\(none\\)".to_string());
} else {
setup_string_vec.push(db_path.to_str().unwrap().to_string().replace("ups_db", ""));
}
crate::info!(
"Setting up: {:<25}Version: {}",
product_table.name,
product_version
);
env_vars.insert(
prod_dir_label,
String::from(product_table.product_dir.to_str().unwrap()),
);
env_vars.insert(setup_var, setup_string_vec.join("\\ "));
for (k, v) in product_table.env_var.iter() {
let mut existing_var = match env_vars.get(k) {
Some(existing) => existing.clone(),
None => match env::var(k) {
Ok(r) => r,
Err(_) => String::from(""),
},
};
let mut start_pos = 0;
let mut end_pos = 0;
if let Ok(prod_text) = prod_dir_env.as_ref() {
let start_pos_option = existing_var.find(prod_text.as_str());
if let Some(tmp_start) = start_pos_option {
start_pos = tmp_start;
for (i, character) in existing_var[tmp_start..].chars().enumerate() {
let glob_index = tmp_start + i;
if character == ':' || glob_index == existing_var.len() {
end_pos = glob_index + 1;
break;
}
}
}
if end_pos != 0 {
existing_var.replace_range(start_pos..end_pos, "");
}
}
let output_var = match v {
(table::EnvActionType::Prepend, var) => [var.clone(), existing_var].join(":"),
(table::EnvActionType::Append, var) => [existing_var, var.clone()].join(":"),
};
env_vars.insert(k.clone(), output_var);
}
}
fn get_table_path_from_input(input_path: &str) -> Option<table::Table> {
let mut input_pathbuf = PathBuf::from(input_path);
let mut table_path: Option<PathBuf> = None;
let mut prod_dir: Option<PathBuf> = None;
if input_pathbuf.is_file() {
if let Some(extension) = input_pathbuf.extension() {
if extension.to_str().unwrap() == "table" {
table_path = Some(input_pathbuf.clone());
let mut tmp_prod_dir = input_pathbuf.clone();
tmp_prod_dir.pop();
tmp_prod_dir.pop();
prod_dir = Some(tmp_prod_dir);
}
}
} else if input_pathbuf.is_dir() {
let mut search_path: Option<PathBuf> = None;
if input_pathbuf.ends_with("ups") {
search_path = Some(input_pathbuf.clone());
}
input_pathbuf.push("ups");
if input_pathbuf.is_dir() {
search_path = Some(input_pathbuf);
}
if !search_path.is_none() {
for entry in fs::read_dir(&search_path.unwrap()).unwrap() {
let entry = entry.unwrap();
if let Some(extension) = entry.path().extension() {
if extension.to_str().unwrap() == "table" {
table_path = Some(entry.path());
let mut tmp_prod_dir = entry.path();
tmp_prod_dir.pop();
tmp_prod_dir.pop();
prod_dir = Some(tmp_prod_dir);
}
}
}
}
}
if let Some(table_file) = table_path {
let table_file = table_file.canonicalize().unwrap();
let prod_dir = prod_dir.unwrap().canonicalize().unwrap();
let name = String::from(table_file.file_stem().unwrap().to_str().unwrap());
Some(table::Table::new(name, table_file, prod_dir).unwrap())
} else {
return None;
}
}
fn normalize_path(input: String) -> Result<String, std::io::Error> {
let tmp_path = PathBuf::from(input).canonicalize()?;
let err = std::io::Error::new(std::io::ErrorKind::Other, "Problem normalizing Path");
let tmp_string = tmp_path.to_str().ok_or(err)?;
Ok(String::from(tmp_string))
}
fn get_command_string() -> String {
let mut marker = false;
let mut command_arg = String::new();
let switches = vec!["-r"];
for arg in env::args() {
let next_string: String = match marker {
true => {
marker = false;
normalize_path(arg).unwrap()
}
false => {
if switches.contains(&arg.as_str()) {
marker = true;
}
arg
}
};
command_arg.push_str(format!("{} ", next_string.as_str()).as_str());
}
command_arg.pop();
command_arg
}
pub fn setup_command(sub_args: &argparse::ArgMatches, _main_args: &argparse::ArgMatches) {
logger::build_logger(sub_args, true);
let db = db::DB::new(None, None, None, None);
let current = String::from("current");
let mut tags_str = vec![];
let mut tags = vec![];
if sub_args.is_present("tag") {
for t in sub_args.values_of("tag").unwrap() {
tags_str.push(t.to_string());
}
for t in tags_str.iter() {
tags.push(t);
}
}
crate::info!("Using tags: {:?}", tags);
tags.push(¤t);
let product = sub_args.value_of("product");
let mut mode = table::VersionType::Exact;
if sub_args.is_present("inexact") {
mode = table::VersionType::Inexact;
}
let table_option = match (product, sub_args.value_of("relative")) {
(Some(name), _) => {
if !db.has_product(&name.to_string()) {
exit_with_message!(format!("Cannot find product `{}` to setup", name));
}
let local_table = db.get_table_from_tag(&name.to_string(), tags.clone());
let versions = db.get_versions_from_tag(&name.to_string(), tags.clone());
let mut version = String::from("");
match versions.last() {
Some(v) => {
version = v.clone();
}
None => (),
}
(local_table, version)
}
(None, Some(path)) => {
let table = get_table_path_from_input(path);
let mut version = String::from("");
if table.is_some() {
let mut tmp = String::from("LOCAL:");
tmp.push_str(table.as_ref().unwrap().path.to_str().unwrap());
version = tmp
}
mode = table::VersionType::Inexact;
(table, version)
}
_ => (None, String::from("")),
};
let keep = sub_args.is_present("keep");
if let (Some(table), version) = table_option {
let mut deps: Option<db::graph::Graph> = None;
if !sub_args.is_present("just") {
let mut dep_graph = db::graph::Graph::new(&db);
dep_graph.add_table(
&table,
mode,
db::graph::NodeType::Required,
Some(&tags),
true,
);
deps = Some(dep_graph);
}
let mut env_vars: FnvHashMap<String, String> = FnvHashMap::default();
let flavors = db.get_flavors_from_version(&table.name, &version);
let flavor = match flavors.last() {
Some(flav) => flav.clone(),
None => String::from(""),
};
let db_dirs = db.get_db_directories();
let db_path = match flavors.len() {
1 => db_dirs[0].clone(),
2 => db_dirs[1].clone(),
_ => PathBuf::from(""), };
setup_table(&version, &table, &mut env_vars, false, &flavor, db_path);
if let Some(dependencies) = deps {
for node in dependencies.iter().skip(1) {
let name = dependencies.get_name(node);
let versions = dependencies.product_versions(&name);
let mut largest_version = versions.iter().max().unwrap().clone().clone();
let node_table_option: Option<table::Table>;
if largest_version.as_str() != "" {
node_table_option = db.get_table_from_version(&name, &largest_version);
} else {
node_table_option = db.get_table_from_tag(&name, tags.clone());
let versions = db.get_versions_from_tag(&name, tags.clone());
match versions.last() {
Some(v) => {
largest_version = v.clone();
}
None => (),
}
}
match (node_table_option, dependencies.is_optional(&name)) {
(Some(node_table), _) => {
let flavors =
db.get_flavors_from_version(&node_table.name, &largest_version);
let flavor = match flavors.last() {
Some(flav) => flav.clone(),
None => String::from(""),
};
let db_path = match flavors.len() {
1 => db_dirs[0].clone(),
2 => db_dirs[1].clone(),
_ => PathBuf::from(""), };
setup_table(
&largest_version,
&node_table,
&mut env_vars,
keep,
&flavor,
db_path,
)
}
(None, true) => continue,
(None, false) => {
if env::var(String::from("SETUP_") + &name.to_uppercase()).is_ok() {
crate::warn!("Product {} could not be found in the database, resolving dependency using setup version", &name);
continue;
} else {
exit_with_message!(format!(
"Cannot find any acceptable table for {}",
&name
));
}
}
}
}
}
let current_reups_command = get_command_string();
let reups_history_string = match env::var("REUPS_HISTORY") {
Ok(existing) => format!("\"{}|{}\"", existing, current_reups_command),
_ => format!("\"{}\"", current_reups_command),
};
let reups_history_key = String::from("REUPS_HISTORY");
env_vars.insert(reups_history_key, reups_history_string);
let mut return_string = String::from("export ");
for (k, v) in env_vars {
return_string.push_str([k, v].join("=").as_str());
return_string.push_str(" ");
}
println!("{}", return_string);
} else {
exit_with_message!(
"Error, no product to setup, please specify product or path to table with -r"
);
}
}