diff --git a/.github/workflows/docker-hub.yml b/.github/workflows/docker-hub.yml index 34267338a..7447b23a5 100644 --- a/.github/workflows/docker-hub.yml +++ b/.github/workflows/docker-hub.yml @@ -55,7 +55,7 @@ jobs: ) PLATFORM_LIST=$(echo $PLATFORM_STRING | jq -c .) echo "PLATFORM_LIST=$PLATFORM_LIST" >> $GITHUB_ENV - echo "::set-output name=platform_list::$PLATFORM_LIST" + echo "platform_list=$PLATFORM_LIST" >> $GITHUB_OUTPUT build: name: Build @@ -100,17 +100,16 @@ jobs: DOCKER_BUILDKIT: 1 run: | set -exuo pipefail + # Verify the image was built for the correct platform docker image inspect ${DOCKER_USERNAME}/${IMAGE_NAME}:cli --format='{{.Os}}/{{.Architecture}}' - cat < Dockerfile.test - FROM ${DOCKER_USERNAME}/${IMAGE_NAME}:cli - RUN apt-get update && apt-get install -y file - RUN file /usr/local/bin/metacallcli && ldd /usr/local/bin/metacallcli - RUN echo "console.log('0123456789abcdef')" > script.js - RUN metacallcli script.js | tee output.txt - RUN grep 0123456789abcdef output.txt - EOF - docker buildx build --progress=plain --platform ${{ matrix.platform }} -f Dockerfile.test -t test-image . + # Run tests directly in the container (QEMU is already set up from bake) + # This avoids the buildx cross-platform base image resolution issues + docker run --rm --platform ${{ matrix.platform }} ${DOCKER_USERNAME}/${IMAGE_NAME}:cli sh -c ' + echo "console.log('"'"'0123456789abcdef'"'"')" > script.js + metacallcli script.js | tee output.txt + grep 0123456789abcdef output.txt + ' - name: Tag & Push Platform Images # Only run when master or when tagging a version @@ -163,7 +162,7 @@ jobs: echo "Create the latest tag" cli_platform_tags="" - for platform in ${platforms[@]}"; do + for platform in "${platforms[@]}"; do platform_tag=$(echo "${platform}" | tr '/' '-') cli_platform_tags="${cli_platform_tags} ${DOCKER_USERNAME}/${IMAGE_NAME}:cli-${platform_tag}" done diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 000000000..d3fa4871e --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,118 @@ +# +# MetaCall Library by Parra Studios +# Docker bake configuration for MetaCall. +# +# Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Variables from environment +variable "METACALL_BASE_IMAGE" { + default = "debian:trixie-slim" +} + +variable "METACALL_PATH" { + default = "/usr/local/metacall" +} + +variable "METACALL_BUILD_TYPE" { + default = "relwithdebinfo" +} + +variable "METACALL_INSTALL_OPTIONS" { + default = "base python ruby nodejs typescript file rpc rapidjson pack backtrace" +} + +variable "METACALL_BUILD_OPTIONS" { + default = "python ruby nodejs typescript file rpc examples tests scripts ports install pack" +} + +variable "METACALL_RUNTIME_OPTIONS" { + default = "base python ruby nodejs typescript file rpc backtrace ports clean" +} + +variable "DOCKER_USERNAME" { + default = "metacall" +} + +variable "IMAGE_NAME" { + default = "core" +} + +# Build all images in dependency order +group "default" { + targets = ["deps", "dev", "runtime", "cli"] +} + +# Base dependencies image +target "deps" { + context = "." + dockerfile = "tools/deps/Dockerfile" + tags = ["${DOCKER_USERNAME}/${IMAGE_NAME}:deps"] + args = { + METACALL_BASE_IMAGE = "${METACALL_BASE_IMAGE}" + METACALL_PATH = "${METACALL_PATH}" + METACALL_TOOLS_PATH = "${METACALL_PATH}/tools" + METACALL_BUILD_TYPE = "${METACALL_BUILD_TYPE}" + METACALL_INSTALL_OPTIONS = "${METACALL_INSTALL_OPTIONS}" + } + network = "host" +} + +# Development image (depends on deps) +target "dev" { + context = "." + dockerfile = "tools/dev/Dockerfile" + tags = ["${DOCKER_USERNAME}/${IMAGE_NAME}:dev"] + args = { + METACALL_PATH = "${METACALL_PATH}" + METACALL_BUILD_TYPE = "${METACALL_BUILD_TYPE}" + METACALL_BUILD_OPTIONS = "${METACALL_BUILD_OPTIONS}" + } + network = "host" + # Use the deps target as the base image + contexts = { + "metacall/core:deps" = "target:deps" + } +} + +# Runtime image (depends on dev for builder stage) +target "runtime" { + context = "." + dockerfile = "tools/runtime/Dockerfile" + tags = ["${DOCKER_USERNAME}/${IMAGE_NAME}:runtime"] + args = { + METACALL_BASE_IMAGE = "${METACALL_BASE_IMAGE}" + METACALL_PATH = "${METACALL_PATH}" + METACALL_RUNTIME_OPTIONS = "${METACALL_RUNTIME_OPTIONS}" + } + network = "host" + # Use the dev target as the builder base image + contexts = { + "metacall/core:dev" = "target:dev" + } +} + +# CLI image (depends on dev for builder and runtime for base) +target "cli" { + context = "." + dockerfile = "tools/cli/Dockerfile" + tags = ["${DOCKER_USERNAME}/${IMAGE_NAME}:cli"] + network = "host" + # Use both dev (for builder) and runtime (for base) targets + contexts = { + "metacall/core:dev" = "target:dev" + "metacall/core:runtime" = "target:runtime" + } +} diff --git a/docker-compose.sh b/docker-compose.sh index e254cb103..6a51dcccc 100755 --- a/docker-compose.sh +++ b/docker-compose.sh @@ -199,7 +199,7 @@ sub_cache() { $DOCKER_COMPOSE -f docker-compose.yml -f docker-compose.cache.yml build cli } -# Build MetaCall Docker Compose with multi-platform specifier (link manually dockerignore files) +# Build MetaCall Docker Compose with multi-platform specifier using bake with contexts sub_platform() { if [ -z "$METACALL_PLATFORM" ]; then echo "Error: METACALL_PLATFORM variable not defined" @@ -209,30 +209,26 @@ sub_platform() { # Initialize QEMU for Buildkit docker run --rm --privileged tonistiigi/binfmt --install all + # Load default environment variables + source .env + # Debian in Docker Hub does not support LoongArch64 yet, let's use official LoongArch repository instead if [ "$METACALL_PLATFORM" = "linux/loong64" ]; then - source .env export METACALL_BASE_IMAGE="ghcr.io/loong64/${METACALL_BASE_IMAGE}" fi - # Generate the docker compose file with all .env variables substituted (bake seems not to support this) - $DOCKER_COMPOSE -f docker-compose.yml config &> docker-compose.bake.yml - - # Build with Bake, so the image can be loaded into local docker context - ln -sf tools/deps/.dockerignore .dockerignore - docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load deps - - ln -sf tools/dev/.dockerignore .dockerignore - docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load dev - - ln -sf tools/runtime/.dockerignore .dockerignore - docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load runtime - - ln -sf tools/cli/.dockerignore .dockerignore - docker buildx bake -f docker-compose.bake.yml --set *.platform="${METACALL_PLATFORM}" --load cli - - # Delete temporal docker compose file - rm -rf docker-compose.bake.yml + # Export variables for docker bake + export METACALL_BASE_IMAGE="${METACALL_BASE_IMAGE}" + export METACALL_PATH="${METACALL_PATH}" + export METACALL_BUILD_TYPE="${METACALL_BUILD_TYPE}" + + # Build all images with Bake in a single command using contexts for dependencies + # This ensures that dependent images (dev->deps, runtime->dev, cli->runtime+dev) + # can properly reference their base images without needing them in local cache + docker buildx bake \ + -f docker-bake.hcl \ + --set "*.platform=${METACALL_PLATFORM}" \ + --load } # Push MetaCall Docker Compose diff --git a/docker-compose.yml b/docker-compose.yml index 1c1997b13..5246e4439 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,6 +46,8 @@ services: dev: image: metacall/core:dev container_name: metacall_core_dev + depends_on: + - deps build: network: "host" context: . @@ -69,6 +71,8 @@ services: runtime: image: metacall/core:runtime container_name: metacall_core_runtime + depends_on: + - dev build: network: "host" context: . @@ -92,6 +96,8 @@ services: cli: image: metacall/core:cli container_name: metacall_core_cli + depends_on: + - runtime build: network: "host" context: . diff --git a/tools/cli/Dockerfile.dockerignore b/tools/cli/Dockerfile.dockerignore new file mode 100644 index 000000000..1d085cacc --- /dev/null +++ b/tools/cli/Dockerfile.dockerignore @@ -0,0 +1 @@ +** diff --git a/tools/deps/Dockerfile.dockerignore b/tools/deps/Dockerfile.dockerignore new file mode 100644 index 000000000..df169544d --- /dev/null +++ b/tools/deps/Dockerfile.dockerignore @@ -0,0 +1,3 @@ +** +!tools/metacall-environment.sh +!tools/nobuildtest.patch diff --git a/tools/dev/Dockerfile.dockerignore b/tools/dev/Dockerfile.dockerignore new file mode 100644 index 000000000..ab1f6c4a4 --- /dev/null +++ b/tools/dev/Dockerfile.dockerignore @@ -0,0 +1,19 @@ +** +!cmake/** +!data/** +!deploy/** +!docs/** +!source/** +!tools/metacall-configure.sh +!tools/metacall-build.sh +!.clang-format +!CMakeLists.txt +!metacall-config.cmake.in +!metacall-config-version.cmake.in +!AUTHORS +!DESCRIPTION +!LICENSE +!README.md +!VERSION +!WELCOME +source/loaders/rs_loader/rust/target diff --git a/tools/runtime/Dockerfile.dockerignore b/tools/runtime/Dockerfile.dockerignore new file mode 100644 index 000000000..b6829eb82 --- /dev/null +++ b/tools/runtime/Dockerfile.dockerignore @@ -0,0 +1,2 @@ +** +!tools/metacall-runtime.sh