flatlake/
options.rs

1use anyhow::{bail, Result};
2use clap::{arg, command, value_parser, ArgAction, ArgMatches, Command};
3use schematic::{derive_enum, Config, ConfigEnum};
4use serde::{Deserialize, Serialize};
5use std::{env, path::PathBuf};
6
7use crate::logging::{LogLevel, Logger};
8
9derive_enum!(
10    #[derive(ConfigEnum, Default, Copy)]
11    pub enum SortDirection {
12        #[default]
13        Asc,
14        Desc,
15    }
16);
17
18#[derive(ConfigEnum, Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
19#[serde(rename_all = "snake_case")]
20pub enum OutputElement {
21    Data,
22    FlatData,
23    Content,
24    ContentAst,
25}
26
27#[derive(ConfigEnum, Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
28#[serde(rename_all = "snake_case")]
29pub enum OutputMethod {
30    Single,
31    List,
32    Aggregate,
33}
34
35pub fn get_cli_matches() -> ArgMatches {
36    command!()
37        .arg(
38            arg!(
39                -s --source <DIR> "The location of your source files"
40            )
41            .required(false)
42            .value_parser(value_parser!(PathBuf)),
43        )
44        .arg(
45            arg!(
46                -d --dest <DIR> "The location Flatlake should write your output files. Defaults to `api`"
47            )
48            .required(false)
49            .value_parser(value_parser!(PathBuf)),
50        )
51        .arg(
52            arg!(
53                -v --verbose ... "Print verbose logging while generating files. Does not affect the contents of the output files"
54            )
55            .action(clap::ArgAction::SetTrue),
56        )
57        .arg(
58            arg!(
59                --logfile <DIR> "Path to a logfile to write to. Will replace the file on each run"
60            )
61            .required(false)
62            .value_parser(value_parser!(PathBuf)),
63        )
64        .get_matches()
65}
66
67#[derive(Config, Debug, Clone)]
68#[config(rename_all = "snake_case")]
69pub struct LakeParameters {
70    /// The location of your input files
71    #[setting(env = "FLATLAKE_SOURCE")]
72    pub source: PathBuf,
73
74    /// Where to output the built API
75    #[setting(default = "api", env = "FLATLAKE_DEST")]
76    pub dest: PathBuf,
77
78    /// Print verbose logging while building. Does not impact the output files.
79    #[setting(env = "FLATLAKE_VERBOSE")]
80    pub verbose: bool,
81
82    ///Path to a logfile to write to. Will replace the file on each run
83    #[setting(env = "FLATLAKE_LOGFILE")]
84    pub logfile: Option<PathBuf>,
85
86    #[setting(nested)]
87    pub collections: Vec<LakeCollection>,
88
89    #[setting(nested)]
90    pub global: GlobalLakeSettings,
91}
92
93#[derive(Config, Debug, Clone)]
94#[config(rename_all = "snake_case")]
95pub struct LakeCollection {
96    pub output_key: String,
97    #[setting(nested)]
98    pub inputs: Vec<LakeCollectionInput>,
99    #[setting(default = vec![OutputElement::Data, OutputElement::Content])]
100    pub single_elements: Vec<OutputElement>,
101    #[setting(default = vec![OutputElement::Data])]
102    pub list_elements: Vec<OutputElement>,
103    pub outputs: Option<Vec<OutputMethod>>,
104    pub sort_key: Option<String>,
105    pub sort_direction: Option<SortDirection>,
106    pub page_size: Option<usize>,
107}
108
109#[derive(Config, Debug, Clone)]
110#[config(rename_all = "snake_case")]
111pub struct LakeCollectionInput {
112    pub path: String,
113    #[setting(default = "**/*.{md}")]
114    pub glob: String,
115    pub sub_key: Option<String>,
116    pub merge_data: Option<serde_json::Map<String, serde_json::Value>>,
117}
118
119#[derive(Config, Debug, Clone)]
120#[config(rename_all = "snake_case")]
121pub struct GlobalLakeSettings {
122    #[setting(default = "date")]
123    pub sort_key: String,
124    #[setting(default = "asc")]
125    pub sort_direction: SortDirection,
126    #[setting(default = 100)]
127    pub page_size: usize,
128    #[setting(default = vec![OutputMethod::Single, OutputMethod::List, OutputMethod::Aggregate])]
129    pub outputs: Vec<OutputMethod>,
130}
131
132// The configuration object used internally
133#[derive(Debug, Clone)]
134pub struct LakeContext {
135    pub version: &'static str,
136    pub logger: Logger,
137    pub working_directory: PathBuf,
138    pub params: LakeParameters,
139}
140
141impl LakeContext {
142    pub fn load(mut config: LakeParameters) -> Result<Self> {
143        let log_level = if config.verbose {
144            LogLevel::Verbose
145        } else {
146            LogLevel::Standard
147        };
148
149        let working_directory = env::current_dir().unwrap();
150
151        config.source = working_directory.join(PathBuf::from(config.source.clone()));
152        config.dest = working_directory.join(PathBuf::from(config.dest.clone()));
153
154        Ok(Self {
155            working_directory,
156            version: env!("CARGO_PKG_VERSION"),
157            logger: Logger::new(log_level, true, config.logfile.clone().map(PathBuf::from)),
158            params: config,
159        })
160    }
161}
162
163impl LakeParameters {
164    pub fn override_from_cli(&mut self, cli_matches: ArgMatches) {
165        if cli_matches.get_flag("verbose") {
166            self.verbose = true;
167        }
168
169        if let Some(source) = cli_matches.get_one::<PathBuf>("source") {
170            self.source = source.clone();
171        }
172
173        if let Some(dest) = cli_matches.get_one::<PathBuf>("dest") {
174            self.dest = dest.clone();
175        }
176
177        if let Some(logfile) = cli_matches.get_one::<PathBuf>("logfile") {
178            self.logfile = Some(logfile.clone());
179        }
180    }
181}