envfile support

envfile
Ximo Guanter 3 years ago
parent 9184475e68
commit 9fc9de28db

@ -1,12 +1,11 @@
# Dockerfile+ # Dockerfile+
This project provides Dockerfile syntax extensions that have been rejected by the moby project or haven't been addressed in a long time. This project provides useful 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.
- [Getting started](#getting-started) - [Getting started](#getting-started)
- [Features](#features) - [Features](#features)
- [INCLUDE+](#include) - [INCLUDE+](#include)
- [ENVFILE+](#envfile)
- [Roadmap](#roadmap) - [Roadmap](#roadmap)
- [Feedback](#feedback) - [Feedback](#feedback)
@ -27,9 +26,9 @@ That's it!
## Features ## 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: `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" ] 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 ## Roadmap
The next features in line would be: 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) - `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 - `TAG` command
- improvements to .dockerignore, like recursive dockerignore files - improvements to .dockerignore, like recursive dockerignore files

@ -0,0 +1,9 @@
# syntax = edrevo/dockerfile-plus:0.2
FROM alpine
ENVFILE+ dev.env
WORKDIR /
RUN echo "Hello World"

@ -0,0 +1,3 @@
MEAN_STORE_PORT = 4200
MEAN_STORE_SECRET = "dummy_secret"
MEAN_STORE_DATABASE = "dummy_connection"

@ -104,6 +104,7 @@ struct DockerfileOptions {
} }
const INCLUDE_COMMAND: &str = "INCLUDE+"; const INCLUDE_COMMAND: &str = "INCLUDE+";
const ENVFILE_COMMAND: &str = "ENVFILE+";
async fn dockerfile_trap( async fn dockerfile_trap(
mut client: LlbBridgeClient<Channel>, mut client: LlbBridgeClient<Channel>,
@ -114,11 +115,19 @@ async fn dockerfile_trap(
let context_source = Source::local("context"); let context_source = Source::local("context");
let context_layer = solve(&mut client, Terminal::with(context_source.output())).await?; let context_layer = solve(&mut client, Terminal::with(context_source.output())).await?;
for line in dockerfile_contents.lines() { 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) let bytes = read_file(&mut client, &context_layer, file_path.trim_start().to_string(), None)
.await .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))?; .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()); 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 { } else {
result.push(line.to_string()); result.push(line.to_string());
} }

Loading…
Cancel
Save