abbaye/config.rs
1use std::path::PathBuf;
2
3use figment::{
4 Figment,
5 providers::{Format, Toml},
6};
7use miette::{IntoDiagnostic, Result};
8use serde::{Deserialize, Serialize};
9
10use schemars::JsonSchema;
11
12use crate::{
13 builders::BuilderEntry, changelog::ChangelogConfig, version_extractors::AnyVersionExtractor,
14};
15
16/// The output format for generated pages.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
18#[serde(rename_all = "lowercase")]
19pub enum OutputFormat {
20 Html,
21 Gemtext,
22}
23
24impl OutputFormat {
25 /// File extension for this format (e.g. `"html"` or `"gmi"`).
26 pub fn extension(&self) -> &'static str {
27 match self {
28 Self::Html => "html",
29 Self::Gemtext => "gmi",
30 }
31 }
32
33 /// Whether this format supports inline formatting (HTML does, gemtext doesn't).
34 pub fn supports_inline_formatting(&self) -> bool {
35 match self {
36 Self::Html => true,
37 Self::Gemtext => false,
38 }
39 }
40}
41
42fn default_formats() -> Vec<OutputFormat> {
43 vec![OutputFormat::Html]
44}
45
46/// General website metadata.
47#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)]
48pub struct SiteConfig {
49 /// Display name of the project, used in page titles and headings.
50 pub name: String,
51 /// Where to output generated files. Defaults to `public`.
52 #[serde(default = "abbaye_output_dir")]
53 pub output_dir: PathBuf,
54 /// Path to the README file rendered on each version page.
55 /// Defaults to `README.md` in the current working directory.
56 pub readme: Option<PathBuf>,
57 /// Canonical base URL of the published site (e.g. `"https://example.com"`).
58 /// When set, the generated `releases.atom` feed will include absolute links
59 /// and proper entry IDs. Trailing slashes are stripped automatically.
60 pub base_url: Option<String>,
61 /// URL of the project's repository (e.g. `"https://git.sr.ht/~ololduck/abbaye"`).
62 /// When set, we will show the repository link in the generated website.
63 pub repo_url: Option<String>,
64 /// An optional language code for the website (e.g. `"en"` or `"fr"`).
65 /// When set, the generated HTML will include a `lang` attribute on the `<html>` tag. Defaults to `"en"`.
66 pub lang: Option<String>,
67 /// If you have a Fediverse account, you can set this to your username to enable Fediverse integration. (don't forget the starting '@' !)
68 pub fediverse_creator: Option<String>,
69 /// OpenGraph configuration for the website.
70 pub opengraph: Option<OpenGraphConfig>,
71 /// Output formats to generate. Defaults to `["html"]`.
72 /// Set to `["html", "gemtext"]` to also generate Gemini text pages.
73 #[serde(default = "default_formats")]
74 pub formats: Vec<OutputFormat>,
75}
76
77/// OpenGraph configuration for the website.
78#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
79pub struct OpenGraphConfig {
80 /// OpenGraph type of the website. It will be used as the `og:type` meta tag.
81 /// Note: by default, the value "website" will be enforced for the version listing page and "article" for the release notes page.
82 pub r#type: Option<String>,
83 /// URL of the website's image.
84 pub image: String,
85 /// Alt text for the website's image.
86 pub image_alt_text: Option<String>,
87 /// URL of the website. If not set, the `base_url` will be used instead. If `base_url` is not set either, the world explodes. Think of the kittens.
88 pub url: Option<String>,
89 /// Author of the website. Used on release notes pages to indicate the author.
90 pub author: Option<String>,
91}
92
93/// Configuration for the git repository web UI.
94#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
95pub struct GitUiConfig {
96 #[serde(default = "default_branch")]
97 pub default_branch: String,
98 /// Maximum number of commits to show in the log page. Defaults to 200.
99 #[serde(default = "default_max_commits")]
100 pub max_commits: usize,
101 /// Path to the git repository to read. Defaults to `.` (the current directory).
102 pub repo_path: Option<PathBuf>,
103 /// Explicit clone URL displayed in the UI (e.g. `"https://example.com/repository.git"`).
104 /// When absent, derived from `site.base_url` by appending `/repository.git`.
105 pub clone_url: Option<String>,
106 /// Glob patterns matched against a ref's short name (e.g. `"main"`,
107 /// `"feature/*"`, `"v1.0.0"`), using [`globset`](https://docs.rs/globset)
108 /// syntax. Any branch or tag matching one of these patterns is left out
109 /// of the generated UI. Defaults to empty (nothing excluded).
110 #[serde(default)]
111 pub exclude: Vec<String>,
112 /// Glob patterns (same syntax as `exclude`). When non-empty, acts as an
113 /// allowlist: only refs matching at least one `include` pattern are
114 /// considered at all (and are then still subject to `exclude`). When
115 /// empty (the default), every ref is a candidate.
116 #[serde(default)]
117 pub include: Vec<String>,
118 /// Directory prefix for git UI pages relative to the site output root.
119 /// Defaults to `""` (pages generated directly at the site root).
120 /// Set to `"repository"` for the legacy layout.
121 #[serde(default)]
122 pub prefix: String,
123}
124
125fn default_branch() -> String {
126 "main".to_string()
127}
128
129fn default_max_commits() -> usize {
130 200
131}
132
133/// A full configuration for the Abbaye site generator.
134///
135/// Here's a sample configuration that works well as a starting point for rust projects:
136///
137/// ```toml
138/// [site]
139/// name = "Abbaye"
140///
141/// [version_extractor]
142/// type = "cargo" # extract version from Cargo.toml
143///
144/// [changelog]
145/// # let's use the default changelog extractor
146///
147/// [[builders]]
148/// type = "cargo" # calls `cargo build --release` for each target
149/// targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"]
150/// [[builders]]
151/// type = "cargo_doc" # generates documentation using `cargo doc`
152/// no_deps = true
153///
154/// [[builders]]
155/// type = "archive" # creates a compressed tarball of the source code
156/// ```
157///
158/// You can learn more about each builder type in the [builders module documentation](crate::builders).
159///
160#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
161pub struct AbbayeConfig {
162 /// Metadata about the site.
163 pub site: SiteConfig,
164 /// which version extractor to use to extract the version(s) of the project
165 pub version_extractor: AnyVersionExtractor,
166 /// Configuration for the changelog extractor.
167 pub changelog: ChangelogConfig,
168 /// Builders to run during the build process.
169 pub builders: Vec<BuilderEntry>,
170 /// Optional git repository web UI. When present, abbaye generates browsable HTML
171 /// pages at `<output>/repository/` and a clonable bare repository at
172 /// `<output>/repository.git/`.
173 #[serde(default)]
174 pub git_ui: Option<GitUiConfig>,
175}
176
177fn abbaye_output_dir() -> PathBuf {
178 PathBuf::from("public")
179}
180
181/// Load the Abbaye2 configuration from the current working directory.
182///
183/// Looks for `.abbaye.toml` first, then `abbaye.toml`; when both are present
184/// `abbaye.toml` takes precedence (last merge wins).
185pub fn load_config() -> Result<AbbayeConfig> {
186 let cwd = std::env::current_dir().into_diagnostic()?;
187 Figment::new()
188 .merge(Toml::file(cwd.join(".abbaye.toml")))
189 .merge(Toml::file(cwd.join("abbaye.toml")))
190 .merge(Toml::file(cwd.join(".abbaye").join("abbaye.toml")))
191 .extract()
192 .into_diagnostic()
193}