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
|
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#"', features = ["sqlite"] }
diesel = "1.4.4""#
);
const PROJECT_MAIN: &str = r#"
#[macro_use]
extern crate diesel;
use tosin::contrib::admin;
use tosin::urls::{url_map, UrlMap};
use tosin::Settings;
fn urls() -> UrlMap {
url_map! {
"admin" / ..admin::site::urls(),
}
}
fn settings() -> Settings {
Settings {
..Settings::default()
}
}
tosin::main!(urls(), settings());
"#;
const APP_MOD: &str = r#"
use tosin::apps::AppConfig;
mod migrations;
pub mod models;
pub mod urls;
pub mod views;
pub use urls::urls;
#[allow(dead_code)]
pub const APP: AppConfig = AppConfig {
name: module_path!(),
models: models::ALL,
migrations: migrations::ALL,
};
"#;
const APP_MIGRATIONS: &str = r#"
use tosin::db::migration::{gather, Migration};
gather!();
"#;
const APP_MODELS: &str = r#"
#[allow(unused_imports)]
use tosin::db::models::{gather, Id, Model};
// TODO define models
gather!();
"#;
const APP_URLS: &str = r#"
use tosin::urls::{url_map, UrlMap};
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::create_dir_all(app_folder.join("migrations")).unwrap();
fs::write(app_folder.join("migrations/mod.rs"), APP_MIGRATIONS).unwrap();
fs::write(app_folder.join("models.rs"), APP_MODELS).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??")
}
}
}
}
|