use crate::common::*;
use crate::{error::KcfgError, KUBECONFIG};
use chrono::*;
use clap::{Clap, ValueHint};
use std::env;
use std::path::Path;
#[derive(Clap, Debug)]
pub struct ForkOption {
#[clap(short = 'p', long, value_hint = ValueHint::DirPath)]
pub target_path: Option<String>,
#[clap(short, long)]
pub overwrite: bool,
#[clap(short, long)]
pub no_export: bool,
}
impl Default for ForkOption {
fn default() -> Self {
Self {
target_path: None,
overwrite: false,
no_export: false,
}
}
}
pub fn fork(params: ForkOption) -> Result<String, KcfgError> {
let kubeconfig_path = env::var(KUBECONFIG).map_err(|e| KcfgError::EnvVarError {
source: e,
var: KUBECONFIG.to_string(),
})?;
check_file_path(&kubeconfig_path)?;
let path = match params.target_path {
Some(s) => {
check_directory_path(&s)?;
let file_name = Path::new(&kubeconfig_path)
.file_name()
.ok_or_else(|| KcfgError::FileNameDoesNotExist(kubeconfig_path.clone()))?
.to_str()
.ok_or_else(|| KcfgError::PathNotUnicode(kubeconfig_path.clone().into()))?;
let target = Path::new(&s);
target.join(file_name)
}
None => Path::new(&kubeconfig_path).to_path_buf(),
};
let path = path
.to_str()
.ok_or_else(|| KcfgError::PathNotUnicode(path.clone().into_os_string()))?;
let mut forked_file_path = path.to_string();
if !params.overwrite {
let time = Utc::now().timestamp_millis();
let timestamp = time.to_string();
forked_file_path = format!("{}.{}", forked_file_path, timestamp);
}
forked_file_path = format!("{}.fork", forked_file_path);
#[cfg(not(test))]
std::fs::copy(kubeconfig_path, &forked_file_path)?;
if !params.no_export {
std::env::set_var(KUBECONFIG, &forked_file_path);
}
Ok(format!("export {}={}", KUBECONFIG, forked_file_path))
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
#[test]
fn works_with_no_param() {
let params = ForkOption {
target_path: None,
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", "README.md");
let res = fork(params).unwrap();
assert_eq!("export KUBECONFIG=README.md.fork".to_string(), res);
assert_eq!(env::var(KUBECONFIG).unwrap(), "README.md.fork".to_string());
}
#[test]
fn works_with_no_param_2() {
let params = ForkOption {
target_path: None,
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", "src/main.rs");
let res = fork(params).unwrap();
assert_eq!("export KUBECONFIG=src/main.rs.fork".to_string(), res);
assert_eq!(
env::var(KUBECONFIG).unwrap(),
"src/main.rs.fork".to_string()
);
}
#[test]
fn works_with_target_path() {
let params = ForkOption {
target_path: Some("src/".to_string()),
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", "README.md");
let res = fork(params).unwrap();
assert_eq!("export KUBECONFIG=src/README.md.fork".to_string(), res);
assert_eq!(
env::var(KUBECONFIG).unwrap(),
"src/README.md.fork".to_string()
);
}
#[test]
fn works_with_no_overwrite() {
let params = ForkOption {
target_path: Some("src/".to_string()),
overwrite: false,
..Default::default()
};
let timestamp = Utc::now().timestamp_millis();
env::set_var("KUBECONFIG", "README.md");
let res = fork(params).unwrap();
assert_eq!(
format!("export KUBECONFIG=src/README.md.{}.fork", timestamp),
res
);
assert_eq!(
env::var(KUBECONFIG).unwrap(),
format!("src/README.md.{}.fork", timestamp)
);
}
#[test]
fn works_with_no_export() {
let params = ForkOption {
target_path: Some("src/".to_string()),
overwrite: false,
no_export: true,
};
let timestamp = Utc::now().timestamp_millis();
env::set_var("KUBECONFIG", "README.md");
let res = fork(params).unwrap();
assert_eq!(
format!("export KUBECONFIG=src/README.md.{}.fork", timestamp),
res
);
assert_eq!(env::var(KUBECONFIG).unwrap(), "README.md".to_string());
}
#[test]
fn fail_with_file_target_path() {
let params = ForkOption {
target_path: Some("src/main.rs".to_string()),
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", "README.md");
match fork(params) {
Ok(_) => panic!("Should return an error"),
Err(e) => {
if !matches!(e, KcfgError::WrongDirectory(_)) {
panic!("Did not receive the expected error, got `{}`", e)
}
}
}
}
#[test]
fn fails_with_wrong_kubeconfig() {
let params = ForkOption {
target_path: None,
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", "src/");
match fork(params) {
Ok(_) => panic!("Should return an error"),
Err(e) => {
if !matches!(e, KcfgError::WrongFile(_)) {
panic!("Did not receive the expected error, got `{}`", e)
}
}
}
}
#[test]
fn fails_with_empty_kubeconfig() {
let params = ForkOption {
target_path: None,
overwrite: true,
..Default::default()
};
env::set_var("KUBECONFIG", " ");
match fork(params) {
Ok(_) => panic!("Should return an error"),
Err(e) => {
if !matches!(e, KcfgError::PathDoesNotExist(_)) {
panic!("Did not receive the expected error, got `{}`", e)
}
}
}
}
#[test]
fn fails_with_missing_kubeconfig() {
let params = ForkOption {
target_path: None,
overwrite: true,
..Default::default()
};
env::remove_var("KUBECONFIG");
match fork(params) {
Ok(_) => panic!("Should return an error"),
Err(e) => {
if !matches!(e, KcfgError::EnvVarError { .. }) {
panic!("Did not receive the expected error, got `{}`", e)
}
}
}
}
}