2024-01-25 22:33:48 +01:00
|
|
|
use std::{collections::HashMap, fmt::Debug, fs::File, io::BufReader, path::PathBuf};
|
2024-01-24 23:04:01 +01:00
|
|
|
|
|
|
|
use git2;
|
2024-01-25 22:33:48 +01:00
|
|
|
use libpt::log::{debug, error, trace};
|
2024-01-24 23:04:01 +01:00
|
|
|
use serde::Deserialize;
|
2024-01-25 22:08:05 +01:00
|
|
|
use url::Url;
|
2024-01-24 23:04:01 +01:00
|
|
|
|
2024-01-25 22:08:05 +01:00
|
|
|
use crate::error::*;
|
2024-01-24 23:04:01 +01:00
|
|
|
|
|
|
|
pub mod cli;
|
2024-01-25 22:08:05 +01:00
|
|
|
use cli::Cli;
|
2024-01-24 23:04:01 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub struct Changelog {
|
2024-01-25 22:08:05 +01:00
|
|
|
enable: bool,
|
2024-01-24 23:04:01 +01:00
|
|
|
git_log: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub struct Uses {
|
|
|
|
cargo: Option<Cargo>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub struct Cargo {
|
|
|
|
publish: bool,
|
|
|
|
registries: Vec<String>,
|
|
|
|
}
|
|
|
|
|
2024-01-25 22:08:05 +01:00
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
2024-01-25 22:33:48 +01:00
|
|
|
pub struct ApiAuth {
|
|
|
|
user: String,
|
|
|
|
pass: Option<String>,
|
|
|
|
pass_file: Option<PathBuf>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ApiAuth {
|
|
|
|
pub fn check(&self) -> Result<()> {
|
|
|
|
if self.pass.is_some() && self.pass_file.is_some() {
|
|
|
|
let err = ConfigError::YamlApiAuthBothPass(self.clone()).into();
|
|
|
|
error!("{err}");
|
|
|
|
return Err(err);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2024-01-25 22:08:05 +01:00
|
|
|
|
2024-01-24 23:04:01 +01:00
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub struct Api {
|
2024-01-25 22:08:05 +01:00
|
|
|
r#type: ApiType,
|
|
|
|
endpoint: Url,
|
2024-01-25 22:33:48 +01:00
|
|
|
/// May be left empty if the Api does not need auth or the auth is part of the
|
|
|
|
/// [endpoint](Api::endpoint) [Url].
|
|
|
|
auth: Option<ApiAuth>,
|
|
|
|
}
|
|
|
|
impl Api {
|
|
|
|
pub fn check(&self) -> Result<()> {
|
|
|
|
if let Some(auth) = &self.auth {
|
|
|
|
auth.check()?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-01-24 23:04:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub enum ApiType {
|
2024-01-25 22:33:48 +01:00
|
|
|
#[serde(alias = "gitea")]
|
2024-01-24 23:04:01 +01:00
|
|
|
Gitea,
|
2024-01-25 22:33:48 +01:00
|
|
|
#[serde(alias = "gitlab")]
|
2024-01-24 23:04:01 +01:00
|
|
|
Gitlab,
|
2024-01-25 22:33:48 +01:00
|
|
|
#[serde(alias = "github", alias = "GitHub")]
|
2024-01-24 23:04:01 +01:00
|
|
|
Github,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
|
|
pub struct YamlConfig {
|
|
|
|
pub changelog: Changelog,
|
|
|
|
pub uses: Uses,
|
2024-01-25 22:33:48 +01:00
|
|
|
pub api: HashMap<String, Api>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl YamlConfig {
|
|
|
|
/// check if the built configuration is valid
|
|
|
|
pub fn check(&self) -> Result<()> {
|
|
|
|
for api in &self.api {
|
|
|
|
api.1.check()?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-01-24 23:04:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Config {
|
|
|
|
pub yaml: YamlConfig,
|
|
|
|
pub repo: git2::Repository,
|
|
|
|
pub path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for Config {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{}",
|
|
|
|
format!(
|
|
|
|
"Config {{yaml: {:?}, repo_path: {:?}}}",
|
|
|
|
self.yaml, self.path
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Config {
|
|
|
|
pub fn load(cli: Cli) -> Result<Self> {
|
|
|
|
let repo = match git2::Repository::open_from_env() {
|
|
|
|
Ok(repo) => repo,
|
|
|
|
Err(err) => {
|
2024-01-25 22:33:48 +01:00
|
|
|
let err = ConfigError::GitRepoNotFound.into();
|
2024-01-25 22:08:05 +01:00
|
|
|
error!("{err}");
|
|
|
|
return Err(err);
|
2024-01-24 23:04:01 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let mut path = repo.path().to_path_buf();
|
|
|
|
path.pop(); // we want the real root, not the `.git` dir
|
|
|
|
|
2024-01-25 22:08:05 +01:00
|
|
|
let yaml_file_name = if path.join(".autocrate.yaml").exists() {
|
|
|
|
".autocrate.yaml"
|
|
|
|
} else if path.join(".autocrate.yml").exists() {
|
|
|
|
".autocrate.yml"
|
|
|
|
} else {
|
2024-01-25 22:33:48 +01:00
|
|
|
let err = ConfigError::NoYamlFile.into();
|
2024-01-25 22:08:05 +01:00
|
|
|
error!("{err}");
|
|
|
|
return Err(err);
|
|
|
|
};
|
|
|
|
let yaml_file_path = path.join(yaml_file_name);
|
|
|
|
// we can be sure it exists from the checks above
|
|
|
|
assert!(yaml_file_path.exists());
|
|
|
|
if !yaml_file_path.is_file() {
|
2024-01-25 22:33:48 +01:00
|
|
|
let err = ConfigError::YamlFileIsNotFile.into();
|
2024-01-25 22:08:05 +01:00
|
|
|
error!("{err}");
|
|
|
|
return Err(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
let yaml_rd = BufReader::new(File::open(yaml_file_path)?);
|
2024-01-25 22:33:48 +01:00
|
|
|
debug!("reading yaml config and building data structure");
|
2024-01-25 22:08:05 +01:00
|
|
|
let yaml: YamlConfig = serde_yaml::from_reader(yaml_rd)?;
|
2024-01-25 22:33:48 +01:00
|
|
|
trace!("load config:\n{:#?}", yaml);
|
|
|
|
yaml.check()?;
|
|
|
|
debug!("built and checked yaml config");
|
2024-01-25 22:08:05 +01:00
|
|
|
|
|
|
|
Ok(Config { yaml, repo, path })
|
2024-01-24 23:04:01 +01:00
|
|
|
}
|
|
|
|
}
|