prdoclib/
config.rs

1//! PRDoc config
2
3use crate::{error::Result, utils::get_project_root};
4use serde::Deserialize;
5use std::{fs, path::PathBuf};
6
7const CONFIG_NAMES: &[&str] = &["prdoc.toml", ".prdoc.toml"];
8
9/// Environment variables used by PRDoc
10pub mod env {
11	/// If the config is not located at the root of the project or does not have standard name, it
12	/// can still be provided via this env variable
13	pub const PRDOC_CONFIG: &str = "PRDOC_CONFIG";
14
15	/// Not fully supported yet
16	//TODO: Add proper support
17	pub const PRDOC_FOLDERS: &str = "PRDOC_FOLDERS";
18}
19
20/// PRDoc config
21#[derive(Debug, Deserialize)]
22pub struct PRDocConfig {
23	// /// Config version
24	// pub(crate) version: u16,
25	/// Path of the schema
26	pub(crate) schema: PathBuf,
27
28	/// Used for load, scan, check
29	pub prdoc_folders: Vec<PathBuf>,
30
31	/// Used by the generate command
32	pub(crate) output_dir: PathBuf,
33
34	/// Path of the file to use as template
35	pub(crate) template: PathBuf,
36}
37
38/// Wrapper struct for the `PRDocConfig`
39pub struct Config;
40
41impl Config {
42	/// Try finding the PRDOc config in various locations:
43	/// - $PROJECT_ROOT/prdoc.toml
44	/// - $PROJECT_ROOT/.prdoc.toml
45	/// - $PRDOC_CONFIG
46	pub fn get_config_file(config_file: Option<PathBuf>) -> Result<PathBuf> {
47		let root = get_project_root().expect("prdoc should run in a repo");
48
49		if let Some(config) = config_file {
50			if PathBuf::from(&config).exists() {
51				log::debug!("Found config in {config:?}");
52				return Ok(config);
53			}
54		}
55
56		for name in CONFIG_NAMES {
57			let candidate = root.join(name);
58			if candidate.exists() {
59				log::debug!("Found config in {}", candidate.display());
60				return Ok(candidate);
61			}
62		}
63
64		log::warn!("Config not found");
65		Err(crate::error::PRdocLibError::MissingConfig)
66	}
67
68	/// Return a default config. This is used when no config was found or the config file is invalid
69	pub fn get_default_config() -> PRDocConfig {
70		PRDocConfig::default()
71	}
72
73	/// Load the config from the config file
74	pub fn load(config_opts: Option<PathBuf>) -> Result<PRDocConfig> {
75		let config_file = Self::get_config_file(config_opts)?;
76		log::debug!("Loading config from {config_file:?}");
77		let str = match fs::read_to_string(config_file.clone()) {
78			Ok(s) => s,
79			Err(_) => Err(crate::error::PRdocLibError::InvalidConfig(config_file.clone()))?,
80		};
81
82		match toml::from_str(str.as_str()) {
83			Ok(c) => Ok(c),
84			Err(_e) => Err(crate::error::PRdocLibError::InvalidConfig(config_file))?,
85		}
86	}
87}
88
89impl Default for PRDocConfig {
90	fn default() -> Self {
91		Self {
92			// version: 1,
93			schema: "prdoc/schema_user.json".into(),
94			prdoc_folders: vec!["prdoc".into()],
95			output_dir: "prdoc".into(),
96			template: "template.prdoc".into(),
97		}
98	}
99}
100
101impl PRDocConfig {
102	/// Return the path of the schema
103	pub fn schema_path(&self) -> PathBuf {
104		self.schema.clone()
105	}
106}