use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::logfile::{AdminLog, LogError};
/// Configuration file for `radicle-native-ci`.
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
/// Directory where per-run directories are stored. Each run gets
/// its own dedicated subdirectory.
pub state: PathBuf,
/// File where native CI should write a log.
pub log: PathBuf,
/// Optional base URL to information about each run. The run ID is
/// appended, with a slash if needed.
#[serde(skip_serializing_if = "Option::is_none")]
pub base_url: Option<String>,
}
impl Config {
pub fn load_via_env() -> Result<Self, ConfigError> {
const ENV: &str = "RADICLE_NATIVE_CI";
let filename = std::env::var(ENV).map_err(|e| ConfigError::GetEnv(ENV, e))?;
let filename = Path::new(&filename);
let config = Config::read(filename)?;
Ok(config)
}
pub fn open_log(&self) -> Result<AdminLog, ConfigError> {
Ok(AdminLog::open(&self.log)?)
}
/// Read configuration specification from a file.
pub fn read(filename: &Path) -> Result<Self, ConfigError> {
let file = std::fs::File::open(filename)
.map_err(|e| ConfigError::ReadConfig(filename.into(), e))?;
serde_norway::from_reader(&file).map_err(|e| ConfigError::ParseConfig(filename.into(), e))
}
/// Return configuration serialized to JSON.
pub fn as_json(&self) -> String {
// We don't check the result: we know a configuration can
// always be serialized to JSON.
serde_json::to_string_pretty(self).unwrap()
}
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("failed to read configuration file {0}")]
ReadConfig(PathBuf, #[source] std::io::Error),
#[error("failed to parse configuration file as YAML: {0}")]
ParseConfig(PathBuf, #[source] serde_norway::Error),
#[error("failed to get environment variable {0}")]
GetEnv(&'static str, #[source] std::env::VarError),
#[error(transparent)]
Log(#[from] LogError),
}