oseda_cli/cmd/
init.rs

1/*
2npm init -y
3npm install --save-dev vite http-server
4npm install reveal.js serve vite-plugin-singlefile
5touch vite.config.js -> add the plugin, write this by hand
6
7*/
8
9use std::{
10    error::Error,
11    fs::{self},
12    process::Command,
13};
14
15use clap::Args;
16
17use crate::config;
18
19/// Options for the `oseda init` command
20#[derive(Args, Debug)]
21pub struct InitOptions {
22    /// Unused for now
23    #[arg(long, required = false)]
24    presentation_only: bool,
25}
26
27// embed all the static project files into binary
28const PACKAGE_JSON: &str = include_str!("../static/package.json");
29const VITE_CONFIG_JS: &str = include_str!("../static/vite.config.js");
30const INDEX_HTML: &str = include_str!("../static/index.html");
31const MAIN_JS: &str = include_str!("../static/main.js");
32const SLIDES_MD: &str = include_str!("../static/slides.md");
33const CUSTOM_CSS: &str = include_str!("../static/custom.css");
34
35/// Initialize an Oseda project with the provided options
36///
37/// This command will:
38/// - Run `npm init`
39/// - Install required dependencies (Vite, Reveal.js, etc)
40/// - Write config and boilerplate files
41///
42/// # Arguments
43/// * `_opts` - command-line options (this is unused rn, used later I hope)
44///
45/// # Returns
46/// * `Ok(())` if project initialization is suceeded
47/// * `Err` if any step (npm, file write, config generation etc) fails
48pub fn init(_opts: InitOptions) -> Result<(), Box<dyn Error>> {
49    let conf = config::create_conf()?;
50
51    std::fs::create_dir_all(&conf.title)?;
52
53    let output = Command::new("npm")
54        .args(["init", "-y", "--prefix", &conf.title])
55        .current_dir(&conf.title)
56        .output()?;
57
58    // swapped to explicit check so it doesnt hang after
59    if !output.status.success() {
60        eprintln!(
61            "npm init failed: {}",
62            String::from_utf8_lossy(&output.stderr)
63        );
64        return Err("npm init failed".into());
65    }
66
67    let npm_commands = vec![
68        format!("install --save-dev vite http-server"),
69        format!("install reveal.js serve vite-plugin-singlefile"),
70        format!("install vite@5"),
71    ];
72
73    for c in npm_commands {
74        let args: Vec<&str> = c.split(' ').collect();
75        let output = Command::new("npm")
76            .args(&args)
77            .current_dir(&conf.title)
78            .output()?;
79
80        if !output.status.success() {
81            eprintln!(
82                "npm {} failed: {}",
83                c,
84                String::from_utf8_lossy(&output.stderr)
85            );
86            return Err(format!("npm {} failed", c).into());
87        }
88        println!("Bootstrapped npm {}", c);
89
90        println!("Saving config file...");
91
92        config::write_config(&conf.title, &conf)?;
93    }
94
95    fs::write(format!("{}/package.json", &conf.title), PACKAGE_JSON)?;
96    fs::write(format!("{}/vite.config.js", &conf.title), VITE_CONFIG_JS)?;
97    fs::write(format!("{}/index.html", &conf.title), INDEX_HTML)?;
98
99    std::fs::create_dir_all(format!("{}/src", &conf.title))?;
100    fs::write(format!("{}/src/main.js", &conf.title), MAIN_JS)?;
101
102    std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
103    fs::write(format!("{}/slides/slides.md", &conf.title), SLIDES_MD)?;
104
105    std::fs::create_dir_all(format!("{}/css", &conf.title))?;
106    fs::write(format!("{}/css/custom.css", &conf.title), CUSTOM_CSS)?;
107
108    Ok(())
109}