Skip to content

Commit

Permalink
Merge pull request #1227 from loco-rs/fix-docker-gen
Browse files Browse the repository at this point in the history
Fix generator Docker deployment to support both server-side and client-side rendering.
  • Loading branch information
jondot authored Jan 31, 2025
2 parents 7ca0e99 + 9cd8240 commit 458543d
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 162 deletions.
63 changes: 23 additions & 40 deletions loco-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use std::{
collections::HashMap,
fs,
path::{Path, PathBuf},
str::FromStr,
sync::OnceLock,
};

Expand All @@ -35,12 +34,6 @@ pub struct GenerateResults {
}
const DEPLOYMENT_SHUTTLE_RUNTIME_VERSION: &str = "0.51.0";

const DEPLOYMENT_OPTIONS: &[(&str, DeploymentKind)] = &[
("Docker", DeploymentKind::Docker),
("Shuttle", DeploymentKind::Shuttle),
("Nginx", DeploymentKind::Nginx),
];

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("{0}")]
Expand Down Expand Up @@ -228,23 +221,19 @@ pub enum ScaffoldKind {
Htmx,
}

#[derive(clap::ValueEnum, Debug, Clone)]
#[derive(Debug, Clone)]
pub enum DeploymentKind {
Docker,
Shuttle,
Nginx,
}
impl FromStr for DeploymentKind {
type Err = ();

fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"docker" => Ok(Self::Docker),
"shuttle" => Ok(Self::Shuttle),
"nginx" => Ok(Self::Nginx),
_ => Err(()),
}
}
Docker {
copy_paths: Vec<PathBuf>,
is_client_side_rendering: bool,
},
Shuttle {
runttime_version: Option<String>,
},
Nginx {
host: String,
port: i32,
},
}

#[derive(Debug)]
Expand Down Expand Up @@ -304,12 +293,9 @@ pub enum Component {
},
Deployment {
kind: DeploymentKind,
fallback_file: Option<String>,
asset_folder: Option<String>,
host: String,
port: i32,
},
}

pub struct AppInfo {
pub app_name: String,
}
Expand Down Expand Up @@ -366,31 +352,28 @@ pub fn generate(rrgen: &RRgen, component: Component, appinfo: &AppInfo) -> Resul
let vars = json!({ "name": name });
render_template(rrgen, Path::new("mailer"), &vars)?
}
Component::Deployment {
kind,
fallback_file,
asset_folder,
host,
port,
} => match kind {
DeploymentKind::Docker => {
Component::Deployment { kind } => match kind {
DeploymentKind::Docker {
copy_paths,
is_client_side_rendering,
} => {
let vars = json!({
"pkg_name": appinfo.app_name,
"copy_asset_folder": asset_folder.unwrap_or_default(),
"fallback_file": fallback_file.unwrap_or_default()
"copy_paths": copy_paths,
"is_client_side_rendering": is_client_side_rendering,
});
render_template(rrgen, Path::new("deployment/docker"), &vars)?
}
DeploymentKind::Shuttle => {
DeploymentKind::Shuttle { runttime_version } => {
let vars = json!({
"pkg_name": appinfo.app_name,
"shuttle_runtime_version": DEPLOYMENT_SHUTTLE_RUNTIME_VERSION,
"shuttle_runtime_version": runttime_version.unwrap_or_else( || DEPLOYMENT_SHUTTLE_RUNTIME_VERSION.to_string()),
"with_db": cfg!(feature = "with-db")
});

render_template(rrgen, Path::new("deployment/shuttle"), &vars)?
}
DeploymentKind::Nginx => {
DeploymentKind::Nginx { host, port } => {
let host = host.replace("http://", "").replace("https://", "");
let vars = json!({
"pkg_name": appinfo.app_name,
Expand Down
24 changes: 16 additions & 8 deletions loco-gen/src/templates/deployment/docker/docker.t
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,27 @@ WORKDIR /usr/src/

COPY . .

{% if is_client_side_rendering -%}
RUN apt-get update && apt-get install -y curl ca-certificates

# Install Node.js using the latest available version from NodeSource.
# In production, replace "setup_current.x" with a specific version
# to avoid unexpected breaking changes in future releases.
RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \
apt-get install -y nodejs
RUN cd frontend && npm install && npm run build
{% endif -%}

RUN cargo build --release

FROM debian:bookworm-slim

WORKDIR /usr/app

{% if copy_asset_folder -%}
COPY --from=builder /usr/src/{{copy_asset_folder}} /usr/app/{{copy_asset_folder}}
{% endif -%}
{% if fallback_file -%}
COPY --from=builder /usr/src/{{fallback_file}} /usr/app/{{fallback_file}}
{% endif -%}
COPY --from=builder /usr/src/config /usr/app/config
COPY --from=builder /usr/src/target/release/{{pkg_name}}-cli /usr/app/{{pkg_name}}-cli
{% for path in copy_paths -%}
COPY --from=builder /usr/src/{{path}} {{path}}
{% endfor -%}
COPY --from=builder /usr/src/config config
COPY --from=builder /usr/src/target/release/{{pkg_name}}-cli {{pkg_name}}-cli

ENTRYPOINT ["/usr/app/{{pkg_name}}-cli"]
39 changes: 17 additions & 22 deletions loco-gen/tests/templates/deployment.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use insta::assert_snapshot;
use loco_gen::{collect_messages, generate, AppInfo, Component, DeploymentKind};
use rrgen::RRgen;
use std::fs;
use std::{fs, path::PathBuf};

#[rstest::rstest]
fn can_generate_docker(
#[values(None, Some("404_html".to_string()))] fallback_file: Option<String>,
#[values(None, Some("assets".to_string()))] asset_folder: Option<String>,
#[values(vec![], vec![std::path::PathBuf::from("404.html"), PathBuf::from("asset")])]
copy_paths: Vec<PathBuf>,
#[values(true, false)] is_client_side_rendering: bool,
) {
let mut settings = insta::Settings::clone_current();
settings.set_prepend_module_to_snapshot(false);
settings.set_snapshot_suffix("deployment");
let _guard = settings.bind_to_scope();

let component = Component::Deployment {
kind: DeploymentKind::Docker,
fallback_file: fallback_file.clone(),
asset_folder: asset_folder.clone(),
host: "localhost".to_string(),
port: 8080,
kind: DeploymentKind::Docker {
copy_paths: copy_paths.clone(),
is_client_side_rendering,
},
};

let tree_fs = tree_fs::TreeBuilder::default().drop(true).create().unwrap();
Expand All @@ -33,8 +33,6 @@ fn can_generate_docker(
)
.expect("Generation failed");

// assert_snapshot!("generate_docker_result", collect_messages(&gen_result));

assert_eq!(
collect_messages(&gen_result),
r"* Dockerfile generated successfully.
Expand All @@ -44,8 +42,8 @@ fn can_generate_docker(
assert_snapshot!(
format!(
"generate[docker_file_[{}]_[{}]]",
fallback_file.as_ref().map_or("None", |f| f.as_str()),
asset_folder.as_ref().map_or("None", |a| a.as_str())
copy_paths.len(),
is_client_side_rendering
),
fs::read_to_string(tree_fs.root.join("dockerfile")).expect("dockerfile missing")
);
Expand All @@ -69,11 +67,10 @@ fn can_generate_nginx() {
let _guard = settings.bind_to_scope();

let component = Component::Deployment {
kind: DeploymentKind::Nginx,
fallback_file: None,
asset_folder: None,
host: "localhost".to_string(),
port: 8080,
kind: DeploymentKind::Nginx {
host: "localhost".to_string(),
port: 8080,
},
};

let tree_fs = tree_fs::TreeBuilder::default().drop(true).create().unwrap();
Expand Down Expand Up @@ -108,11 +105,9 @@ fn can_generate_shuttle() {
let _guard = settings.bind_to_scope();

let component = Component::Deployment {
kind: DeploymentKind::Shuttle,
fallback_file: None,
asset_folder: None,
host: "localhost".to_string(),
port: 8080,
kind: DeploymentKind::Shuttle {
runttime_version: Some("0.1.1".to_string()),
},
};

let tree_fs = tree_fs::TreeBuilder::default()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ FROM debian:bookworm-slim

WORKDIR /usr/app

COPY --from=builder /usr/src/config /usr/app/config
COPY --from=builder /usr/src/target/release/tester-cli /usr/app/tester-cli
COPY --from=builder /usr/src/config config
COPY --from=builder /usr/src/target/release/tester-cli tester-cli

ENTRYPOINT ["/usr/app/tester-cli"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
source: loco-gen/tests/templates/deployment.rs
expression: "fs::read_to_string(tree_fs.root.join(\"dockerfile\")).expect(\"dockerfile missing\")"
---
FROM rust:1.83.0-slim as builder

WORKDIR /usr/src/

COPY . .

RUN apt-get update && apt-get install -y curl ca-certificates

# Install Node.js using the latest available version from NodeSource.
# In production, replace "setup_current.x" with a specific version
# to avoid unexpected breaking changes in future releases.
RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \
apt-get install -y nodejs
RUN cd frontend && npm install && npm run build
RUN cargo build --release

FROM debian:bookworm-slim

WORKDIR /usr/app

COPY --from=builder /usr/src/config config
COPY --from=builder /usr/src/target/release/tester-cli tester-cli

ENTRYPOINT ["/usr/app/tester-cli"]
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ FROM debian:bookworm-slim

WORKDIR /usr/app

COPY --from=builder /usr/src/404_html /usr/app/404_html
COPY --from=builder /usr/src/config /usr/app/config
COPY --from=builder /usr/src/target/release/tester-cli /usr/app/tester-cli
COPY --from=builder /usr/src/404.html 404.html
COPY --from=builder /usr/src/asset asset
COPY --from=builder /usr/src/config config
COPY --from=builder /usr/src/target/release/tester-cli tester-cli

ENTRYPOINT ["/usr/app/tester-cli"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
source: loco-gen/tests/templates/deployment.rs
expression: "fs::read_to_string(tree_fs.root.join(\"dockerfile\")).expect(\"dockerfile missing\")"
---
FROM rust:1.83.0-slim as builder

WORKDIR /usr/src/

COPY . .

RUN apt-get update && apt-get install -y curl ca-certificates

# Install Node.js using the latest available version from NodeSource.
# In production, replace "setup_current.x" with a specific version
# to avoid unexpected breaking changes in future releases.
RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \
apt-get install -y nodejs
RUN cd frontend && npm install && npm run build
RUN cargo build --release

FROM debian:bookworm-slim

WORKDIR /usr/app

COPY --from=builder /usr/src/404.html 404.html
COPY --from=builder /usr/src/asset asset
COPY --from=builder /usr/src/config config
COPY --from=builder /usr/src/target/release/tester-cli tester-cli

ENTRYPOINT ["/usr/app/tester-cli"]

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ source: loco-gen/tests/templates/deployment.rs
expression: "fs::read_to_string(tree_fs.root.join(\"Cargo.toml\")).expect(\"cargo.toml not exists\")"
---
[dependencies]
shuttle-axum = "0.51.0"
shuttle-runtime = { version = "0.51.0", default-features = false }
shuttle-shared-db = { version = "0.51.0", features = ["postgres"] }
shuttle-axum = "0.1.1"
shuttle-runtime = { version = "0.1.1", default-features = false }
shuttle-shared-db = { version = "0.1.1", features = ["postgres"] }


[[bin]]
Expand Down
Loading

0 comments on commit 458543d

Please sign in to comment.