Skip to content

Commit

Permalink
refactor: move gen into a crate - loco-gen
Browse files Browse the repository at this point in the history
  • Loading branch information
jondot committed Oct 21, 2024
1 parent 79d9ee6 commit 935e4cf
Show file tree
Hide file tree
Showing 52 changed files with 184 additions and 85 deletions.
33 changes: 19 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["xtask", "loco-extras"]
members = ["xtask", "loco-extras", "loco-gen"]
exclude = ["starters"]

[workspace.package]
Expand All @@ -26,7 +26,7 @@ default = ["auth_jwt", "cli", "with-db", "cache_inmem", "bg_redis", "bg_pg"]
auth_jwt = ["dep:jsonwebtoken"]
cli = ["dep:clap"]
testing = ["dep:axum-test"]
with-db = ["dep:sea-orm", "dep:sea-orm-migration"]
with-db = ["dep:sea-orm", "dep:sea-orm-migration", "loco-gen/with-db"]
channels = ["dep:socketioxide"]
# Storage features
all_storage = ["storage_aws_s3", "storage_azure", "storage_gcp"]
Expand All @@ -39,6 +39,7 @@ bg_redis = ["dep:rusty-sidekiq", "dep:bb8"]
bg_pg = ["dep:sqlx", "dep:ulid"]

[dependencies]
loco-gen = { path = "./loco-gen" }
backtrace_printer = { version = "1.3.0" }

# cli
Expand All @@ -56,8 +57,8 @@ sea-orm = { version = "1.0.0", features = [
tokio = { version = "1.33.0", default-features = false }
# the rest

serde = "1"
serde_json = "1"
serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = "0.9"
serde_variant = "0.1.2"

Expand All @@ -66,8 +67,8 @@ async-trait = { workspace = true }

axum = { workspace = true }
axum-extra = { version = "0.9", features = ["cookie"] }
regex = "1"
lazy_static = "1.4.0"
regex = { workspace = true }
lazy_static = { workspace = true }
fs-err = "2.11.0"
# mailer
tera = "1.19.1"
Expand All @@ -79,8 +80,8 @@ lettre = { version = "0.11.4", default-features = false, features = [
"tokio1-rustls-tls",
] }
include_dir = "0.7.3"
thiserror = "1"
tracing = "0.1.40"
thiserror = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing-appender = "0.2.3"

Expand All @@ -103,12 +104,7 @@ ipnetwork = "0.20.0"

axum-test = { version = "16.1.0", optional = true }

# gen
rrgen = "0.5.3"
chrono = "0.4.31"
cargo_metadata = "0.18.1"
dialoguer = "0.11.0"

chrono = { workspace = true }
cfg-if = "1"

uuid = { version = "1.10.0", features = ["v4", "fast-rng"] }
Expand Down Expand Up @@ -138,6 +134,14 @@ rusty-sidekiq = { version = "0.11.0", default-features = false, optional = true
bb8 = { version = "0.8.1", optional = true }

[workspace.dependencies]

chrono = "0.4"
tracing = "0.1.40"
regex = "1"
thiserror = "1"
serde = "1"
serde_json = "1"
lazy_static = "1.4.0"
async-trait = { version = "0.1.74" }
axum = { version = "0.7.5", features = ["macros"] }
tower = "0.4"
Expand Down Expand Up @@ -168,6 +172,7 @@ features = [
features = ["testing"]

[dev-dependencies]
cargo_metadata = "0.18.1"
loco-rs = { path = ".", features = ["testing"] }
rstest = "0.21.0"
insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] }
Expand Down
30 changes: 30 additions & 0 deletions loco-gen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "loco-gen"
version = "0.1.0"
description = "Loco generators"
license.workspace = true
edition.workspace = true
rust-version.workspace = true

[features]
with-db = []

[lib]
path = "src/lib.rs"

[dependencies]

lazy_static = { workspace = true }
rrgen = "0.5.3"
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
regex = { workspace = true }
tracing = { workspace = true }
chrono = { workspace = true }

clap = { version = "4.4.7", features = ["derive"] }
tempfile = "3"
syn = "2"
dialoguer = "0.11"
duct = "0.13"
5 changes: 2 additions & 3 deletions src/gen/controller.rs → loco-gen/src/controller.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rrgen::RRgen;
use serde_json::json;

use crate::gen;
use crate as gen;

const API_CONTROLLER_CONTROLLER_T: &str = include_str!("templates/controller/api/controller.t");
const API_CONTROLLER_TEST_T: &str = include_str!("templates/controller/api/test.t");
Expand All @@ -12,8 +12,7 @@ const HTMX_VIEW_T: &str = include_str!("templates/controller/htmx/view.t");
const HTML_CONTROLLER_CONTROLLER_T: &str = include_str!("templates/controller/html/controller.t");
const HTML_VIEW_T: &str = include_str!("templates/controller/html/view.t");

use super::{collect_messages, AppInfo};
use crate::Result;
use super::{collect_messages, AppInfo, Result};

pub fn generate(
rrgen: &RRgen,
Expand Down
81 changes: 47 additions & 34 deletions src/gen/mod.rs → loco-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ mod scaffold;
mod testutil;
use std::str::FromStr;

use crate::{config::Config, errors, Result};

const CONTROLLER_T: &str = include_str!("templates/controller.t");
const CONTROLLER_TEST_T: &str = include_str!("templates/request_test.t");

Expand Down Expand Up @@ -51,6 +49,26 @@ const DEPLOYMENT_OPTIONS: &[(&str, DeploymentKind)] = &[
("Nginx", DeploymentKind::Nginx),
];

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("{0}")]
Message(String),
#[error(transparent)]
RRgen(#[from] rrgen::Error),
#[error(transparent)]
IO(#[from] std::io::Error),
#[error(transparent)]
Any(#[from] Box<dyn std::error::Error + Send + Sync>),
}

impl Error {
pub fn msg(err: impl std::error::Error + Send + Sync + 'static) -> Self {
Self::Message(err.to_string()) //.bt()
}
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Serialize, Deserialize, Debug)]
struct FieldType {
name: String,
Expand Down Expand Up @@ -178,14 +196,24 @@ pub enum Component {
/// Name of the thing to generate
name: String,
},
Deployment {},
Deployment {
fallback_file: Option<String>,
asset_folder: Option<String>,
host: String,
port: i32,
},
}
pub struct AppInfo {
pub app_name: String,
}

/// Generate a component
///
/// # Errors
///
/// This function will return an error if it fails
#[allow(clippy::too_many_lines)]
pub fn generate(component: Component, config: &Config, appinfo: &AppInfo) -> Result<()> {
pub fn generate(component: Component, appinfo: &AppInfo) -> Result<()> {
let rrgen = RRgen::default();
/*
(1)
Expand Down Expand Up @@ -251,36 +279,25 @@ pub fn generate(component: Component, config: &Config, appinfo: &AppInfo) -> Res
rrgen.generate(MAILER_TEXT_T, &vars)?;
rrgen.generate(MAILER_HTML_T, &vars)?;
}
Component::Deployment {} => {
Component::Deployment {
fallback_file,
asset_folder,
host,
port,
} => {
let deployment_kind = match std::env::var("LOCO_DEPLOYMENT_KIND") {
Ok(kind) => kind.parse::<DeploymentKind>().map_err(|_e| {
errors::Error::Message(format!("deployment {kind} not supported"))
})?,
Ok(kind) => kind
.parse::<DeploymentKind>()
.map_err(|_e| Error::Message(format!("deployment {kind} not supported")))?,
Err(_err) => prompt_deployment_selection().map_err(Box::from)?,
};

match deployment_kind {
DeploymentKind::Docker => {
let copy_asset_folder = &config
.server
.middlewares
.static_assets
.clone()
.map(|a| a.folder.path)
.unwrap_or_default();

let fallback_file = &config
.server
.middlewares
.static_assets
.clone()
.map(|a| a.fallback)
.unwrap_or_default();

let vars = json!({
"pkg_name": appinfo.app_name,
"copy_asset_folder": copy_asset_folder,
"fallback_file": fallback_file
"copy_asset_folder": asset_folder.unwrap_or_default(),
"fallback_file": fallback_file.unwrap_or_default()
});
rrgen.generate(DEPLOYMENT_DOCKER_T, &vars)?;
rrgen.generate(DEPLOYMENT_DOCKER_IGNORE_T, &vars)?;
Expand All @@ -295,15 +312,11 @@ pub fn generate(component: Component, config: &Config, appinfo: &AppInfo) -> Res
rrgen.generate(DEPLOYMENT_SHUTTLE_CONFIG_T, &vars)?;
}
DeploymentKind::Nginx => {
let host = &config
.server
.host
.replace("http://", "")
.replace("https://", "");
let host = host.replace("http://", "").replace("https://", "");
let vars = json!({
"pkg_name": appinfo.app_name,
"domain": &host,
"port": &config.server.port
"domain": host,
"port": port
});
rrgen.generate(DEPLOYMENT_NGINX_T, &vars)?;
}
Expand Down Expand Up @@ -335,7 +348,7 @@ fn prompt_deployment_selection() -> Result<DeploymentKind> {
.items(&options)
.default(0)
.interact()
.map_err(errors::Error::msg)?;
.map_err(Error::msg)?;

Ok(DEPLOYMENT_OPTIONS[selection].1.clone())
}
File renamed without changes.
33 changes: 31 additions & 2 deletions src/gen/model.rs → loco-gen/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use duct::cmd;
use rrgen::RRgen;
use serde_json::json;

use crate::{errors::Error, Result};
use super::{Error, Result};

const MODEL_T: &str = include_str!("templates/model.t");
const MODEL_TEST_T: &str = include_str!("templates/model_test.t");
Expand Down Expand Up @@ -93,7 +93,7 @@ pub fn generate(
mod tests {
use std::{env, process::Command};

use crate::gen::{
use crate::{
testutil::{self, assert_cargo_check, assert_file, assert_single_file_match},
AppInfo,
};
Expand Down Expand Up @@ -131,6 +131,35 @@ mod tests {

#[test]
fn test_can_generate_model() {
/*
issues: 1. setting current dir is too aggressive and fails other test that are run in parallel.
- possible solution to forget 'temp' and always generate in actual current dir, making sure to delete before and after
- or isolate these tests and run them with serial
- either way may be to gate under a test_generators feature flag
- or move all these into integration tests, but then need to expose the generators functions
- or add a magic env var, saying where the base app folder is, and have all gen operations start from there
- another solution is to use category_... and aggressively use cargo test filtering from now on
test_ (unit test)
gen_test (generators tests)
integration_(various integration)
- another solution: move gen into loco-gen make it a crate, then its testable in isolation in another ci job
< the only reverse dep is the Error and Result types, which we can take care of >
another insight: we don't need 'gen' when building to production. this is a dev only feature and dev only crate
[ ] refactor into() to be manual and take config, create a proper deployment and nginx params
generate should not know about loco config
[ ] create a thiserror result/error typeset
[ ] with-db feature should be irrelevant to gen, or propogate this feature from master crate
[ ] migrate all errors to gen local things
[ ] map error at the root calling gen to loco crate errors
[ ] refactor all gen namespaces and types into loco_gen
[ ] shuffle / move deps from loco to gen and take care of shared deps
2. running seaorm and migrations is too heavy
3. running cargo check may be too heavy, and requires 'cd' into the dir too
*/
let rrgen = rrgen::RRgen::default();
with_new_app("saas", || {
super::generate(
Expand Down
5 changes: 2 additions & 3 deletions src/gen/scaffold.rs → loco-gen/src/scaffold.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rrgen::RRgen;
use serde_json::json;

use crate::gen;
use crate as gen;

const API_CONTROLLER_SCAFFOLD_T: &str = include_str!("templates/scaffold/api/controller.t");
const API_CONTROLLER_TEST_T: &str = include_str!("templates/scaffold/api/test.t");
Expand All @@ -22,8 +22,7 @@ const HTML_VIEW_CREATE_SCAFFOLD_T: &str = include_str!("templates/scaffold/html/
const HTML_VIEW_SHOW_SCAFFOLD_T: &str = include_str!("templates/scaffold/html/view_show.t");
const HTML_VIEW_LIST_SCAFFOLD_T: &str = include_str!("templates/scaffold/html/view_list.t");

use super::{collect_messages, model, AppInfo, MAPPINGS};
use crate::{errors::Error, Result};
use super::{collect_messages, model, AppInfo, Error, Result, MAPPINGS};

pub fn generate(
rrgen: &RRgen,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 935e4cf

Please sign in to comment.