use std::path::{Path, PathBuf};
use crate::Environment;
use super::ConfigError;
pub const PROJECT_DOCUMENT_NAME: &str = "onetaskgraph.yaml";
pub const USER_DOCUMENT_RELATIVE_PATH: &str = "onetaskgraph/config.yaml";
pub const SECRETS_RELATIVE_PATH: &str = "onetaskgraph/secrets.env";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
pub path: PathBuf,
pub text: String,
}
pub fn documents(
working_directory: &Path,
environment: &Environment,
) -> Result<Vec<Document>, ConfigError> {
let mut found = Vec::new();
if let Some(path) = user_document_path(environment)
&& let Some(text) = read_optional(&path)?
{
found.push(Document { path, text });
}
if let Some(path) = nearest_project_document(working_directory)?
&& let Some(text) = read_optional(&path)?
{
found.push(Document { path, text });
}
Ok(found)
}
#[must_use]
pub fn user_document_path(environment: &Environment) -> Option<PathBuf> {
Some(configuration_home(environment)?.join(USER_DOCUMENT_RELATIVE_PATH))
}
#[must_use]
pub fn secrets_path(environment: &Environment) -> Option<PathBuf> {
if let Some(override_path) = environment.non_empty(super::SECRETS_FILE_VARIABLE) {
return Some(PathBuf::from(override_path));
}
Some(configuration_home(environment)?.join(SECRETS_RELATIVE_PATH))
}
fn configuration_home(environment: &Environment) -> Option<PathBuf> {
if let Some(xdg) = environment.non_empty("XDG_CONFIG_HOME") {
return Some(PathBuf::from(xdg));
}
Some(PathBuf::from(environment.non_empty("HOME")?).join(".config"))
}
fn nearest_project_document(working_directory: &Path) -> Result<Option<PathBuf>, ConfigError> {
for directory in working_directory.ancestors() {
let candidate = directory.join(PROJECT_DOCUMENT_NAME);
match candidate.try_exists() {
Ok(true) => return Ok(Some(candidate)),
Ok(false) => {}
Err(error) => return Err(ConfigError::read(&candidate, &error)),
}
}
Ok(None)
}
pub fn read_optional(path: &Path) -> Result<Option<String>, ConfigError> {
match std::fs::read_to_string(path) {
Ok(text) => Ok(Some(text)),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(error) => Err(ConfigError::read(path, &error)),
}
}