From 8901a7503bd9a2bc9d6002938e2292b366468898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 27 Mar 2024 22:08:23 +0000 Subject: [PATCH 1/2] Generate the Rails application with the same user as the caller Read the user id and group id of the caller and pass them to the Docker so the generate folders are with the same user as the caller. Fixes #4. --- Cargo.lock | 17 +++++++++++++++++ Cargo.toml | 1 + Dockerfile | 4 ++++ Dockerfile.windows | 5 +++++ src/docker_client.rs | 14 ++++++++++++-- src/main.rs | 17 ++++++++++++++--- 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 Dockerfile.windows diff --git a/Cargo.lock b/Cargo.lock index 43e5649..2c675d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,12 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + [[package]] name = "memchr" version = "2.7.1" @@ -246,6 +252,7 @@ dependencies = [ "assert_cmd", "clap", "predicates", + "users", ] [[package]] @@ -326,6 +333,16 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "users" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log", +] + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index ea8ae4f..a85b9af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] clap = { version = "4.5.1", features = ["derive"] } +users = "0.11.0" [dev-dependencies] assert_cmd = "2.0.14" diff --git a/Dockerfile b/Dockerfile index eb09298..773cd8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,9 @@ ARG RUBY_VERSION=3.2.3 FROM ruby:${RUBY_VERSION} +ARG USER_ID=1000 +ARG GROUP_ID=1000 +RUN groupadd -g $GROUP_ID app && useradd -u $USER_ID -g app -m app +USER app ARG RAILS_VERSION # Install Rails based on the version specified but if not specified, install the latest version. RUN if [ -z "$RAILS_VERSION" ] ; then gem install rails ; else gem install rails -v $RAILS_VERSION ; fi diff --git a/Dockerfile.windows b/Dockerfile.windows new file mode 100644 index 0000000..eb09298 --- /dev/null +++ b/Dockerfile.windows @@ -0,0 +1,5 @@ +ARG RUBY_VERSION=3.2.3 +FROM ruby:${RUBY_VERSION} +ARG RAILS_VERSION +# Install Rails based on the version specified but if not specified, install the latest version. +RUN if [ -z "$RAILS_VERSION" ] ; then gem install rails ; else gem install rails -v $RAILS_VERSION ; fi diff --git a/src/docker_client.rs b/src/docker_client.rs index 84188e9..0ed7f6e 100644 --- a/src/docker_client.rs +++ b/src/docker_client.rs @@ -3,7 +3,12 @@ use std::process::{Command, Stdio}; pub struct DockerClient {} impl DockerClient { - pub fn build_image(ruby_version: &str, rails_version: &str) -> Command { + pub fn build_image( + ruby_version: &str, + rails_version: &str, + user_id: Option, + group_id: Option, + ) -> Command { let mut command = Command::new("docker"); command @@ -11,7 +16,12 @@ impl DockerClient { .arg("--build-arg") .arg(format!("RUBY_VERSION={}", ruby_version)) .arg("--build-arg") - .arg(format!("RAILS_VERSION={}", rails_version)) + .arg(format!("RAILS_VERSION={}", rails_version)); + + user_id.map(|id| command.args(["--build-arg", &format!("USER_ID={}", id)])); + group_id.map(|id| command.args(["--build-arg", &format!("GROUP_ID={}", id)])); + + command .arg("-t") .arg(format!("rails-new-{}-{}", ruby_version, rails_version)) .arg("-") diff --git a/src/main.rs b/src/main.rs index 91084e9..5f5a6fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,15 +13,26 @@ use crate::docker_client::DockerClient; fn main() { let cli = Cli::parse(); - // read the content of the DOCKERFILE and store it in a variable - let dockerfile = include_bytes!("../Dockerfile"); + let dockerfile: &[u8]; + let user_id: Option; + let group_id: Option; + + if cfg!(windows) { + user_id = None; + group_id = None; + dockerfile = include_bytes!("../Dockerfile.windows"); + } else { + user_id = Some(users::get_current_uid()); + group_id = Some(users::get_current_gid()); + dockerfile = include_bytes!("../Dockerfile"); + } let ruby_version = cli.ruby_version; let rails_version = cli.rails_version; // Run docker build --build-arg RUBY_VERSION=$RUBY_VERSION --build-arg RAILS_VERSION=$RAILS_VERSION -t rails-new-$RUBY_VERSION-$RAILS_VERSION // passing the content of DOCKERFILE to the command stdin - let mut child = DockerClient::build_image(&ruby_version, &rails_version) + let mut child = DockerClient::build_image(&ruby_version, &rails_version, user_id, group_id) .spawn() .expect("Failed to execute process"); From 2b51f63663b37c82dbd794753c87296ff806cc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 27 Mar 2024 22:38:18 +0000 Subject: [PATCH 2/2] Compile OS specific code in a separate module based on the OS --- Cargo.toml | 1 + src/main.rs | 31 +++++++++++++------------------ src/unix.rs | 11 +++++++++++ src/windows.rs | 11 +++++++++++ 4 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 src/unix.rs create mode 100644 src/windows.rs diff --git a/Cargo.toml b/Cargo.toml index a85b9af..730f630 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] clap = { version = "4.5.1", features = ["derive"] } +[target.'cfg(unix)'.dependencies] users = "0.11.0" [dev-dependencies] diff --git a/src/main.rs b/src/main.rs index 5f5a6fd..e018574 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,35 +10,30 @@ use clap::Parser; use crate::docker_client::DockerClient; +#[cfg_attr(unix, path = "unix.rs")] +#[cfg_attr(windows, path = "windows.rs")] +mod os_specific; + fn main() { let cli = Cli::parse(); - let dockerfile: &[u8]; - let user_id: Option; - let group_id: Option; - - if cfg!(windows) { - user_id = None; - group_id = None; - dockerfile = include_bytes!("../Dockerfile.windows"); - } else { - user_id = Some(users::get_current_uid()); - group_id = Some(users::get_current_gid()); - dockerfile = include_bytes!("../Dockerfile"); - } - let ruby_version = cli.ruby_version; let rails_version = cli.rails_version; // Run docker build --build-arg RUBY_VERSION=$RUBY_VERSION --build-arg RAILS_VERSION=$RAILS_VERSION -t rails-new-$RUBY_VERSION-$RAILS_VERSION // passing the content of DOCKERFILE to the command stdin - let mut child = DockerClient::build_image(&ruby_version, &rails_version, user_id, group_id) - .spawn() - .expect("Failed to execute process"); + let mut child = DockerClient::build_image( + &ruby_version, + &rails_version, + os_specific::get_user_id(), + os_specific::get_group_id(), + ) + .spawn() + .expect("Failed to execute process"); let mut stdin = child.stdin.take().expect("Failed to open stdin"); std::thread::spawn(move || { - stdin.write_all(dockerfile).unwrap(); + stdin.write_all(os_specific::dockerfile_content()).unwrap(); }); let status = child.wait().expect("failed to wait on child"); diff --git a/src/unix.rs b/src/unix.rs new file mode 100644 index 0000000..e24e232 --- /dev/null +++ b/src/unix.rs @@ -0,0 +1,11 @@ +pub fn dockerfile_content() -> &'static [u8] { + include_bytes!("../Dockerfile") +} + +pub fn get_user_id() -> Option { + Some(users::get_current_uid()) +} + +pub fn get_group_id() -> Option { + Some(users::get_current_gid()) +} diff --git a/src/windows.rs b/src/windows.rs new file mode 100644 index 0000000..a9a3c49 --- /dev/null +++ b/src/windows.rs @@ -0,0 +1,11 @@ +pub fn dockerfile_content() -> &'static [u8] { + include_bytes!("../Dockerfile.windows") +} + +pub fn get_user_id() -> Option { + None +} + +pub fn get_group_id() -> Option { + None +}