Skip to content

Commit

Permalink
Deploy CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
levkk committed Nov 9, 2024
1 parent e7c7e1e commit 4af81b7
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 7 deletions.
30 changes: 28 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion rwf-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rwf-cli"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
license = "MIT"
description = "Rust Web Framework CLI"
Expand All @@ -14,3 +14,7 @@ tokio = { version = "1", features = ["full"] }
log = "0.4"
time = "0.3"
regex = "1"
toml = "0.8"
flate2 = "*"
tar = "0.4"
serde_json = "1"
71 changes: 71 additions & 0 deletions rwf-cli/src/deploy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::fs::File;
use std::path::Path;
use std::path::PathBuf;

use flate2::write::GzEncoder;
use flate2::Compression;
use rwf::config::ConfigFile;
use tokio::process::Command;

use crate::logging::*;
use crate::util::*;

pub async fn build() -> Result<bool, Box<dyn std::error::Error + 'static>> {
let build = Command::new("cargo")
.arg("build")
.arg("--release")
.status()
.await?;

if !build.success() {
error("couldn't build the application, check build logs for error");
return Ok(false);
}

Ok(true)
}

pub async fn package(config: Option<PathBuf>) -> Result<(), Box<dyn std::error::Error + 'static>> {
if !build().await? {
return Ok(());
}

let archive = File::create("build.tar.gz")?;
let enc = GzEncoder::new(archive, Compression::default());
let mut tar = tar::Builder::new(enc);

let info = package_info().await?;
let executable = Path::new(&info.target_dir).join("release").join(&info.name);

packaging("binary");
tar.append_file(&info.name, &mut File::open(executable).expect("binary"))
.expect("binary");

for path in ["static", "templates"] {
let p = Path::new(path);

if p.is_dir() {
packaging(path);
tar.append_dir_all(path, p)?;
}
}

if let Some(config) = config {
if config.is_file() {
if let Err(_) = ConfigFile::load(&config) {
warning(format!(
"{} doesn't seem to be be valid Rwf config file, but we'll use it anyway",
config.display()
));
}
packaging(config.display());
tar.append_file("rwf.toml", &mut File::open(config)?)?;
} else {
warning(format!("{} does not exist, skipping", config.display()));
}
}

created("build.tar.gz");

Ok(())
}
8 changes: 8 additions & 0 deletions rwf-cli/src/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ pub fn error(something: impl ToString) {
eprintln!("{}: {}", "error".red(), something.to_string());
}

pub fn warning(something: impl ToString) {
eprintln!("{}: {}", "warning".yellow(), something.to_string());
}

pub fn removed(something: impl ToString) {
eprintln!("{} {}", "removed".red(), something.to_string());
}

pub fn packaging(something: impl ToString) {
eprintln!("{} {}", "packaging".green(), something.to_string());
}
29 changes: 27 additions & 2 deletions rwf-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use clap::{Args, Parser, Subcommand};
use rwf::logging::Logger;
use rwf::model::Pool;

use std::path::Path;
use std::path::{Path, PathBuf};

mod add;
mod deploy;
mod logging;
mod migrate;
mod remove;
Expand All @@ -30,6 +31,9 @@ enum Subcommands {

/// Remove a controller/view/model/all of the above
Remove(RemoveSubcommand),

/// Build and deploy the application.
Deploy(DeploySubcommand),
}

#[derive(Args, Debug)]
Expand Down Expand Up @@ -107,7 +111,22 @@ enum Remove {
},
}

#[tokio::main]
#[derive(Args, Debug)]
struct DeploySubcommand {
#[command(subcommand)]
command: Deploy,
}

#[derive(Subcommand, Debug)]
enum Deploy {
/// Package the application for deployment.
Package {
#[arg(long, short, help = "Rwf production configuration file")]
config: Option<PathBuf>,
},
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
// std::env::set_var("RWF_LOG_QUERIES", "1");
Logger::init();
Expand Down Expand Up @@ -154,6 +173,12 @@ async fn main() {
remove::controller(&name).await.unwrap();
}
},

Subcommands::Deploy(deploy) => match deploy.command {
Deploy::Package { config } => {
deploy::package(config).await.unwrap();
}
},
}
}

Expand Down
8 changes: 7 additions & 1 deletion rwf-cli/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ use crate::logging::created;
use rwf::colors::MaybeColorize;

pub async fn setup() {
for dir in ["migrations", "templates", "src/controllers", "src/models"] {
for dir in [
"migrations",
"templates",
"src/controllers",
"src/models",
"static",
] {
let path = Path::new(dir);

if !path.exists() {
Expand Down
42 changes: 42 additions & 0 deletions rwf-cli/src/util.rs
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
use tokio::fs::read_to_string;
use tokio::process::Command;
use toml::Value;

#[derive(Debug, Clone)]
pub struct PackageInfo {
pub name: String,
pub version: String,
pub target_dir: String,
}

async fn cargo_toml() -> Result<Value, Box<dyn std::error::Error + 'static>> {
let cargo_toml = read_to_string("Cargo.toml").await?;
let toml: Value = toml::from_str(&cargo_toml)?;

Ok(toml)
}

pub async fn package_info() -> Result<PackageInfo, Box<dyn std::error::Error + 'static>> {
let toml = cargo_toml().await?;

let name = toml
.get("package")
.expect("Cargo.toml to have a valid [package] attribute")
.get("name")
.expect("Cargo.toml to have a valid \"name\" field");

let version = toml
.get("package")
.expect("Cargo.toml to have a valid [package] attribute")
.get("version")
.expect("Cargo.toml to have a valid \"name\" field");

let metadata = Command::new("cargo").arg("metadata").output().await?.stdout;
let json: serde_json::Value = serde_json::from_slice(&metadata)?;
let target_dir = json["target_directory"].as_str().unwrap().to_string();

Ok(PackageInfo {
name: name.as_str().unwrap().to_string(),
version: version.as_str().unwrap().to_string(),
target_dir,
})
}
2 changes: 1 addition & 1 deletion rwf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rwf"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
license = "MIT"
description = "Framework for building web applications in the Rust programming language"
Expand Down
15 changes: 15 additions & 0 deletions rwf/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub trait MaybeColorize {
fn green(&self) -> String;
fn red(&self) -> String;
fn purple(&self) -> String;
fn yellow(&self) -> String;
}

impl MaybeColorize for &str {
Expand Down Expand Up @@ -37,6 +38,16 @@ impl MaybeColorize for &str {
self.to_string()
}
}

fn yellow(&self) -> String {
let config = get_config();

if config.general.tty {
Colorize::yellow(*self).to_string()
} else {
self.to_string()
}
}
}

impl MaybeColorize for String {
Expand All @@ -51,6 +62,10 @@ impl MaybeColorize for String {
fn purple(&self) -> String {
MaybeColorize::purple(&self.as_str())
}

fn yellow(&self) -> String {
MaybeColorize::yellow(&self.as_str())
}
}

#[cfg(test)]
Expand Down
26 changes: 26 additions & 0 deletions rwf/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ impl Default for General {
}
}

fn true_from_env(name: &str) -> bool {
if let Ok(var) = var(name) {
["1", "true"].contains(&var.as_str())
} else {
false
}
}

impl General {
pub fn secret_key(&self) -> Result<Vec<u8>, Error> {
use base64::{engine::general_purpose, Engine as _};
Expand All @@ -176,10 +184,18 @@ impl General {
}

fn default_log_queries() -> bool {
if true_from_env("RWF_LOG_QUERIES") {
return true;
}

false
}

fn default_secret_key() -> String {
if let Ok(key) = var("RWF_SECRET_KEY") {
return key;
}

use base64::{engine::general_purpose, Engine as _};
use rand::Rng;

Expand All @@ -189,17 +205,27 @@ impl General {
}

fn default_cache_templates() -> bool {
if true_from_env("RWF_CACHE_TEMPLATES") {
return true;
}

#[cfg(debug_assertions)]
return false;
#[cfg(not(debug_assertions))]
return true;
}

fn default_track_requests() -> bool {
if true_from_env("RWF_TRACK_REQUESTS") {
return true;
}
false
}

fn default_csrf_protection() -> bool {
if true_from_env("RWF_CSRF_PROTECTION") {
return true;
}
true
}

Expand Down
1 change: 1 addition & 0 deletions rwf/src/hmr.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unused_imports)]
use std::path::PathBuf;
use std::time::Duration;

Expand Down

0 comments on commit 4af81b7

Please sign in to comment.