helmule/src/source/helm.rs

107 lines
3.4 KiB
Rust

use super::{ChartLocal, Repo};
use crate::helpers::cli::{cli_exec, cli_exec_from_dir};
use base64::{engine::general_purpose, Engine as _};
use std::{fs::rename, collections::HashMap};
pub(crate) enum RepoKind {
Default,
Oci,
}
const LATEST_VERSION: &str = "latest";
pub(crate) struct Helm {
pub(crate) chart: String,
pub(crate) repository_url: String,
pub(crate) version: String,
}
impl From<crate::config::Chart> for Helm {
fn from(value: crate::config::Chart) -> Self {
Helm {
chart: value.name.clone(),
repository_url: value.get_helm_repository_url(),
version: match value.version {
Some(res) => res,
None => LATEST_VERSION.to_string(),
},
}
}
}
impl Helm {
fn repo_kind_from_url(&self) -> Result<RepoKind, Box<dyn std::error::Error>> {
let prefix = self
.repository_url
.chars()
.take_while(|&ch| ch != ':')
.collect::<String>();
match prefix.as_str() {
"oci" => Ok(RepoKind::Oci),
"https" | "http" => Ok(RepoKind::Default),
_ => Err(Box::from(format!(
"repo kind is not defined by the prefix: {}",
prefix
))),
}
}
fn pull_default(&self, workdir_path: String, vars: HashMap<String, String>) -> Result<ChartLocal, Box<dyn std::error::Error>> {
// Add repo and update
let repo_local_name = general_purpose::STANDARD_NO_PAD.encode(self.repository_url.clone());
let cmd = format!("helm repo add {} {}", repo_local_name, self.repository_url);
cli_exec(cmd)?;
cli_exec("helm repo update".to_string())?;
let args = match self.version.as_str() {
LATEST_VERSION => "".to_string(),
_ => format!("--version {}", self.version.clone()),
};
let cmd = format!(
"helm pull {}/{} {} --destination {} --untar",
repo_local_name, &self.chart, args, workdir_path
);
cli_exec(cmd)?;
// Get the version
let cmd = format!("helm show chart {}/{}", workdir_path, &self.chart);
let helm_stdout = cli_exec(cmd)?;
let old_dir_name = format!("{}/{}", workdir_path, &self.chart);
let new_dir_name: String;
match serde_yaml::from_str::<super::Version>(&helm_stdout) {
Ok(res) => {
new_dir_name = format!("{}-{}", old_dir_name, res.version);
rename(old_dir_name, new_dir_name.clone())?;
}
Err(err) => return Err(Box::from(err)),
};
//cleaning up
let cmd = format!("helm repo remove {}", repo_local_name);
cli_exec(cmd)?;
let cmd = "helm show chart . | yq '.version'".to_string();
let version = cli_exec_from_dir(cmd, new_dir_name.clone())?;
Ok(ChartLocal {
name: self.chart.clone(),
version,
path: new_dir_name,
repo_url: self.repository_url.clone(),
vars,
})
}
}
impl Repo for Helm {
fn pull(&self, workdir_path: String, vars: HashMap<String, String>) -> Result<ChartLocal, Box<dyn std::error::Error>> {
let repository_kind = self.repo_kind_from_url()?;
let path = match repository_kind {
RepoKind::Default => self.pull_default(workdir_path, vars)?,
RepoKind::Oci => {
todo!()
}
};
Ok(path)
}
}