feat: Look for recipes in ./recipes/, build files in ./files/, and Containerfiles in ./containerfiles/ (#157)
Recipe files can now be put into their own directory `./recipes/`. This directory is NEVER copied into the build so changes to a recipe will no longer cause cache misses for builds. Here is an example of my build changing the second to last module and only requiring the last 2 `RUN` layers to be run again. ``` => CACHED [stage-config 1/1] COPY ./config /config 0.0s => CACHED [stage-modules 1/2] COPY --from=ghcr.io/blue-build/modules:latest /modules /modules 0.0s => CACHED [stage-modules 2/2] COPY ./modules /modules 0.0s => CACHED [stage-keys 1/1] COPY cosign.pub /keys/jp-desktop-gaming.pub 0.0s => CACHED [stage-4 2/16] RUN --mount=type=bind,from=stage-keys,src=/keys,dst=/tmp/keys mkdir -p /usr/etc/pki/containers/ && cp /tmp/keys/* /usr/et 0.0s => CACHED [stage-bins 1/3] COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /bins/cosign 0.0s => CACHED [stage-bins 2/3] COPY --from=docker.io/mikefarah/yq /usr/bin/yq /bins/yq 0.0s => CACHED [stage-bins 3/3] COPY --from=ghcr.io/blue-build/cli:main-installer /out/bluebuild /bins/bluebuild 0.0s => CACHED [stage-4 3/16] RUN --mount=type=bind,from=stage-bins,src=/bins,dst=/tmp/bins mkdir -p /usr/bin/ && cp /tmp/bins/* /usr/bin/ && ostree 0.0s => CACHED [stage-4 4/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 5/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 6/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 7/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 8/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 9/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 10/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 11/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 12/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 13/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => CACHED [stage-4 14/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind 0.0s => [stage-4 15/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind,from= 33.4s => [stage-4 16/16] RUN --mount=type=tmpfs,target=/var --mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw --mount=type=bind,from=s 0.7s ``` Support was also added to put all build files into `./files/` instead of `./config/`. This is an all or nothing operation, meaning if there exists a directory of `files` then the `config` directory will be completely ignored. Work will have to be done in https://github.com/blue-build/modules to allow users to put their files directly in `./files/` and not `./files/files` for the `files` module or `./files/scripts` for the scripts module. Support was also added to move the `./config/containerfiles/` directory to the root of the project. Now the directories you can find in the root of projects are: ``` files/ containerfiles/ recipes/ ```
This commit is contained in:
parent
e66e880857
commit
f8b7334662
28 changed files with 217 additions and 70 deletions
|
|
@ -2,10 +2,11 @@ use std::{borrow::Cow, env, fs, path::Path, process};
|
|||
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::{
|
||||
CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_SERVER_HOST, CI_SERVER_PROTOCOL, COSIGN_PATH,
|
||||
GITHUB_RESPOSITORY, GITHUB_SERVER_URL,
|
||||
CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_SERVER_HOST, CI_SERVER_PROTOCOL, CONFIG_PATH,
|
||||
CONTAINERFILES_PATH, CONTAINER_FILE, COSIGN_PATH, FILES_PATH, GITHUB_RESPOSITORY,
|
||||
GITHUB_SERVER_URL,
|
||||
};
|
||||
use log::{debug, error, trace};
|
||||
use log::{debug, error, trace, warn};
|
||||
use typed_builder::TypedBuilder;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
@ -90,14 +91,22 @@ fn print_containerfile(containerfile: &str) -> String {
|
|||
trace!("print_containerfile({containerfile})");
|
||||
debug!("Loading containerfile contents for {containerfile}");
|
||||
|
||||
let path = format!("config/containerfiles/{containerfile}/Containerfile");
|
||||
let legacy_path = Path::new(CONFIG_PATH);
|
||||
let containerfiles_path = Path::new(CONTAINERFILES_PATH);
|
||||
|
||||
let path = if containerfiles_path.exists() && containerfiles_path.is_dir() {
|
||||
containerfiles_path.join(format!("{containerfile}/{CONTAINER_FILE}"))
|
||||
} else {
|
||||
warn!("Use of {CONFIG_PATH} is deprecated for the containerfile module, please move your containerfile directories into {CONTAINERFILES_PATH}");
|
||||
legacy_path.join(format!("containerfiles/{containerfile}/{CONTAINER_FILE}"))
|
||||
};
|
||||
|
||||
let file = fs::read_to_string(&path).unwrap_or_else(|e| {
|
||||
error!("Failed to read file {path}: {e}");
|
||||
error!("Failed to read file {}: {e}", path.display());
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
debug!("Containerfile contents {path}:\n{file}");
|
||||
debug!("Containerfile contents {}:\n{file}", path.display());
|
||||
|
||||
file
|
||||
}
|
||||
|
|
@ -139,6 +148,17 @@ fn modules_exists() -> bool {
|
|||
mod_path.exists() && mod_path.is_dir()
|
||||
}
|
||||
|
||||
fn files_dir_exists() -> bool {
|
||||
let path = Path::new(FILES_PATH);
|
||||
let exists = path.exists() && path.is_dir();
|
||||
|
||||
if !exists {
|
||||
warn!("Use of the {CONFIG_PATH} directory is deprecated. Please move your non-recipe files into {FILES_PATH}");
|
||||
}
|
||||
|
||||
exists
|
||||
}
|
||||
|
||||
mod filters {
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
pub fn replace<T: std::fmt::Display>(input: T, from: char, to: &str) -> askama::Result<String> {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
{%- set files_dir_exists = self::files_dir_exists() %}
|
||||
{%- include "stages.j2" %}
|
||||
|
||||
FROM {{ recipe.base_image }}:{{ recipe.image_version }}
|
||||
|
|
@ -5,7 +6,11 @@ FROM {{ recipe.base_image }}:{{ recipe.image_version }}
|
|||
ARG RECIPE={{ recipe_path.display() }}
|
||||
ARG IMAGE_REGISTRY={{ registry }}
|
||||
|
||||
{%- if files_dir_exists %}
|
||||
ARG CONFIG_DIRECTORY="/tmp/files"
|
||||
{%- else %}
|
||||
ARG CONFIG_DIRECTORY="/tmp/config"
|
||||
{%- endif %}
|
||||
ARG MODULE_DIRECTORY="/tmp/modules"
|
||||
ARG IMAGE_NAME="{{ recipe.name }}"
|
||||
ARG BASE_IMAGE="{{ recipe.base_image }}"
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ This makes it really easy to copy a file or program from another image.
|
|||
|
||||
### `containerfiles:`
|
||||
|
||||
The `containerfiles` property allows you to tell the compiler which directory contains a `Containerfile` in `./config/containerfiles/`.
|
||||
The `containerfiles` property allows you to tell the compiler which directory contains a `Containerfile` in `./containerfiles/`.
|
||||
|
||||
Below is an example of how a `containerfile` module would be used with the `containerfiles` property:
|
||||
|
||||
|
|
@ -43,10 +43,10 @@ modules:
|
|||
|
||||
In the example above, the compiler would look for these files:
|
||||
|
||||
- `./config/containerfiles/example/Containerfile`
|
||||
- `./config/containerfiles/subroutine/Containerfile`
|
||||
- `./containerfiles/example/Containerfile`
|
||||
- `./containerfiles/subroutine/Containerfile`
|
||||
|
||||
You could then store files related to say the `subroutine` `Containerfile` in `./config/containerfiles/subroutine/` to keep it organized and portable for other recipes to use.
|
||||
You could then store files related to say the `subroutine` `Containerfile` in `./containerfiles/subroutine/` to keep it organized and portable for other recipes to use.
|
||||
|
||||
:::note
|
||||
**NOTE:** The instructions you add in your `Containerfile`'s each become a layer unlike other modules which are typically run as a single `RUN` command, thus creating only one layer.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ RUN --mount=type=bind,from=stage-bins,src=/bins,dst=/tmp/bins \
|
|||
{%- else %}
|
||||
RUN \
|
||||
--mount=type=tmpfs,target=/var \
|
||||
{%- if files_dir_exists %}
|
||||
--mount=type=bind,from=stage-files,src=/files,dst=/tmp/files,rw \
|
||||
{%- else %}
|
||||
--mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw \
|
||||
{%- endif %}
|
||||
{%- if let Some(source) = module.source %}
|
||||
--mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \
|
||||
{%- else %}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
# This stage is responsible for holding onto
|
||||
# your config without copying it directly into
|
||||
# the final image
|
||||
{%- if files_dir_exists %}
|
||||
FROM scratch as stage-files
|
||||
COPY ./files /files
|
||||
{%- else %}
|
||||
FROM scratch as stage-config
|
||||
COPY ./config /config
|
||||
{%- endif %}
|
||||
|
||||
# Copy modules
|
||||
# The default modules are inside blue-build/modules
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue