use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use crate::actions::staged::{Stage, StagedAction};
use crate::actions::{Action, DefinedAction};
use crate::bset;
use crate::entities::ansible_opts::AnsibleOpts;
use crate::entities::containered_opts::ContaineredOpts;
use crate::entities::custom_command::CustomCommand;
use crate::entities::github_cicd_opts::GitHubOpts;
use crate::entities::gitlab_cicd_opts::GitLabOpts;
use crate::entities::info::{Info, ShortName};
use crate::entities::remote_host::RemoteHost;
use crate::entities::requirements::Requirement;
use crate::pipelines::DescribedPipeline;
const CURRENT_GLOBAL_CONF_VERSION: u8 = 5;
pub fn get_default_global_conf_version() -> u8 {
CURRENT_GLOBAL_CONF_VERSION
}
#[derive(Deserialize, Serialize, Clone)]
pub struct DeployerGlobalConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub projects: Vec<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub actions_registry: BTreeSet<DefinedAction>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub pipelines_registry: BTreeSet<DescribedPipeline>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub remote_hosts: BTreeMap<ShortName, RemoteHost>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub containered_registry: BTreeMap<Info, ContaineredOpts>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub ansible_registry: BTreeMap<Info, AnsibleOpts>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub github_registry: BTreeMap<Info, GitHubOpts>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub gitlab_registry: BTreeMap<Info, GitLabOpts>,
#[serde(default = "get_default_global_conf_version")]
pub version: u8,
}
#[derive(Deserialize, Serialize)]
struct Registries {
actions: BTreeSet<DefinedAction>,
pipelines: BTreeSet<DescribedPipeline>,
}
impl DeployerGlobalConfig {
pub fn make_sure_contain_defaults(actions_registry: &mut BTreeSet<DefinedAction>) {
let info = Info::new("interrupt", "0.1.0").unwrap();
actions_registry.insert(DefinedAction {
info,
tags: Default::default(),
action: Action::Interrupt,
requirements: Default::default(),
exec_in_project_dir: None,
skip_sync: None,
});
}
pub fn export_registries(&self, path: &str) -> anyhow::Result<()> {
let registries = Registries {
actions: self.actions_registry.clone(),
pipelines: self.pipelines_registry.clone(),
};
let content = serde_pretty_yaml::to_string_pretty(®istries)?;
std::fs::write(path, content)?;
Ok(())
}
pub fn import_registries(&mut self, path: &str) -> anyhow::Result<()> {
let content = std::fs::read_to_string(path)?;
let registries = serde_pretty_yaml::from_str::<Registries>(&content)?;
self.actions_registry = self.actions_registry.union(®istries.actions).cloned().collect();
self.pipelines_registry = self.pipelines_registry.union(®istries.pipelines).cloned().collect();
Ok(())
}
}
impl Default for DeployerGlobalConfig {
fn default() -> Self {
let mut actions_registry = bset!();
let pipelines_registry = bset!();
DeployerGlobalConfig::make_sure_contain_defaults(&mut actions_registry);
let info = Info::new("cargo-release", "0.1.0").unwrap();
actions_registry.insert(DefinedAction {
info,
tags: vec!["rust".into(), "cargo".into()],
action: Action::Staged(StagedAction {
stage: Some(Stage::Build),
command: CustomCommand {
cmd: "cargo build --release".into(),
placeholders: Default::default(),
env: Default::default(),
ignore_fails: None,
show_success_output: None,
show_cmd: None,
only_when_fresh: None,
remote_exec: Default::default(),
daemon: None,
daemon_wait_seconds: None,
},
}),
requirements: vec![Requirement::ExistsAny {
paths: [PathBuf::from("/bin/cargo"), PathBuf::from("~/.cargo/bin/cargo")]
.into_iter()
.collect::<BTreeSet<_>>(),
desc: "Install `cargo` via your package manager or with this command: `curl https://sh.rustup.rs -sSf | sh`."
.to_string(),
}],
exec_in_project_dir: None,
skip_sync: None,
});
Self {
actions_registry,
pipelines_registry,
projects: Default::default(),
remote_hosts: Default::default(),
containered_registry: Default::default(),
ansible_registry: Default::default(),
github_registry: Default::default(),
gitlab_registry: Default::default(),
version: CURRENT_GLOBAL_CONF_VERSION,
}
}
}
pub fn extract_version(value: impl AsRef<str>) -> anyhow::Result<u8> {
let value = serde_pretty_yaml::from_str::<serde_pretty_yaml::Value>(value.as_ref())?;
if value.is_mapping()
&& let Some(version) = value.get("version")
&& let Some(version) = version.as_u64()
{
return Ok(version as u8);
}
anyhow::bail!("Can't detect config version! Config file is invalid!")
}