diff --git a/README.md b/README.md index c167cfd..1baa629 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ # Dockerfile+ -This project provides Dockerfile syntax extensions that have been rejected by the moby project or haven't been addressed in a long time. - -Currently, the project adds an `INCLUDE+` Dockerfile directive that allows you to import the content of another file into your Dockerfile. There are plans to add more features in the near future. +This project provides useful Dockerfile syntax extensions that have been rejected by the moby project or haven't been addressed in a long time. - [Getting started](#getting-started) - [Features](#features) - [INCLUDE+](#include) + - [ENVFILE+](#envfile) - [Roadmap](#roadmap) - [Feedback](#feedback) @@ -27,9 +26,9 @@ That's it! ## Features -### INCLUDE+ +Note: All Dockerfile+ commands will end up with a `+` sign to avoid any potential future collisions with Dockerfile commands. -Right now there is just one extra instruction: `INCLUDE+`. All Dockerfile+ commands will end up with a `+` sign to avoid any potential future collisions with Dockerfile commands. +### INCLUDE+ `INCLUDE+` will import the verbatim contents of another file into your Dockerfile. Here's an example Dockerfile which uses the `INCLUDE+` instruction: @@ -54,11 +53,45 @@ RUN echo "Hello World" ENTRYPOINT [ "mybin" ] ``` +### ENVFILE+ + +docker-compose has had support for envfiles for a while now, but Dockerfile hasn't. The `ENVFILE+` instruction brings that support to Dockerfile! If you `ENVFILE+` a .env file, each line will be treated as an `ENV` definition. Here's an example: + +```Dockerfile +# syntax = edrevo/dockerfile-plus + +FROM alpine + +ENVFILE+ prod.env + +ENTRYPOINT [ "mybin" ] +``` + +If prod.env has the following: + +```env +FOO=Hello +BAR=World +``` + +The resulting Docker image would be equivalent to the one generated by this standard Dockerfile: + +```Dockerfile +# syntax = edrevo/dockerfile-plus + +FROM alpine + +ENV FOO=Hello + +ENV BAR=World + +ENTRYPOINT [ "mybin" ] +``` + ## Roadmap The next features in line would be: -- `ENVFILE+` command, which would read a .env file and import all of those environment variable definitions into the Dockerfile - `RUN+ --no-cache`, which would disable the cache only for a specific RUN step (useful for non-idempotent commands, for example those that clone git repos) - `TAG` command - improvements to .dockerignore, like recursive dockerignore files diff --git a/dockerfile-plus/examples/envfile/Dockerfile b/dockerfile-plus/examples/envfile/Dockerfile new file mode 100644 index 0000000..3e472e0 --- /dev/null +++ b/dockerfile-plus/examples/envfile/Dockerfile @@ -0,0 +1,9 @@ +# syntax = edrevo/dockerfile-plus:0.2 + +FROM alpine + +ENVFILE+ dev.env + +WORKDIR / + +RUN echo "Hello World" diff --git a/dockerfile-plus/examples/envfile/dev.env b/dockerfile-plus/examples/envfile/dev.env new file mode 100644 index 0000000..0e4a193 --- /dev/null +++ b/dockerfile-plus/examples/envfile/dev.env @@ -0,0 +1,3 @@ +MEAN_STORE_PORT = 4200 +MEAN_STORE_SECRET = "dummy_secret" +MEAN_STORE_DATABASE = "dummy_connection" \ No newline at end of file diff --git a/dockerfile-plus/src/main.rs b/dockerfile-plus/src/main.rs index 1d2d24d..6da22de 100644 --- a/dockerfile-plus/src/main.rs +++ b/dockerfile-plus/src/main.rs @@ -104,6 +104,7 @@ struct DockerfileOptions { } const INCLUDE_COMMAND: &str = "INCLUDE+"; +const ENVFILE_COMMAND: &str = "ENVFILE+"; async fn dockerfile_trap( mut client: LlbBridgeClient, @@ -114,11 +115,19 @@ async fn dockerfile_trap( let context_source = Source::local("context"); let context_layer = solve(&mut client, Terminal::with(context_source.output())).await?; for line in dockerfile_contents.lines() { - if let Some(file_path) = line.trim().strip_prefix(INCLUDE_COMMAND) { + let trimmed_line = line.trim(); + if let Some(file_path) = trimmed_line.strip_prefix(INCLUDE_COMMAND) { let bytes = read_file(&mut client, &context_layer, file_path.trim_start().to_string(), None) .await .with_context(|| format!("Could not read file \"{}\". Remember that the file path is relative to the build context, not the Dockerfile path.", file_path))?; result.push(std::str::from_utf8(&bytes)?.to_string()); + } else if let Some(file_path) = trimmed_line.strip_prefix(ENVFILE_COMMAND) { + let bytes = read_file(&mut client, &context_layer, file_path.trim_start().to_string(), None) + .await + .with_context(|| format!("Could not read file \"{}\". Remember that the file path is relative to the build context, not the Dockerfile path.", file_path))?; + for env_line in std::str::from_utf8(&bytes)?.lines() { + result.push(format!("ENV {}", env_line)); + } } else { result.push(line.to_string()); }