oseda_cli/
config.rs

1use std::error::Error;
2use std::fs::File;
3use std::io::BufWriter;
4use std::{ffi::OsString, fs};
5
6use chrono::{DateTime, Utc};
7use inquire::validator::Validation;
8use serde::{Deserialize, Serialize};
9use strum::IntoEnumIterator;
10
11use crate::categories::Category;
12use crate::cmd::check::OsedaCheckError;
13use crate::github;
14
15pub fn read_and_validate_config(skip_git: bool) -> Result<OsedaConfig, OsedaCheckError> {
16    let config_str = fs::read_to_string("oseda-config.json").map_err(|_| {
17        OsedaCheckError::MissingConfig(format!(
18            "Could not find config file in {}",
19            std::env::current_dir().unwrap().to_str().unwrap()
20        ))
21    })?;
22
23    let conf: OsedaConfig = serde_json::from_str(&config_str)
24        .map_err(|_| OsedaCheckError::BadConfig("Could not parse oseda config file".to_owned()))?;
25
26    if !skip_git {
27        println!("Running git checks");
28        let gh_name = github::get_config("user.name").ok_or_else(|| {
29            OsedaCheckError::BadGitCredentials(
30                "Could not get git user.name from git config".to_owned(),
31            )
32        })?;
33
34        if gh_name != conf.author {
35            return Err(OsedaCheckError::BadGitCredentials(
36                "Config author does not match git credentials".to_owned(),
37            ));
38        }
39    }
40
41    let path = std::env::current_dir().map_err(|_| {
42        OsedaCheckError::DirectoryNameMismatch("Could not get path of working directory".to_owned())
43    })?;
44
45    let cwd = path.file_name().ok_or_else(|| {
46        OsedaCheckError::DirectoryNameMismatch("Could not resolve path name".to_owned())
47    })?;
48
49    if cwd != OsString::from(conf.title.clone()) {
50        return Err(OsedaCheckError::DirectoryNameMismatch(
51            "Config title does not match directory name".to_owned(),
52        ));
53    }
54
55    Ok(conf)
56}
57
58#[derive(Serialize, Deserialize)]
59pub struct OsedaConfig {
60    pub title: String,
61    pub author: String,
62    pub category: Vec<Category>,
63    // effectively mutable. Will get updated on each deployment
64    pub last_updated: DateTime<Utc>,
65}
66
67pub fn create_conf() -> Result<OsedaConfig, Box<dyn Error>> {
68    // let mut title = String::new();
69    // std::io::stdin().read_line(&mut title)?;
70
71    let validator = |input: &str| {
72        if input.chars().count() < 2 {
73            Ok(Validation::Invalid(
74                ("Title must be longer than two characters").into(),
75            ))
76        } else {
77            Ok(Validation::Valid)
78        }
79    };
80
81    let mut title = inquire::Text::new("Title: ")
82        .with_validator(validator)
83        .prompt()?;
84
85    title = title.replace(" ", "-");
86
87    let categories = get_categories()?;
88
89    let user_name = github::get_config("user.name")
90        .ok_or("Could not get github username. Please ensure you are signed into github")?;
91
92    Ok(OsedaConfig {
93        title: title.trim().to_owned(),
94        author: user_name,
95        category: categories,
96        last_updated: get_time(),
97    })
98}
99
100fn get_categories() -> Result<Vec<Category>, Box<dyn Error>> {
101    let options: Vec<Category> = Category::iter().collect();
102
103    let selected_categories =
104        inquire::MultiSelect::new("Select categories", options.clone()).prompt()?;
105
106    println!("You selected:");
107    for category in selected_categories.iter() {
108        println!("- {:?}", category);
109    }
110
111    Ok(selected_categories)
112}
113
114pub fn update_time(mut conf: OsedaConfig) -> Result<(), Box<dyn Error>> {
115    conf.last_updated = get_time();
116
117    write_config(".", &conf)?;
118    Ok(())
119}
120
121fn get_time() -> DateTime<Utc> {
122    chrono::offset::Utc::now()
123}
124
125pub fn write_config(path: &str, conf: &OsedaConfig) -> Result<(), Box<dyn Error>> {
126    let file = File::create(format!("{}/oseda-config.json", path))?;
127    let writer = BufWriter::new(file);
128
129    serde_json::to_writer_pretty(writer, &conf)?;
130
131    Ok(())
132}