feat: switched to clap for CLI
							parent
							
								
									7cf0e44b65
								
							
						
					
					
						commit
						3800534a51
					
				|  | @ -1,2 +1,3 @@ | |||
| /target | ||||
| db.sqlite | ||||
| data | ||||
|  |  | |||
|  | @ -68,6 +68,55 @@ dependencies = [ | |||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstream" | ||||
| version = "0.6.18" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" | ||||
| dependencies = [ | ||||
|  "anstyle", | ||||
|  "anstyle-parse", | ||||
|  "anstyle-query", | ||||
|  "anstyle-wincon", | ||||
|  "colorchoice", | ||||
|  "is_terminal_polyfill", | ||||
|  "utf8parse", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle" | ||||
| version = "1.0.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-parse" | ||||
| version = "0.2.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" | ||||
| dependencies = [ | ||||
|  "utf8parse", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-query" | ||||
| version = "1.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" | ||||
| dependencies = [ | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anstyle-wincon" | ||||
| version = "3.0.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" | ||||
| dependencies = [ | ||||
|  "anstyle", | ||||
|  "windows-sys 0.59.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "argon2" | ||||
| version = "0.5.3" | ||||
|  | @ -290,6 +339,7 @@ dependencies = [ | |||
|  "axum", | ||||
|  "axum-extra", | ||||
|  "chrono", | ||||
|  "clap", | ||||
|  "r2d2", | ||||
|  "r2d2_sqlite", | ||||
|  "rand", | ||||
|  | @ -354,6 +404,52 @@ dependencies = [ | |||
|  "phf_codegen", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap" | ||||
| version = "4.5.26" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" | ||||
| dependencies = [ | ||||
|  "clap_builder", | ||||
|  "clap_derive", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_builder" | ||||
| version = "4.5.26" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" | ||||
| dependencies = [ | ||||
|  "anstream", | ||||
|  "anstyle", | ||||
|  "clap_lex", | ||||
|  "strsim", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_derive" | ||||
| version = "4.5.24" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" | ||||
| dependencies = [ | ||||
|  "heck", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_lex" | ||||
| version = "0.7.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "colorchoice" | ||||
| version = "1.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cookie" | ||||
| version = "0.18.1" | ||||
|  | @ -595,6 +691,12 @@ dependencies = [ | |||
|  "hashbrown", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "heck" | ||||
| version = "0.5.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "http" | ||||
| version = "1.2.0" | ||||
|  | @ -730,6 +832,12 @@ dependencies = [ | |||
|  "winapi-util", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "is_terminal_polyfill" | ||||
| version = "1.70.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "itoa" | ||||
| version = "1.0.14" | ||||
|  | @ -836,7 +944,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" | |||
| dependencies = [ | ||||
|  "libc", | ||||
|  "wasi", | ||||
|  "windows-sys", | ||||
|  "windows-sys 0.52.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1333,9 +1441,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "windows-sys", | ||||
|  "windows-sys 0.52.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strsim" | ||||
| version = "0.11.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "subtle" | ||||
| version = "2.6.1" | ||||
|  | @ -1457,7 +1571,7 @@ dependencies = [ | |||
|  "signal-hook-registry", | ||||
|  "socket2", | ||||
|  "tokio-macros", | ||||
|  "windows-sys", | ||||
|  "windows-sys 0.52.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1671,6 +1785,12 @@ version = "1.0.14" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "utf8parse" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "uuid" | ||||
| version = "1.11.0" | ||||
|  | @ -1791,7 +1911,7 @@ version = "0.1.9" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" | ||||
| dependencies = [ | ||||
|  "windows-sys", | ||||
|  "windows-sys 0.52.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -1818,6 +1938,15 @@ dependencies = [ | |||
|  "windows-targets", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-sys" | ||||
| version = "0.59.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" | ||||
| dependencies = [ | ||||
|  "windows-targets", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-targets" | ||||
| version = "0.52.6" | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ argon2 = "0.5.3" | |||
| axum = { version = "0.8.0", features = ["macros"] } | ||||
| axum-extra = { version = "0.10.0", features = ["cookie"] } | ||||
| chrono = { version = "0.4.39", features = ["serde"] } | ||||
| clap = { version = "4.5.26", features = ["derive", "env"] } | ||||
| r2d2 = "0.8.10" | ||||
| r2d2_sqlite = "0.25.0" | ||||
| rand = "0.8.5" | ||||
|  | @ -24,3 +25,6 @@ tokio = { version = "1.42.0", features = ["full"] } | |||
| tower-http = { version = "0.6.2", features = ["compression-br", "compression-gzip", "set-header", "fs"] } | ||||
| tracing = "0.1.41" | ||||
| tracing-subscriber = "0.3.19" | ||||
| 
 | ||||
| [profile.release] | ||||
| strip = true | ||||
|  |  | |||
|  | @ -0,0 +1,57 @@ | |||
| use std::path::PathBuf; | ||||
| 
 | ||||
| use clap::{Args, Parser, Subcommand}; | ||||
| 
 | ||||
| #[derive(Parser)] | ||||
| pub struct Cli { | ||||
|     #[arg(
 | ||||
|         long = "templates", | ||||
|         default_value = "./templates", | ||||
|         value_name = "TEMPLATES_DIR", | ||||
|         env = "TEMPLATES_DIR" | ||||
|     )] | ||||
|     pub templates_dir: PathBuf, | ||||
|     #[arg(
 | ||||
|         long = "static", | ||||
|         default_value = "./static", | ||||
|         value_name = "STATIC_DIR", | ||||
|         env = "STATIC_DIR" | ||||
|     )] | ||||
|     pub static_dir: PathBuf, | ||||
|     #[arg(
 | ||||
|         long = "data", | ||||
|         default_value = "./data", | ||||
|         value_name = "DATA_DIR", | ||||
|         env = "DATA_DIR" | ||||
|     )] | ||||
|     pub data_dir: PathBuf, | ||||
| 
 | ||||
|     #[command(subcommand)] | ||||
|     pub cmd: Subcommands, | ||||
| } | ||||
| 
 | ||||
| #[derive(Subcommand)] | ||||
| pub enum Subcommands { | ||||
|     Serve { domain: String, port: u16 }, | ||||
|     User(UserCmd), | ||||
| } | ||||
| 
 | ||||
| #[derive(Args)] | ||||
| pub struct UserCmd { | ||||
|     #[command(subcommand)] | ||||
|     cmd: UserSubCmd, | ||||
| } | ||||
| 
 | ||||
| #[derive(Subcommand)] | ||||
| pub enum UserSubCmd { | ||||
|     List, | ||||
|     Remove { | ||||
|         username: String, | ||||
|     }, | ||||
|     Add { | ||||
|         username: String, | ||||
|         password: String, | ||||
|         #[arg(long, default_value_t = false)] | ||||
|         admin: bool, | ||||
|     }, | ||||
| } | ||||
|  | @ -1,4 +1,3 @@ | |||
| use argon2::password_hash::rand_core::{OsRng, RngCore}; | ||||
| use rand::Rng; | ||||
| use rusqlite::Row; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										59
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										59
									
								
								src/main.rs
								
								
								
								
							|  | @ -1,8 +1,12 @@ | |||
| mod cli; | ||||
| mod db; | ||||
| mod server; | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| use std::{fs, path::Path, sync::Arc}; | ||||
| 
 | ||||
| use clap::Parser; | ||||
| use cli::UserCmd; | ||||
| use db::DbError; | ||||
| use r2d2_sqlite::SqliteConnectionManager; | ||||
| use tera::Tera; | ||||
| use tower_http::compression::CompressionLayer; | ||||
|  | @ -14,6 +18,7 @@ const MIGRATIONS: [&str; 5] = [ | |||
|     include_str!("migrations/003_events.sql"), | ||||
|     include_str!("migrations/004_auth.sql"), | ||||
| ]; | ||||
| const DB_FILENAME: &str = "db.sqlite3"; | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Context { | ||||
|  | @ -21,31 +26,47 @@ pub struct Context { | |||
|     tera: Arc<Tera>, | ||||
| } | ||||
| 
 | ||||
| fn run_user_cli(data_dir: impl AsRef<Path>, cmd: UserCmd) -> Result<(), DbError> { | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| #[tokio::main] | ||||
| async fn main() { | ||||
|     tracing_subscriber::fmt::init(); | ||||
|     let args = cli::Cli::parse(); | ||||
| 
 | ||||
|     let manager = SqliteConnectionManager::file("db.sqlite"); | ||||
|     let pool = r2d2::Pool::new(manager).unwrap(); | ||||
|     db::run_migrations(&pool, &MIGRATIONS).unwrap(); | ||||
|     match args.cmd { | ||||
|         cli::Subcommands::Serve { domain, port } => { | ||||
|             tracing_subscriber::fmt::init(); | ||||
| 
 | ||||
|     let template_dir = std::env::var("TEMPLATE_DIR").unwrap_or(String::from("./templates")); | ||||
|     let tera = Tera::new(&format!("{template_dir}/**/*")).unwrap(); | ||||
|             if !fs::exists(&args.data_dir).unwrap() { | ||||
|                 fs::create_dir_all(&args.data_dir).unwrap(); | ||||
|             } | ||||
| 
 | ||||
|     let static_dir = std::env::var("STATIC_DIR").unwrap_or(String::from("./static")); | ||||
|             let manager = SqliteConnectionManager::file(args.data_dir.join(DB_FILENAME)); | ||||
|             let pool = r2d2::Pool::new(manager).unwrap(); | ||||
|             db::run_migrations(&pool, &MIGRATIONS).unwrap(); | ||||
| 
 | ||||
|     let ctx = Context { | ||||
|         pool, | ||||
|         tera: Arc::new(tera), | ||||
|     }; | ||||
|     let app = server::app(ctx, &static_dir).layer(CompressionLayer::new().br(true).gzip(true)); | ||||
|             let tera = | ||||
|                 Tera::new(&format!("{}/**/*", args.templates_dir.to_string_lossy())).unwrap(); | ||||
| 
 | ||||
|     let address = "0.0.0.0:8000"; | ||||
|             let ctx = Context { | ||||
|                 pool, | ||||
|                 tera: Arc::new(tera), | ||||
|             }; | ||||
|             let app = server::app(ctx, &args.static_dir) | ||||
|                 .layer(CompressionLayer::new().br(true).gzip(true)); | ||||
| 
 | ||||
|     tracing::info!("Starting server on {address}"); | ||||
|             let address = format!("{}:{}", domain, port); | ||||
| 
 | ||||
|     let listener = tokio::net::TcpListener::bind(address).await.unwrap(); | ||||
|     axum::serve(listener, app.into_make_service()) | ||||
|         .await | ||||
|         .unwrap(); | ||||
|             tracing::info!("Starting server on {address}"); | ||||
| 
 | ||||
|             let listener = tokio::net::TcpListener::bind(address).await.unwrap(); | ||||
|             axum::serve(listener, app.into_make_service()) | ||||
|                 .await | ||||
|                 .unwrap(); | ||||
|         } | ||||
|         cli::Subcommands::User(cmd) => { | ||||
|             run_user_cli(&args.data_dir, cmd).unwrap(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,6 +4,8 @@ mod error; | |||
| mod events; | ||||
| mod plants; | ||||
| 
 | ||||
| use std::path::Path; | ||||
| 
 | ||||
| use axum::{ | ||||
|     extract::State, | ||||
|     http::{header::VARY, HeaderMap, HeaderValue}, | ||||
|  | @ -50,7 +52,7 @@ pub fn render_view( | |||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn app(ctx: crate::Context, static_dir: &str) -> axum::Router { | ||||
| pub fn app(ctx: crate::Context, static_dir: impl AsRef<Path>) -> axum::Router { | ||||
|     let router = Router::new() | ||||
|         .nest("/plants", plants::app()) | ||||
|         .nest("/comments", comments::app()) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue