diff --git a/bacon.toml b/bacon.toml index bf6551db..7b9b9d94 100644 --- a/bacon.toml +++ b/bacon.toml @@ -74,14 +74,14 @@ command = ["cargo", "install", "--path", ".", "--debug", "--locked", "--color", need_stdout = false allow_warnings = true default_watch = false -watch = ["src", "process", "recipe", "template", "utils", "Cargo.toml", "build.rs"] +watch = ["src", "process", "recipe", "template", "utils", "scripts", "Cargo.toml", "build.rs"] [jobs.install-all] command = ["cargo", "install", "--all-features", "--path", ".", "--debug", "--locked", "--color", "always"] need_stdout = false allow_warnings = true default_watch = false -watch = ["src", "process", "recipe", "template", "utils", "Cargo.toml", "build.rs"] +watch = ["src", "process", "recipe", "template", "utils", "scripts", "Cargo.toml", "build.rs"] # You may define here keybindings that would be specific to # a project, for example a shortcut to launch a specific job. diff --git a/integration-tests/test-repo/modules/test-nu-modules/test-nu-modules.nu b/integration-tests/test-repo/modules/test-nu-modules/test-nu-modules.nu new file mode 100644 index 00000000..9cbfbe60 --- /dev/null +++ b/integration-tests/test-repo/modules/test-nu-modules/test-nu-modules.nu @@ -0,0 +1,10 @@ +#!/usr/libexec/bluebuild/nu/nu + +def main [$arg] { + # Parse the JSON string into a NuShell table + let parsed_json = ($arg | from json) + + # List all top-level properties and their values + print "Top-level properties and values:" + $parsed_json | items {|key, value| $"Property: ($key), Value: ($value)" } +} diff --git a/integration-tests/test-repo/recipes/recipe.yml b/integration-tests/test-repo/recipes/recipe.yml index 45216ec2..9adc4884 100644 --- a/integration-tests/test-repo/recipes/recipe.yml +++ b/integration-tests/test-repo/recipes/recipe.yml @@ -34,6 +34,14 @@ modules: - type: test-module source: local + - type: test-nu-modules + source: local + test-prop: + - this + - is + - a + - test + - type: containerfile containerfiles: - labels diff --git a/integration-tests/test-repo/recipes/stages.yml b/integration-tests/test-repo/recipes/stages.yml index 31ea534f..7084c35d 100644 --- a/integration-tests/test-repo/recipes/stages.yml +++ b/integration-tests/test-repo/recipes/stages.yml @@ -20,7 +20,8 @@ stages: modules: - type: files files: - - usr: /usr + - source: usr + destination: /usr - type: script scripts: - example.sh @@ -33,3 +34,10 @@ modules: - labels snippets: - RUN echo "This is a snippet" + - type: test-nu-modules + source: local + test-prop: + - this + - is + - a + - test diff --git a/recipe/src/module.rs b/recipe/src/module.rs index 98ee8910..e9701577 100644 --- a/recipe/src/module.rs +++ b/recipe/src/module.rs @@ -91,6 +91,13 @@ impl<'a> ModuleRequiredFields<'a> { } } + #[must_use] + pub fn is_local_source(&self) -> bool { + self.source + .as_deref() + .is_some_and(|source| source == "local") + } + #[must_use] pub fn generate_akmods_info(&'a self, os_version: &u64) -> AkmodsInfo { #[derive(Debug, Default, Copy, Clone)] diff --git a/recipe/src/recipe.rs b/recipe/src/recipe.rs index 886ce8ee..57581388 100644 --- a/recipe/src/recipe.rs +++ b/recipe/src/recipe.rs @@ -54,6 +54,11 @@ pub struct Recipe<'a> { #[builder(into)] pub alt_tags: Option>, + /// The version of nushell to use for modules. + #[builder(into)] + #[serde(skip_serializing_if = "Option::is_none", rename = "nushell-version")] + pub nushell_version: Option>, + /// The stages extension of the recipe. /// /// This hold the list of stages that can diff --git a/scripts/run_module.sh b/scripts/run_module.sh index 41918554..fe093271 100644 --- a/scripts/run_module.sh +++ b/scripts/run_module.sh @@ -19,16 +19,54 @@ print_banner() { printf '%*.*s%s%*.*s\n' 0 "$padlen" "$padding" "$text" 0 "$padlen" "$padding" } +get_script_path() { + local script_name="$1" + local extensions=("nu" "sh" "bash") + local base_script_path="/tmp/modules/${script_name}/${script_name}" + local tried_scripts=() + + # See if + if [[ -f "${base_script_path}" ]]; then + echo "${base_script_path}" + return 0 + fi + tried_scripts+=("${script_name}") + + # Iterate through each extension and check if the file exists + for ext in "${extensions[@]}"; do + local script_path="${base_script_path}.${ext}" + tried_scripts+=("${script_name}.${ext}") + + if [[ -f "$script_path" ]]; then + # Output only the script path without extra information + echo "$script_path" + return 0 # Exit the function when the first matching file is found + fi + done + + # If no matching file was found + echo "Failed to find scripts matching: ${tried_scripts[*]}" >&2 + return 1 +} + module="$1" params="$2" -script_path="/tmp/modules/${module}/${module}.sh" +script_path="$(get_script_path "$module")" +nushell_version="$(echo "${params}" | jq '.["nushell-version"] // empty')" + +export PATH="/usr/libexec/bluebuild/nu/:$PATH" color_string "$(print_banner "Start '${module}' Module")" "33" -chmod +x ${script_path} +chmod +x "${script_path}" -if ${script_path} "${params}"; then +if "${script_path}" "${params}"; then color_string "$(print_banner "End '${module}' Module")" "32" + else color_string "$(print_banner "Failed '${module}' Module")" "31" exit 1 fi + +if command -v ostree > /dev/null; then + ostree container commit +fi diff --git a/src/commands/validate/yaml_span.rs b/src/commands/validate/yaml_span.rs index e0da837a..f3d2d43b 100644 --- a/src/commands/validate/yaml_span.rs +++ b/src/commands/validate/yaml_span.rs @@ -290,7 +290,7 @@ mod test { #[case(RECIPE, "/description", (109, 29))] #[case(RECIPE, "/image-version", (199, 6))] #[case(RECIPE, "/modules/4/install", (605, 24))] - #[case(RECIPE, "/modules/7/snippets", (824, 57))] + #[case(RECIPE, "/modules/8/snippets", (931, 57))] #[case(RECIPE_INVALID, "/image-version", (182, 11))] #[case(RECIPE_INVALID_STAGE, "/stages/0/from", (262, 8))] #[case(RECIPE_INVALID_MODULE, "/modules/7/containerfiles", (807, 8))] @@ -317,7 +317,7 @@ mod test { #[case("test: value", "/mapping")] #[case(RECIPE, "/test")] #[case(RECIPE, "/image-version/2")] - #[case(RECIPE, "/modules/12")] + #[case(RECIPE, "/modules/13")] fn test_getspan_err(#[case] file: &str, #[case] path: &str) { let file = Arc::new(file.to_owned()); let location = Location::try_from(path).unwrap(); diff --git a/template/src/lib.rs b/template/src/lib.rs index e44e38f6..78af7a5f 100644 --- a/template/src/lib.rs +++ b/template/src/lib.rs @@ -29,6 +29,7 @@ pub struct ContainerFileTemplate<'a> { build_scripts_image: Cow<'a, str>, repo: Cow<'a, str>, base_digest: Cow<'a, str>, + nushell_version: Option>, } #[derive(Debug, Clone, Template, Builder)] diff --git a/template/templates/Containerfile.j2 b/template/templates/Containerfile.j2 index 43b36bc4..b0b2059c 100644 --- a/template/templates/Containerfile.j2 +++ b/template/templates/Containerfile.j2 @@ -35,6 +35,16 @@ RUN --mount=type=bind,from=stage-bins,src=/bins,dst=/tmp/bins \ && cp /tmp/bins/* /usr/bin/ \ && ostree container commit +RUN --mount=type=bind,from={{ blue_build_utils::constants::NUSHELL_IMAGE }}: +{%- if let Some(version) = nushell_version -%} +{{ version }} +{%- else -%} +default +{%- endif %},src=/nu,dst=/tmp/nu \ + mkdir -p /usr/libexec/bluebuild/nu \ + && cp -r /tmp/nu/* /usr/libexec/bluebuild/nu/ \ + && ostree container commit + RUN --mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/scripts/ \ /scripts/pre_build.sh diff --git a/template/templates/modules/modules.j2 b/template/templates/modules/modules.j2 index 8d522e2c..b819ab5b 100644 --- a/template/templates/modules/modules.j2 +++ b/template/templates/modules/modules.j2 @@ -19,8 +19,10 @@ RUN \ {%- endif %} {%- if let Some(source) = module.get_non_local_source() %} --mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \ - {%- else %} + {%- else if module.is_local_source() %} --mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \ + {%- else %} + --mount=type=bind,from=ghcr.io/blue-build/modules/{{ module.module_type }}:latest,src=/modules,dst=/tmp/modules,rw \ {%- endif %} {%- if module.module_type == "akmods" %} --mount=type=bind,from=stage-akmods-{{ module.generate_akmods_info(os_version).stage_name }},src=/rpms,dst=/tmp/rpms,rw \ @@ -28,8 +30,7 @@ RUN \ --mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/tmp/scripts/ \ --mount=type=cache,dst=/var/cache/rpm-ostree,id=rpm-ostree-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \ --mount=type=cache,dst=/var/cache/libdnf5,id=dnf-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \ - /tmp/scripts/run_module.sh '{{ module.module_type }}' '{{ module|json|safe }}' \ - && ostree container commit + /tmp/scripts/run_module.sh '{{ module.module_type }}' '{{ module|json|safe }}' {%- endif %} {%- endif %} {%- endfor %} @@ -57,8 +58,10 @@ RUN \ {%- endif %} {%- if let Some(source) = module.get_non_local_source() %} --mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \ - {%- else %} + {%- else if module.is_local_source() %} --mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \ + {%- else %} + --mount=type=bind,from=ghcr.io/blue-build/modules/{{ module.module_type }}:latest,src=/modules,dst=/tmp/modules,rw \ {%- endif %} --mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/tmp/scripts/ \ /tmp/scripts/run_module.sh '{{ module.module_type }}' '{{ module|json|safe }}' diff --git a/template/templates/stages.j2 b/template/templates/stages.j2 index a61075f9..a92fa27c 100644 --- a/template/templates/stages.j2 +++ b/template/templates/stages.j2 @@ -4,17 +4,17 @@ {%- if self::files_dir_exists() %} FROM scratch AS stage-files COPY ./files /files -{% else if self::config_dir_exists() %} + +{%~ else if self::config_dir_exists() %} FROM scratch AS stage-config COPY ./config /config {% endif %} +{%~ if self::modules_exists() %} # Copy modules # The default modules are inside blue-build/modules # Custom modules overwrite defaults FROM scratch AS stage-modules -COPY --from=ghcr.io/blue-build/modules:latest /modules /modules -{%- if self::modules_exists() %} COPY ./modules /modules {% endif %} @@ -25,7 +25,7 @@ COPY ./modules /modules # can be added to the ostree commits. FROM scratch AS stage-bins COPY --from={{ blue_build_utils::constants::COSIGN_IMAGE }} /ko-app/cosign /bins/cosign -COPY --from=ghcr.io/blue-build/cli: +COPY --from={{ blue_build_utils::constants::BLUE_BULID_IMAGE_REF }}: {%- if let Some(tag) = recipe.blue_build_tag -%} {{ tag }} {%- else -%} @@ -59,6 +59,13 @@ ARG RUST_LOG_STYLE=always {%- endif %} {%- if stage.from != "scratch" %} +COPY --from={{ blue_build_utils::constants::NUSHELL_IMAGE }}: + {%- if let Some(version) = nushell_version -%} + {{ version }} + {%- else -%} + default + {%- endif %} /nu/* /usr/libexec/bluebuild/nu/ + # Add compatibility for modules RUN --mount=type=bind,from=stage-bins,src=/bins/,dst=/tmp/bins/ \ --mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/tmp/scripts/ \ diff --git a/utils/src/constants.rs b/utils/src/constants.rs index 90ff050f..7f492f4a 100644 --- a/utils/src/constants.rs +++ b/utils/src/constants.rs @@ -74,7 +74,9 @@ pub const XDG_RUNTIME_DIR: &str = "XDG_RUNTIME_DIR"; // Misc pub const BUILD_SCRIPTS_IMAGE_REF: &str = "ghcr.io/blue-build/cli/build-scripts"; +pub const BLUE_BULID_IMAGE_REF: &str = "ghcr.io/blue-build/cli"; pub const COSIGN_IMAGE: &str = "ghcr.io/sigstore/cosign/cosign:v2.4.1"; +pub const NUSHELL_IMAGE: &str = "ghcr.io/blue-build/nushell-image"; pub const OCI_ARCHIVE: &str = "oci-archive"; pub const OSTREE_IMAGE_SIGNED: &str = "ostree-image-signed"; pub const OSTREE_UNVERIFIED_IMAGE: &str = "ostree-unverified-image";