feat: Add support for NuShell scripts

This commit is contained in:
Gerald Pinder 2024-12-24 13:23:54 -05:00
parent 1889bd9984
commit 74bd05643f
13 changed files with 115 additions and 16 deletions

View file

@ -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.

View file

@ -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)" }
}

View file

@ -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

View file

@ -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

View file

@ -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)]

View file

@ -54,6 +54,11 @@ pub struct Recipe<'a> {
#[builder(into)]
pub alt_tags: Option<Vec<String>>,
/// The version of nushell to use for modules.
#[builder(into)]
#[serde(skip_serializing_if = "Option::is_none", rename = "nushell-version")]
pub nushell_version: Option<Cow<'a, str>>,
/// The stages extension of the recipe.
///
/// This hold the list of stages that can

View file

@ -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

View file

@ -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();

View file

@ -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<Cow<'a, str>>,
}
#[derive(Debug, Clone, Template, Builder)]

View file

@ -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

View file

@ -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 }}'

View file

@ -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/ \

View file

@ -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";