aboutsummaryrefslogtreecommitdiff
path: root/src/bin/tosin-admin.rs
blob: e519d500374870d0935f434ba56ec2e722475e42 (plain)
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
use std::env::set_current_dir;
use std::fs;
use std::io::Write as _;
use std::path::Path;
use std::process::Command;

use structopt::StructOpt;

const TOSIN_DEPENDENCY: &str = concat!(r#"tosin = { path = ""#, env!("CARGO_MANIFEST_DIR"), r#"" }"#);
const PROJECT_MAIN: &str = r#"
use tosin::Settings;
use tosin::contrib::admin;
use tosin::db::backend::Connectable;
use tosin::urls::{UrlMap, url_map};

fn urls() -> UrlMap {
    url_map! {
        "admin" / ..admin::site::urls(),
    }
}

fn settings() -> Settings<impl Connectable> {
    Settings {
        ..Settings::default()
    }
}

tosin::main!(urls(), settings());
"#;

const APP_MOD: &str = r#"
pub mod urls;
pub mod views;

pub use urls::urls;
"#;
const APP_URLS: &str = r#"
use tosin::urls::{UrlMap, url_map};

use super::views;

pub fn urls() -> UrlMap {
    todo!("fill in URL map")
}
"#;
const APP_VIEWS: &str = r#"
use tosin::http::{Reply, Response};

todo!("write some views");
"#;

#[derive(StructOpt, Debug)]
enum Opt {
    /// Start a new project/site (can contain multiple apps)
    StartProject {
        name: Option<String>,
    },

    /// Start a new app
    StartApp {
        name: String,
    }
}

fn main() {
    let opts = Opt::from_args();
    match opts {
        Opt::StartProject { name } => {
            match name {
                Some(name) => {
                    // there's a name, so we're creating a project.
                    // TODO make this all more robust
                    let cargo_new = Command::new("cargo")
                        .args(&["new", "--bin", &name])
                        .status()
                        .unwrap();
                    if !cargo_new.success() {
                        panic!("cargo new failed");
                    }

                    set_current_dir(name).unwrap();

                    let mut cargo_toml = fs::OpenOptions::new()
                        .append(true)
                        .open("Cargo.toml")
                        .unwrap();
                    writeln!(cargo_toml, "{}", TOSIN_DEPENDENCY).unwrap();
                    drop(cargo_toml);

                    fs::write("src/main.rs", PROJECT_MAIN).unwrap();
                }
                None => {
                    todo!("absorb existing Rust project maybe??")
                }
            }
        }
        Opt::StartApp { name } => {
            // TODO make this more robust
            if fs::metadata("Cargo.toml").is_ok() {
                let app_folder = Path::new("src").join(name);
                fs::create_dir(&app_folder).unwrap();
                fs::write(app_folder.join("mod.rs"), APP_MOD).unwrap();
                fs::write(app_folder.join("urls.rs"), APP_URLS).unwrap();
                fs::write(app_folder.join("views.rs"), APP_VIEWS).unwrap();
            } else {
                todo!("new standalone app crate maybe??")
            }
        }
    }
}