1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

mod artifacts;
mod changelog;
mod funding;
mod mdbooks;

use crate::config::components::changelog::{ChangelogConfig, ChangelogLayer};
pub use artifacts::{ArtifactsConfig, ArtifactsLayer, PackageManagersConfig, PackageManagersLayer};
pub use funding::{FundingConfig, FundingLayer};
pub use mdbooks::{MdBookConfig, MdBookLayer};

use super::{ApplyBoolLayerExt, ApplyLayer, BoolOr};

/// Extra components (complete version)
#[derive(Debug, Clone)]
pub struct ComponentConfig {
    /// Whether to enable the changelog page
    ///
    /// In the future this may become more complex, but for now this is it
    pub changelog: Option<ChangelogConfig>,
    /// The config for using mdbook for a "docs" page
    ///
    /// This defaults to Some(Default) and is set to None
    /// if we fail to auto-detect necessary information or if the user
    /// manually disables it.
    pub mdbook: Option<MdBookConfig>,
    /// The config for for the funding page
    ///
    /// This defaults to Some(Default) and is set to None
    /// if we fail to auto-detect necessary information or if the user
    /// manually disables it.
    pub funding: Option<FundingConfig>,
    /// The config for the "install" page and widget
    ///
    /// This defaults to Some(Default) and is set to None
    /// if we fail to auto-detect necessary information or if the user
    /// manually disables it.
    pub artifacts: Option<ArtifactsConfig>,
}
/// Extra components
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ComponentLayer {
    /// Whether to enable the changelog page
    ///
    /// In the future this may become more complex, but for now this is just a bool
    pub changelog: Option<BoolOr<ChangelogLayer>>,
    /// The config for building and embedding an mdbook on your site
    ///
    /// The book will be linked as "docs" in the nav, and restyled to match
    /// the theme you have for the rest of your oranda site. We use a vendored
    /// copy of mdbook, and not the one you have installed on your system.
    ///
    /// This feature is enabled by default if we find a "book.toml" in
    /// "./", "./book/", or "./docs/".
    ///
    /// It can be completely disabled by setting `"mdbook": false`.
    ///  
    /// More precise settings can be used with `"mdbook": { ... }`.
    pub mdbook: Option<BoolOr<MdBookLayer>>,
    /// The config for for the "funding" page
    ///
    /// This feature is enabled by default if we find a file at "funding.md"
    /// or "./.github/FUNDING.yml".
    ///
    /// It can be completely disabled by setting `"funding": false`.
    ///  
    /// More precise settings can be used with `"funding": { ... }`.
    pub funding: Option<BoolOr<FundingLayer>>,
    /// The config for the "install" page and widget
    ///
    /// # Data Sources
    ///
    /// Once enabled we consider data for 3 possible data sources:
    ///
    /// * The `components.artifacts.package_managers` keys (see those configs for details)
    /// * Your GitHub Releases (if we have a URL to a GitHub repo in `project.repository`)
    /// * dist-manifest.json in your GitHub Releases (if cargo-dist support is enabled)
    ///
    /// These sources can give us:
    ///
    /// * Downloadable Files (`my-app-x86_64-pc-windows-msvc.zip`)
    /// * Runnable One-Liners (`curl install.sh | sh`, `npm install ...`)
    ///
    /// Which can be known/assumed to be:
    ///
    /// * Runnable/Installable on specific platforms (don't recommend `install.sh` on windows)
    /// * Preferred over others (install script nicer than downloadable tarballs)
    /// * Have checksums (`my-app-x86_64-pc-windows-msvc.zip.sha256`)
    /// * Be viewable (`install.sh`)
    ///
    /// GitHub Releses support will also get us a list of Releases these will be grouped into
    /// We will try to intelligently pick a "Latest Release" to display up-front:
    ///
    /// * If there's cargo-dist releases, prefer the latest one of those (stable over prereleases)
    ///     * This is a hack to make monorepos behave better while we don't fully support them
    /// * Otherwise if there's a stable release, pick the latest stable release
    /// * Otherwise pick the latest prerelease
    ///
    /// Otherwise we will place all of this under one artifical "current release".
    ///
    ///
    /// ## Github Releases
    ///
    /// GitHub Releases integration is a fuzzy system of auto-detection based on the filenames
    /// of assets we find uploaded to each GitHub Release. If we find a filename contains
    /// something that looks like a target triple ("x86_64-pc-windows-msvc") we will assume
    /// the artifact is only for that platform.
    ///
    /// If we find files with names like "..install..sh" we will assume those are curl-sh
    /// installer scripts.
    ///
    /// If we find a platform-specific tarball/zip, we will assume it's an archive containing
    /// prebuilt binaries for that platform.
    ///
    /// We also experimentally detect things like .deb files but it's only half-baked right now.
    ///
    ///
    /// # The Install Page
    ///
    /// The Install Page will show up in your nav if this feature is at all enabled.
    ///
    /// It will show:
    ///
    /// 1. The Install Widget (see below)
    /// 2. All the Runnable One-Liners for the Latest Release
    /// 3. A table of downloadable artifacts (tarballs/zips) for the Latest Release.
    ///
    ///
    /// # The Install Widget
    ///
    /// The Install Widget will show up on your front page and install page if
    /// this feature is at all enabled. Although currently it will auto-hide
    /// if there's absolutely nothing to show (#305).
    ///
    /// It will autodetect the user's current platform and try to recommend an installation method.
    ///
    /// If there are multiple supported platforms with different installation methods,
    /// a "platform" dropdown will appear to override the auto-detect.
    ///
    /// If there are multiple installation options for a platform, we will present them as tabs,
    /// roughly in decreasing order of preference (first tab is always best).
    ///
    /// Preference is currently fuzzy, but roughly:
    ///
    /// * platform-native solutions like msi's or debs will be recommended first
    /// * installer scripts will be shown after that
    /// * custom package_managers will be shown after that
    /// * tarballs/zips will be shown last
    ///
    /// If no installation methods are found for the user's platform, they will be linked to
    /// the install page and offered the platform dropdown to override.
    ///
    ///
    /// # Enabling / Disabling
    ///
    /// This feature is enabled if:
    ///
    /// * cargo-dist support is enabled
    ///   * `artifacts.cargo_dist: true` is set
    ///   * we find `[workspace.metadata.dist]` in your Cargo.toml
    /// * you set a package_manager in `artifacts.package_managers`
    ///
    /// It can be completely disabled by setting `"artifacts": false`.
    ///  
    /// More precise settings can be used with `"artifacts": { ... }`.
    ///
    /// FIXME(#397): there is currently an expressivity hole here: there is no way to *just*
    /// turn on plain GitHub Releases integration. You either need to have cargo-dist
    /// integration enabled, or add a random package_manager to make us enable it.
    pub artifacts: Option<BoolOr<ArtifactsLayer>>,
}
impl Default for ComponentConfig {
    fn default() -> Self {
        ComponentConfig {
            changelog: Some(ChangelogConfig::default()),
            mdbook: Some(MdBookConfig::default()),
            funding: Some(FundingConfig::default()),
            artifacts: Some(ArtifactsConfig::default()),
        }
    }
}
impl ApplyLayer for ComponentConfig {
    type Layer = ComponentLayer;
    fn apply_layer(&mut self, layer: Self::Layer) {
        // This is intentionally written slightly cumbersome to make you update this
        let ComponentLayer {
            changelog,
            mdbook,
            funding,
            artifacts,
        } = layer;
        self.changelog.apply_bool_layer(changelog);
        self.mdbook.apply_bool_layer(mdbook);
        self.funding.apply_bool_layer(funding);
        self.artifacts.apply_bool_layer(artifacts);
    }
}
impl ComponentConfig {
    /// Convenience for checking if the artifacts component is actually enabled
    /// because a ton of code was repeating this due to the extra Option.
    pub fn artifacts_enabled(&self) -> bool {
        self.artifacts
            .as_ref()
            .map(|a| a.has_some())
            .unwrap_or(false)
    }
}