From f1e8aab95e43c2648ec05b55780b5d5d5c6005a4 Mon Sep 17 00:00:00 2001 From: Helio Chissini de Castro Date: Thu, 2 Nov 2023 13:46:43 +0100 Subject: [PATCH] feat(docker): Rename images to new defaults - ORT main image is now called ort alone. Is based on previous ort-extended image. - A new image called ort-minimal is created based on original ort image. - Language component images now have named version with hash addition to chek if contents of the image changed without changing core language. Signed-off-by: Helio Chissini de Castro --- .github/actions/ortdocker/action.yml | 140 ++--- .github/actions/ortdocker/check_image.py | 9 +- ...ort-runtime.yml => docker-ort-minimal.yml} | 179 ++++++- ...ker-ort-runtime-ext.yml => docker-ort.yml} | 7 +- Dockerfile | 75 ++- Dockerfile-extended | 85 --- Dockerfile-minimal | 495 ++++++++++++++++++ scripts/custom_docker.sh | 4 +- scripts/docker_build.sh | 24 +- 9 files changed, 840 insertions(+), 178 deletions(-) rename .github/workflows/{docker-ort-runtime.yml => docker-ort-minimal.yml} (55%) rename .github/workflows/{docker-ort-runtime-ext.yml => docker-ort.yml} (96%) delete mode 100644 Dockerfile-extended create mode 100644 Dockerfile-minimal diff --git a/.github/actions/ortdocker/action.yml b/.github/actions/ortdocker/action.yml index d4ff3ac196f47..9f703b74e5574 100644 --- a/.github/actions/ortdocker/action.yml +++ b/.github/actions/ortdocker/action.yml @@ -20,81 +20,83 @@ description: "Check and create Docker image for ORT components" author: "The ORT Project Authors" inputs: - registry: - description: "GitHub container registry" - default: "ghcr.io" - token: - description: "GitHub token" - required: true - name: - description: "Image name" - required: true - version: - description: "Image version" - required: true - build-args: - description: "List of build-time variables" - required: false + registry: + description: "GitHub container registry" + default: "ghcr.io" + token: + description: "GitHub token" + required: true + name: + description: "Image name" + required: true + version: + description: "Image version" + required: true + build-args: + description: "List of build-time variables" + required: false runs: - using: "composite" + using: "composite" - steps: - - name: Install Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' + steps: + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + cache: "pip" - - name: Check if Docker image tag exists - id: check_image - shell: bash - env: - INPUT_REGISTRY: ${{ inputs.registry }} - INPUT_TOKEN: ${{ inputs.token }} - INPUT_NAME: ${{ inputs.name }} - INPUT_VERSION: ${{ inputs.version }} - run: | - pip install -q -U pip requests + - name: Check if Docker image tag exists + id: check_image + shell: bash + env: + INPUT_REGISTRY: ${{ inputs.registry }} + INPUT_TOKEN: ${{ inputs.token }} + INPUT_NAME: ${{ inputs.name }} + INPUT_VERSION: ${{ inputs.version }} + BUILD_ARGS: ${{ inputs.build-args }} + run: | + pip install -q -U pip requests - result=$(python ./.github/actions/ortdocker/check_image.py) - echo $result - echo "result=$result" >> $GITHUB_OUTPUT + result=$(python ./.github/actions/ortdocker/check_image.py) + echo $result + echo "result=$result" >> $GITHUB_OUTPUT - - name: Set up Docker build - if: steps.check_image.outputs.result != 'found' - uses: docker/setup-buildx-action@v3 + - name: Set up Docker build + if: steps.check_image.outputs.result != 'found' + uses: docker/setup-buildx-action@v3 - - name: Login to GitHub container registry - if: steps.check_image.outputs.result != 'found' - uses: docker/login-action@v3 - with: - registry: ${{ inputs.registry }} - username: ${{ github.actor }} - password: ${{ inputs.token }} + - name: Login to GitHub container registry + if: steps.check_image.outputs.result != 'found' + uses: docker/login-action@v3 + with: + registry: ${{ inputs.registry }} + username: ${{ github.actor }} + password: ${{ inputs.token }} - - name: Extract components metadata (tags, labels) - if: steps.check_image.outputs.result != 'found' - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.name }} - tags: - type=raw,value=${{ inputs.version }} + - name: Extract components metadata (tags, labels) + if: steps.check_image.outputs.result != 'found' + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.name }} + tags: | + type=raw,value=${{ inputs.version }} + type=raw,value=${{ steps.check_image.outputs.result }} - - name: Build image - if: steps.check_image.outputs.result != 'found' - uses: docker/build-push-action@v5 - with: - context: . - target: ${{ inputs.name }} - push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} - load: false - build-args: ${{ inputs.build-args }} - tags: | - ${{ steps.meta.outputs.tags }} - ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.name }}:latest - labels: ${{ steps.meta.outputs.labels }} - build-contexts: | - base=docker-image://${{ inputs.registry }}/${{ github.repository }}/base:latest + - name: Build image + if: steps.check_image.outputs.result != 'found' + uses: docker/build-push-action@v5 + with: + context: . + target: ${{ inputs.name }} + push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + load: false + build-args: ${{ inputs.build-args }} + tags: | + ${{ steps.meta.outputs.tags }} + ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.name }}:latest + labels: ${{ steps.meta.outputs.labels }} + build-contexts: | + base=docker-image://${{ inputs.registry }}/${{ github.repository }}/base:latest diff --git a/.github/actions/ortdocker/check_image.py b/.github/actions/ortdocker/check_image.py index 31af107f11752..55b3b396cfd4d 100644 --- a/.github/actions/ortdocker/check_image.py +++ b/.github/actions/ortdocker/check_image.py @@ -15,6 +15,7 @@ # SPDX-License-Identifier: Apache-2.0 # License-Filename: LICENSE +import hashlib import os import requests @@ -26,7 +27,11 @@ token = os.getenv("INPUT_TOKEN") org = os.getenv("GITHUB_REPOSITORY_OWNER") name = os.getenv("INPUT_NAME") -version = os.getenv("INPUT_VERSION") +base_version = os.getenv("INPUT_VERSION") +unique_id = hashlib.sha256(os.getenv("BUILD_ARGS").encode()).hexdigest() + +# We base the version on the base_version and the unique_id +version = f"{base_version}-{unique_id[:8]}" url = f"https://api.github.com/orgs/{org}/packages/container/ort%2F{name}/versions" @@ -47,4 +52,4 @@ if version in versions: print("found") else: - print("none") + print(version) diff --git a/.github/workflows/docker-ort-runtime.yml b/.github/workflows/docker-ort-minimal.yml similarity index 55% rename from .github/workflows/docker-ort-runtime.yml rename to .github/workflows/docker-ort-minimal.yml index dc147e089957b..43c93d7868eb7 100644 --- a/.github/workflows/docker-ort-runtime.yml +++ b/.github/workflows/docker-ort-minimal.yml @@ -15,7 +15,7 @@ # SPDX-License-Identifier: Apache-2.0 # License-Filename: LICENSE -name: Docker runtime image +name: ORT Minimal Image on: workflow_dispatch: @@ -25,7 +25,7 @@ on: paths: - '.versions' - 'Dockerfile' - - '.github/workflows/docker-ort-runtime.yml' + - '.github/workflows/docker-ort-minimal.yml' push: tags: - '*' @@ -162,9 +162,9 @@ jobs: GO_DEP_VERSION=${{ env.GO_DEP_VERSION }} GO_VERSION=${{ env.GO_VERSION }} - runtime_image: + minimal_image: needs: [ base_image, nodejs_image, python_image, rust_image, ruby_image, golang_image ] - name: Build ORT runtime image + name: Build ORT minimal image runs-on: ubuntu-22.04 permissions: contents: read @@ -208,7 +208,7 @@ jobs: type=raw,value=${{ env.ORT_VERSION }} type=ref,event=tag - - name: Build ORT runtime image + - name: Build ORT minimal image uses: docker/build-push-action@v5 with: context: . @@ -228,3 +228,172 @@ jobs: rust=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/rust:latest ruby=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/ruby:latest golang=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/golang:latest + + android_image: + name: Android image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Android image + uses: ./.github/actions/ortdocker + with: + name: android + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.ANDROID_CMD_VERSION }}" + build-args: | + ANDROID_CMD_VERSION=${{ env.ANDROID_CMD_VERSION }} + + dart_image: + name: Dart image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Dart image + uses: ./.github/actions/ortdocker + with: + name: dart + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.DART_VERSION }}" + build-args: | + DART_VERSION=${{ env.DART_VERSION }} + + dotnet_image: + name: Dotnet image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Dotnet image + uses: ./.github/actions/ortdocker + with: + name: dotnet + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.DOTNET_VERSION }}" + build-args: | + DOTNET_VERSION=${{ env.DOTNET_VERSION }} + NUGET_INSPECTOR_VERSION=${{ env.NUGET_INSPECTOR_VERSION }} + + haskell_image: + name: Haskell image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Haskell image + uses: ./.github/actions/ortdocker + with: + name: haskell + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.HASKELL_STACK_VERSION }}" + build-args: | + HASKELL_STACK_VERSION=${{ env.HASKELL_STACK_VERSION }} + + scala_image: + name: Scala image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Scala image + uses: ./.github/actions/ortdocker + with: + name: scala + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.SBT_VERSION }}" + build-args: | + SBT_VERSION=${{ env.SBT_VERSION }} + + swift_image: + name: Swift image + runs-on: ubuntu-22.04 + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + - name: Set environment variables + run: | + cat .versions >> $GITHUB_ENV + - name: Build Swift image + uses: ./.github/actions/ortdocker + with: + name: swift + token: ${{ secrets.GITHUB_TOKEN }} + version: "${{ env.SWIFT_VERSION }}" + build-args: | + SWIFT_VERSION=${{ env.SWIFT_VERSION }} + + ort_image: + name: Build ORT image + needs: [ minimal_image, android_image, dart_image, dotnet_image, haskell_image, scala_image, swift_image ] + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout default branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get ORT current version + run: | + ORT_VERSION=$(./gradlew -q properties --property version | sed -nr "s/version: (.+)/\1/p") + echo "ORT_VERSION=${ORT_VERSION}" >> $GITHUB_ENV + + - name: Set up Docker build + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract components metadata (tags, labels) + id: meta-ort + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ github.repository_owner }}/ort-extended + tags: | + type=schedule,pattern={{date 'YYYYMMDD'}} + type=schedule,pattern=snapshot + type=pep440,pattern={{version}} + type=raw,value=${{ env.ORT_VERSION }} + type=ref,event=tag + + - name: Build ORT extended runtime image + uses: docker/build-push-action@v5 + with: + context: . + push: true + load: false + tags: | + ${{ steps.meta-ort.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-contexts: | + ort-minimal=docker-image://${{ env.REGISTRY }}/${{ github.repository_owner }}/ort-minimal:${{ env.ORT_VERSION }} + android=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/android:latest + swift=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/swift:latest + scala=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/scala:latest + dart=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/dart:latest + dotnet=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/dotnet:latest + haskell=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/haskell:latest \ No newline at end of file diff --git a/.github/workflows/docker-ort-runtime-ext.yml b/.github/workflows/docker-ort.yml similarity index 96% rename from .github/workflows/docker-ort-runtime-ext.yml rename to .github/workflows/docker-ort.yml index 2a63ca5b68dd9..6a1a935c2d3e6 100644 --- a/.github/workflows/docker-ort-runtime-ext.yml +++ b/.github/workflows/docker-ort.yml @@ -15,13 +15,13 @@ # SPDX-License-Identifier: Apache-2.0 # License-Filename: LICENSE -name: Docker extended runtime image +name: ORT Image on: workflow_dispatch: workflow_run: workflows: - - 'Docker runtime image' + - 'ORT Minimal Image' types: - completed @@ -186,14 +186,13 @@ jobs: uses: docker/build-push-action@v5 with: context: . - file: Dockerfile-extended push: true load: false tags: | ${{ steps.meta-ort.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-contexts: | - ort=docker-image://${{ env.REGISTRY }}/${{ github.repository_owner }}/ort:${{ env.ORT_VERSION }} + ort-minimal=docker-image://${{ env.REGISTRY }}/${{ github.repository_owner }}/ort-minimal:${{ env.ORT_VERSION }} android=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/android:latest swift=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/swift:latest scala=docker-image://${{ env.REGISTRY }}/${{ github.repository }}/scala:latest diff --git a/Dockerfile b/Dockerfile index 07443d068e3fb..df6c92cbe8c11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -432,8 +432,8 @@ FROM scratch AS ortbin COPY --from=ortbuild /opt/ort /opt/ort #------------------------------------------------------------------------ -# Main Minimal Runtime container -FROM base as run +# Minimal Runtime container +FROM base as minimal # Remove ort build scripts RUN [ -d /etc/scripts ] && sudo rm -rf /etc/scripts @@ -493,3 +493,74 @@ WORKDIR $HOME RUN mkdir -p "$HOME/.ort" ENTRYPOINT ["/opt/ort/bin/ort"] + +#------------------------------------------------------------------------ +# Full Runtime container +FROM minimal as run + +# Repo and Android +ENV ANDROID_HOME=/opt/android-sdk +ENV ANDROID_USER_HOME=$HOME/.android +ENV PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/bin +ENV PATH=$PATH:$ANDROID_HOME/platform-tools +COPY --from=android --chown=$USER:$USER $ANDROID_HOME $ANDROID_HOME +RUN sudo chmod -R o+rw $ANDROID_HOME + +RUN syft $ANDROID_HOME -o spdx-json --file /usr/share/doc/ort/ort-android.spdx.json + +# Swift +ENV SWIFT_HOME=/opt/swift +ENV PATH=$PATH:$SWIFT_HOME/bin +COPY --from=swift --chown=$USER:$USER $SWIFT_HOME $SWIFT_HOME + +RUN syft $SWIFT_HOME -o spdx-json --file /usr/share/doc/ort/ort-swift.spdx.json + + +# Scala +ENV SBT_HOME=/opt/sbt +ENV PATH=$PATH:$SBT_HOME/bin +COPY --from=scala --chown=$USER:$USER $SBT_HOME $SBT_HOME + +RUN syft $SBT_HOME -o spdx-json --file /usr/share/doc/ort/ort-sbt.spdx.json + +# Dart +ENV DART_SDK=/opt/dart-sdk +ENV PATH=$PATH:$DART_SDK/bin +COPY --from=dart --chown=$USER:$USER $DART_SDK $DART_SDK + +RUN syft $DART_SDK -o spdx-json --file /usr/share/doc/ort/ort-golang.dart.json + +# Dotnet +ENV DOTNET_HOME=/opt/dotnet +ENV NUGET_INSPECTOR_HOME=$DOTNET_HOME +ENV PATH=$PATH:$DOTNET_HOME:$DOTNET_HOME/tools:$DOTNET_HOME/bin + +COPY --from=dotnet --chown=$USER:$USER $DOTNET_HOME $DOTNET_HOME + +RUN syft $DOTNET_HOME -o spdx-json --file /usr/share/doc/ort/ort-dotnet.spdx.json + +# PHP +ARG PHP_VERSION=8.1 +ARG COMPOSER_VERSION=2.2 + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update && \ + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + php${PHP_VERSION} \ + && sudo rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /opt/php/bin \ + && curl -ksS https://getcomposer.org/installer | php -- --install-dir=/opt/php/bin --filename=composer --$COMPOSER_VERSION + +ENV PATH=$PATH:/opt/php/bin + +RUN syft /opt/php -o spdx-json --file /usr/share/doc/ort/ort-php.spdx.json + +# Haskell +ENV HASKELL_HOME=/opt/haskell +ENV PATH=$PATH:$HASKELL_HOME/bin + +COPY --from=haskell /opt/haskell /opt/haskell + +RUN syft /opt/haskell -o spdx-json --file /usr/share/doc/ort/ort-haskell.spdx.json \ No newline at end of file diff --git a/Dockerfile-extended b/Dockerfile-extended deleted file mode 100644 index 3a878f1bb1e4f..0000000000000 --- a/Dockerfile-extended +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (C) 2023 The ORT Project Authors (see ) -# -# 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 -# -# https://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. -# -# SPDX-License-Identifier: Apache-2.0 -# License-Filename: LICENSE - -FROM ort - -# Repo and Android -ENV ANDROID_HOME=/opt/android-sdk -ENV ANDROID_USER_HOME=$HOME/.android -ENV PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/bin -ENV PATH=$PATH:$ANDROID_HOME/platform-tools -COPY --from=android --chown=$USER:$USER $ANDROID_HOME $ANDROID_HOME -RUN sudo chmod -R o+rw $ANDROID_HOME - -RUN syft $ANDROID_HOME -o spdx-json --file /usr/share/doc/ort/ort-android.spdx.json - -# Swift -ENV SWIFT_HOME=/opt/swift -ENV PATH=$PATH:$SWIFT_HOME/bin -COPY --from=swift --chown=$USER:$USER $SWIFT_HOME $SWIFT_HOME - -RUN syft $SWIFT_HOME -o spdx-json --file /usr/share/doc/ort/ort-swift.spdx.json - - -# Scala -ENV SBT_HOME=/opt/sbt -ENV PATH=$PATH:$SBT_HOME/bin -COPY --from=scala --chown=$USER:$USER $SBT_HOME $SBT_HOME - -RUN syft $SBT_HOME -o spdx-json --file /usr/share/doc/ort/ort-sbt.spdx.json - -# Dart -ENV DART_SDK=/opt/dart-sdk -ENV PATH=$PATH:$DART_SDK/bin -COPY --from=dart --chown=$USER:$USER $DART_SDK $DART_SDK - -RUN syft $DART_SDK -o spdx-json --file /usr/share/doc/ort/ort-golang.dart.json - -# Dotnet -ENV DOTNET_HOME=/opt/dotnet -ENV NUGET_INSPECTOR_HOME=$DOTNET_HOME -ENV PATH=$PATH:$DOTNET_HOME:$DOTNET_HOME/tools:$DOTNET_HOME/bin - -COPY --from=dotnet --chown=$USER:$USER $DOTNET_HOME $DOTNET_HOME - -RUN syft $DOTNET_HOME -o spdx-json --file /usr/share/doc/ort/ort-dotnet.spdx.json - -# PHP -ARG PHP_VERSION=8.1 -ARG COMPOSER_VERSION=2.2 - -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - sudo apt-get update && \ - DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ - php${PHP_VERSION} \ - && sudo rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /opt/php/bin \ - && curl -ksS https://getcomposer.org/installer | php -- --install-dir=/opt/php/bin --filename=composer --$COMPOSER_VERSION - -ENV PATH=$PATH:/opt/php/bin - -RUN syft /opt/php -o spdx-json --file /usr/share/doc/ort/ort-php.spdx.json - -# Haskell -ENV HASKELL_HOME=/opt/haskell -ENV PATH=$PATH:$HASKELL_HOME/bin - -COPY --from=haskell /opt/haskell /opt/haskell - -RUN syft /opt/haskell -o spdx-json --file /usr/share/doc/ort/ort-haskell.spdx.json diff --git a/Dockerfile-minimal b/Dockerfile-minimal new file mode 100644 index 0000000000000..07443d068e3fb --- /dev/null +++ b/Dockerfile-minimal @@ -0,0 +1,495 @@ +# syntax=docker/dockerfile:1.4 + +# Copyright (C) 2020 The ORT Project Authors (see ) +# +# 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 +# +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +# License-Filename: LICENSE + +# Set this to the Java version to use in the base image (and to build and run ORT with). +ARG JAVA_VERSION=17 +ARG UBUNTU_VERSION=jammy + +# Use OpenJDK Eclipe Temurin Ubuntu LTS +FROM eclipse-temurin:$JAVA_VERSION-jdk-$UBUNTU_VERSION as base + +ENV LANG=en_US.UTF-8 +ENV LANGUAGE=en_US:en +ENV LC_ALL=en_US.UTF-8 + +# Check and set apt proxy +COPY scripts/set_apt_proxy.sh /etc/scripts/set_apt_proxy.sh +RUN /etc/scripts/set_apt_proxy.sh + +# Base package set +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates \ + coreutils \ + curl \ + dirmngr \ + file \ + gcc \ + git \ + git-lfs \ + g++ \ + gnupg2 \ + iproute2 \ + libarchive-tools \ + libffi-dev \ + libgmp-dev \ + libmagic1 \ + libz-dev \ + locales \ + lzma \ + make \ + netbase \ + openssh-client \ + openssl \ + procps \ + rsync \ + sudo \ + tzdata \ + uuid-dev \ + unzip \ + wget \ + xz-utils \ + && rm -rf /var/lib/apt/lists/* \ + && git lfs install + +RUN echo $LANG > /etc/locale.gen \ + && locale-gen $LANG \ + && update-locale LANG=$LANG + +ARG USERNAME=ort +ARG USER_ID=1000 +ARG USER_GID=$USER_ID +ARG HOMEDIR=/home/ort +ENV HOME=$HOMEDIR +ENV USER=$USERNAME + +# Non privileged user +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd \ + --uid $USER_ID \ + --gid $USER_GID \ + --shell /bin/bash \ + --home-dir $HOMEDIR \ + --create-home $USERNAME + +RUN chgrp $USER /opt \ + && chmod g+wx /opt + +# sudo support +RUN echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME + +# Copy certificates scripts only. +COPY scripts/*_certificates.sh /etc/scripts/ + +# Set this to a directory containing CRT-files for custom certificates that ORT and all build tools should know about. +ARG CRT_FILES="*.crt" +COPY "$CRT_FILES" /tmp/certificates/ + +RUN /etc/scripts/export_proxy_certificates.sh /tmp/certificates/ \ + && /etc/scripts/import_certificates.sh /tmp/certificates/ + +# Add Syft to use as primary SPDX Docker scanner +# Create docs dir to store future SPDX files +RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin \ + && mkdir -p /usr/share/doc/ort \ + && chown $USER:$USER /usr/share/doc/ort + +USER $USER +WORKDIR $HOME + +ENTRYPOINT [ "/bin/bash" ] + +#------------------------------------------------------------------------ +# PYTHON - Build Python as a separate component with pyenv +FROM base AS pythonbuild + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + libreadline-dev \ + libgdbm-dev \ + libsqlite3-dev \ + libssl-dev \ + libbz2-dev \ + liblzma-dev \ + tk-dev \ + && sudo rm -rf /var/lib/apt/lists/* + +ARG PYTHON_VERSION=3.11.5 +ARG PYENV_GIT_TAG=v2.3.25 + +ENV PYENV_ROOT=/opt/python +ENV PATH=$PATH:$PYENV_ROOT/shims:$PYENV_ROOT/bin +RUN curl -kSs https://pyenv.run | bash \ + && pyenv install -v $PYTHON_VERSION \ + && pyenv global $PYTHON_VERSION + +ARG CONAN_VERSION=1.57.0 +ARG PYTHON_INSPECTOR_VERSION=0.10.0 +ARG PYTHON_PIPENV_VERSION=2022.9.24 +ARG PYTHON_POETRY_VERSION=1.6.1 +ARG PIPTOOL_VERSION=22.2.2 +ARG SCANCODE_VERSION=32.0.6 + +RUN pip install --no-cache-dir -U \ + pip=="$PIPTOOL_VERSION" \ + wheel \ + && pip install --no-cache-dir -U \ + Mercurial \ + conan=="$CONAN_VERSION" \ + pip \ + pipenv=="$PYTHON_PIPENV_VERSION" \ + poetry=="$PYTHON_POETRY_VERSION" \ + python-inspector=="$PYTHON_INSPECTOR_VERSION" + +RUN ARCH=$(arch | sed s/aarch64/arm64/) \ + && if [ "$ARCH" == "arm64" ]; then \ + pip install -U scancode-toolkit-mini==$SCANCODE_VERSION; \ + else \ + curl -Os https://raw.githubusercontent.com/nexB/scancode-toolkit/v$SCANCODE_VERSION/requirements.txt; \ + pip install -U --constraint requirements.txt scancode-toolkit==$SCANCODE_VERSION; \ + rm requirements.txt; \ + fi + +FROM scratch AS python +COPY --from=pythonbuild /opt/python /opt/python + +#------------------------------------------------------------------------ +# NODEJS - Build NodeJS as a separate component with nvm +FROM base AS nodejsbuild + +ARG BOWER_VERSION=1.8.12 +ARG NODEJS_VERSION=20.9.0 +ARG NPM_VERSION=10.1.0 +ARG PNPM_VERSION=8.8.0 +ARG YARN_VERSION=1.22.17 + +ENV NVM_DIR=/opt/nvm +ENV PATH=$PATH:$NVM_DIR/versions/node/v$NODEJS_VERSION/bin + +RUN git clone --depth 1 https://github.com/nvm-sh/nvm.git $NVM_DIR +RUN . $NVM_DIR/nvm.sh \ + && nvm install "$NODEJS_VERSION" \ + && nvm alias default "$NODEJS_VERSION" \ + && nvm use default \ + && npm install --global npm@$NPM_VERSION bower@$BOWER_VERSION pnpm@$PNPM_VERSION yarn@$YARN_VERSION + +FROM scratch AS nodejs +COPY --from=nodejsbuild /opt/nvm /opt/nvm + +#------------------------------------------------------------------------ +# RUBY - Build Ruby as a separate component with rbenv +FROM base AS rubybuild + +# hadolint ignore=DL3004 +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + libreadline6-dev \ + libssl-dev \ + libz-dev \ + make \ + xvfb \ + zlib1g-dev \ + && sudo rm -rf /var/lib/apt/lists/* + +ARG COCOAPODS_VERSION=1.11.2 +ARG RUBY_VERSION=3.1.2 + +ENV RBENV_ROOT=/opt/rbenv +ENV PATH=$RBENV_ROOT/bin:$RBENV_ROOT/shims/:$RBENV_ROOT/plugins/ruby-build/bin:$PATH + +RUN git clone --depth 1 https://github.com/rbenv/rbenv.git $RBENV_ROOT +RUN git clone --depth 1 https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build +WORKDIR $RBENV_ROOT +RUN src/configure \ + && make -C src +RUN rbenv install $RUBY_VERSION -v \ + && rbenv global $RUBY_VERSION \ + && gem install bundler cocoapods:$COCOAPODS_VERSION + +FROM scratch AS ruby +COPY --from=rubybuild /opt/rbenv /opt/rbenv + +#------------------------------------------------------------------------ +# RUST - Build as a separate component +FROM base AS rustbuild + +ARG RUST_VERSION=1.72.0 + +ENV RUST_HOME=/opt/rust +ENV CARGO_HOME=$RUST_HOME/cargo +ENV RUSTUP_HOME=$RUST_HOME/rustup +RUN curl -ksSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain $RUST_VERSION + +FROM scratch AS rust +COPY --from=rustbuild /opt/rust /opt/rust + +#------------------------------------------------------------------------ +# GOLANG - Build as a separate component +FROM base AS gobuild + +ARG GO_DEP_VERSION=0.5.4 +ARG GO_VERSION=1.21.1 +ENV GOBIN=/opt/go/bin +ENV PATH=$PATH:/opt/go/bin + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ + && curl -L https://dl.google.com/go/go$GO_VERSION.linux-$ARCH.tar.gz | tar -C /opt -xz \ + && curl -ksS https://raw.githubusercontent.com/golang/dep/v$GO_DEP_VERSION/install.sh | bash + +FROM scratch AS golang +COPY --from=gobuild /opt/go /opt/go + +#------------------------------------------------------------------------ +# HASKELL STACK +FROM base AS haskellbuild + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + zlib1g-dev \ + && sudo rm -rf /var/lib/apt/lists/* + +ARG HASKELL_STACK_VERSION=2.7.5 + +ENV HASKELL_HOME=/opt/haskell +ENV PATH=$PATH:$HASKELL_HOME/bin + +RUN curl -sSL https://get.haskellstack.org/ | bash -s -- -d $HASKELL_HOME/bin + +FROM scratch AS haskell +COPY --from=haskellbuild /opt/haskell /opt/haskell + +#------------------------------------------------------------------------ +# REPO / ANDROID SDK +FROM base AS androidbuild + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + unzip \ + && sudo rm -rf /var/lib/apt/lists/* + +ARG ANDROID_CMD_VERSION=9477386 +ENV ANDROID_HOME=/opt/android-sdk + +RUN --mount=type=tmpfs,target=/android \ + cd /android \ + && curl -Os https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMD_VERSION}_latest.zip \ + && unzip -q commandlinetools-linux-${ANDROID_CMD_VERSION}_latest.zip -d $ANDROID_HOME \ + && PROXY_HOST_AND_PORT=${https_proxy#*://} \ + && PROXY_HOST_AND_PORT=${PROXY_HOST_AND_PORT%/} \ + && if [ -n "$PROXY_HOST_AND_PORT" ]; then \ + # While sdkmanager uses HTTPS by default, the proxy type is still called "http". + SDK_MANAGER_PROXY_OPTIONS="--proxy=http --proxy_host=${PROXY_HOST_AND_PORT%:*} --proxy_port=${PROXY_HOST_AND_PORT##*:}"; \ + fi \ + && yes | $ANDROID_HOME/cmdline-tools/bin/sdkmanager $SDK_MANAGER_PROXY_OPTIONS --sdk_root=$ANDROID_HOME "platform-tools" "cmdline-tools;latest" + +RUN curl -ksS https://storage.googleapis.com/git-repo-downloads/repo | tee $ANDROID_HOME/cmdline-tools/bin/repo > /dev/null 2>&1 \ + && sudo chmod a+x $ANDROID_HOME/cmdline-tools/bin/repo + +FROM scratch AS android +COPY --from=androidbuild /opt/android-sdk /opt/android-sdk + +#------------------------------------------------------------------------ +# Dart +FROM base AS dartbuild + +ARG DART_VERSION=2.18.4 +WORKDIR /opt/ + +ENV DART_SDK=/opt/dart-sdk +ENV PATH=$PATH:$DART_SDK/bin + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN --mount=type=tmpfs,target=/dart \ + ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/) \ + && curl -o /dart/dart.zip -L https://storage.googleapis.com/dart-archive/channels/stable/release/$DART_VERSION/sdk/dartsdk-linux-$ARCH-release.zip \ + && unzip /dart/dart.zip + +FROM scratch AS dart +COPY --from=dartbuild /opt/dart-sdk /opt/dart-sdk + +#------------------------------------------------------------------------ +# SBT +FROM base AS scalabuild + +ARG SBT_VERSION=1.6.1 + +ENV SBT_HOME=/opt/sbt +ENV PATH=$PATH:$SBT_HOME/bin + +RUN curl -L https://github.com/sbt/sbt/releases/download/v$SBT_VERSION/sbt-$SBT_VERSION.tgz | tar -C /opt -xz + +FROM scratch AS scala +COPY --from=scalabuild /opt/sbt /opt/sbt + +#------------------------------------------------------------------------ +# SWIFT +FROM base AS swiftbuild + +ARG SWIFT_VERSION=5.8.1 + +ENV SWIFT_HOME=/opt/swift +ENV PATH=$PATH:$SWIFT_HOME/bin + +RUN mkdir -p $SWIFT_HOME \ + && echo $SWIFT_VERSION \ + && if [ "$(arch)" = "aarch64" ]; then \ + SWIFT_PACKAGE="ubuntu2204-aarch64/swift-$SWIFT_VERSION-RELEASE/swift-$SWIFT_VERSION-RELEASE-ubuntu22.04-aarch64.tar.gz"; \ + else \ + SWIFT_PACKAGE="ubuntu2204/swift-$SWIFT_VERSION-RELEASE/swift-$SWIFT_VERSION-RELEASE-ubuntu22.04.tar.gz"; \ + fi \ + && curl -L https://download.swift.org/swift-$SWIFT_VERSION-release/$SWIFT_PACKAGE \ + | tar -xz -C $SWIFT_HOME --strip-components=2 + +FROM scratch AS swift +COPY --from=swiftbuild /opt/swift /opt/swift + +#------------------------------------------------------------------------ +# DOTNET +FROM base AS dotnetbuild + +ARG DOTNET_VERSION=6.0 +ARG NUGET_INSPECTOR_VERSION=0.9.12 + +ENV DOTNET_HOME=/opt/dotnet +ENV NUGET_INSPECTOR_HOME=$DOTNET_HOME +ENV PATH=$PATH:$DOTNET_HOME:$DOTNET_HOME/tools:$DOTNET_HOME/bin + +# Note: We are not installing a dotnet package directly because +# debian packages from Ubuntu and Microsoft are incomplete + +RUN mkdir -p $DOTNET_HOME \ + && echo $SWIFT_VERSION \ + && if [ "$(arch)" = "aarch64" ]; then \ + curl -L https://aka.ms/dotnet/$DOTNET_VERSION/dotnet-sdk-linux-arm64.tar.gz | tar -C $DOTNET_HOME -xz; \ + else \ + curl -L https://aka.ms/dotnet/$DOTNET_VERSION/dotnet-sdk-linux-x64.tar.gz | tar -C $DOTNET_HOME -xz; \ + fi + +RUN mkdir -p $DOTNET_HOME/bin \ + && curl -L https://github.com/nexB/nuget-inspector/releases/download/v$NUGET_INSPECTOR_VERSION/nuget-inspector-v$NUGET_INSPECTOR_VERSION-linux-x64.tar.gz \ + | tar --strip-components=1 -C $DOTNET_HOME/bin -xz + +FROM scratch AS dotnet +COPY --from=dotnetbuild /opt/dotnet /opt/dotnet + +#------------------------------------------------------------------------ +# ORT +FROM base as ortbuild + +# Set this to the version ORT should report. +ARG ORT_VERSION="DOCKER-SNAPSHOT" + +WORKDIR $HOME/src/ort + +# Prepare Gradle +RUN --mount=type=cache,target=/var/tmp/gradle \ + --mount=type=bind,target=$HOME/src/ort,rw \ + export GRADLE_USER_HOME=/var/tmp/gradle \ + && sudo chown -R "$USER". $HOME/src/ort /var/tmp/gradle \ + && scripts/set_gradle_proxy.sh \ + && ./gradlew --no-daemon --stacktrace \ + -Pversion=$ORT_VERSION \ + :cli:installDist \ + :helper-cli:startScripts \ + && mkdir /opt/ort \ + && cp -a $HOME/src/ort/cli/build/install/ort /opt/ \ + && cp -a $HOME/src/ort/scripts/*.sh /opt/ort/bin/ \ + && cp -a $HOME/src/ort/helper-cli/build/scripts/orth /opt/ort/bin/ \ + && cp -a $HOME/src/ort/helper-cli/build/libs/helper-cli-*.jar /opt/ort/lib/ + +FROM scratch AS ortbin +COPY --from=ortbuild /opt/ort /opt/ort + +#------------------------------------------------------------------------ +# Main Minimal Runtime container +FROM base as run + +# Remove ort build scripts +RUN [ -d /etc/scripts ] && sudo rm -rf /etc/scripts + +# Install optional tool subversion for ORT analyzer +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + sudo apt-get update && \ + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends \ + subversion \ + && sudo rm -rf /var/lib/apt/lists/* + +RUN syft / --exclude '*/usr/share/doc' --exclude '*/etc' -o spdx-json --file /usr/share/doc/ort/ort-base.spdx.json + +# Python +ENV PYENV_ROOT=/opt/python +ENV PATH=$PATH:$PYENV_ROOT/shims:$PYENV_ROOT/bin +COPY --from=python --chown=$USER:$USER $PYENV_ROOT $PYENV_ROOT +RUN syft $PYENV_ROOT -o spdx-json --file /usr/share/doc/ort/ort-python.spdx.json + +# NodeJS +ARG NODEJS_VERSION=18.14.2 +ENV NVM_DIR=/opt/nvm +ENV PATH=$PATH:$NVM_DIR/versions/node/v$NODEJS_VERSION/bin +COPY --from=nodejs --chown=$USER:$USER $NVM_DIR $NVM_DIR +RUN syft $NVM_DIR -o spdx-json --file /usr/share/doc/ort/ort-nodejs.spdx.json + +# Rust +ENV RUST_HOME=/opt/rust +ENV CARGO_HOME=$RUST_HOME/cargo +ENV RUSTUP_HOME=$RUST_HOME/rustup +ENV PATH=$PATH:$CARGO_HOME/bin:$RUSTUP_HOME/bin +COPY --from=rust --chown=$USER:$USER $RUST_HOME $RUST_HOME +RUN chmod o+rwx $CARGO_HOME +RUN syft $RUST_HOME -o spdx-json --file /usr/share/doc/ort/ort-rust.spdx.json + +# Golang +ENV PATH=$PATH:/opt/go/bin +COPY --from=golang --chown=$USER:$USER /opt/go /opt/go +RUN syft /opt/go -o spdx-json --file /usr/share/doc/ort/ort-golang.spdx.json + +# Ruby +ENV RBENV_ROOT=/opt/rbenv/ +ENV GEM_HOME=/var/tmp/gem +ENV PATH=$PATH:$RBENV_ROOT/bin:$RBENV_ROOT/shims:$RBENV_ROOT/plugins/ruby-install/bin +COPY --from=ruby --chown=$USER:$USER $RBENV_ROOT $RBENV_ROOT +RUN syft $RBENV_ROOT -o spdx-json --file /usr/share/doc/ort/ort-ruby.spdx.json + +# ORT +COPY --from=ortbin --chown=$USER:$USER /opt/ort /opt/ort +ENV PATH=$PATH:/opt/ort/bin + +USER $USER +WORKDIR $HOME + +# Ensure that the ORT data directory exists to be able to mount the config into it with correct permissions. +RUN mkdir -p "$HOME/.ort" + +ENTRYPOINT ["/opt/ort/bin/ort"] diff --git a/scripts/custom_docker.sh b/scripts/custom_docker.sh index 0e08cefe4d50a..c6c8776df8ace 100755 --- a/scripts/custom_docker.sh +++ b/scripts/custom_docker.sh @@ -27,10 +27,10 @@ DOCKER_IMAGE_ROOT="${DOCKER_IMAGE_ROOT:-ghcr.io/oss-review-toolkit}" valid_components=("android" "swift" "sbt" "dart" "dotnet" "php" "haskell") # Define the Dockerfile template -dockerfile_template="FROM ghcr.io/oss-review-toolkit/ort\n" +dockerfile_template="FROM ${DOCKER_IMAGE_ROOT}/ort-minimal\n" # Default output file -output_file="Dockerfile.custom" +output_file="Dockerfile-custom" function usage() { echo "Usage: $0 -c [ ...] -o " diff --git a/scripts/docker_build.sh b/scripts/docker_build.sh index 91320671fe105..20af898b3689c 100755 --- a/scripts/docker_build.sh +++ b/scripts/docker_build.sh @@ -45,13 +45,17 @@ image_build() { shift docker buildx build \ - -f "$GIT_ROOT/Dockerfile" \ + -f "$GIT_ROOT/Dockerfile-minimal" \ --target "$target" \ --tag "${DOCKER_IMAGE_ROOT}/$name:$version" \ --tag "${DOCKER_IMAGE_ROOT}/$name:latest" \ "$@" . } +# Minimimal ORT image +# This is the base image for ORT and contains the minimal +# set of tools required to run ORT including main binaries. + # Base image_build base ort/base "${JAVA_VERSION}-jdk-${UBUNTU_VERSION}" \ --build-arg UBUNTU_VERSION="$UBUNTU_VERSION" \ @@ -104,6 +108,8 @@ image_build golang ort/golang "$GO_VERSION" \ image_build run ort "$ORT_VERSION" \ --build-arg ORT_VERSION="$ORT_VERSION" \ --build-arg NODEJS_VERSION="$NODEJS_VERSION" \ + --tag "ort-minimal:$ORT_VERSION" \ + --tag "ort-minimal:latest" \ --build-context "base=docker-image://${DOCKER_IMAGE_ROOT}/ort/base:latest" \ --build-context "python=docker-image://${DOCKER_IMAGE_ROOT}/ort/python:latest" \ --build-context "nodejs=docker-image://${DOCKER_IMAGE_ROOT}/ort/nodejs:latest" \ @@ -112,9 +118,6 @@ image_build run ort "$ORT_VERSION" \ --build-context "ruby=docker-image://${DOCKER_IMAGE_ROOT}/ort/ruby:latest" \ "$@" -# Build adjacent language containers if ALL_LANGUAGES is set. -[ -z "$ALL_LANGUAGES" ] && exit 0 - # Android # shellcheck disable=SC1091 image_build android ort/android "$ANDROID_CMD_VERSION" \ @@ -153,11 +156,15 @@ image_build haskell ort/haskell "$HASKELL_STACK_VERSION" \ --build-context "base=docker-image://${DOCKER_IMAGE_ROOT}/ort/base:latest" \ "$@" -# Runtime extended ORT image +# Main runtime ORT image +# This not using the image_build function as it needs to build +# from multiple images docker buildx build \ - --file Dockerfile-extended \ - --tag "${DOCKER_IMAGE_ROOT}/ort-extended:$ORT_VERSION" \ - --tag "${DOCKER_IMAGE_ROOT}/ort-extended:latest" \ + --file Dockerfile \ + --tag "${DOCKER_IMAGE_ROOT}/ort:$ORT_VERSION" \ + --tag "${DOCKER_IMAGE_ROOT}/ort:latest" \ + --tag "ort:$ORT_VERSION" \ + --tag "ort:latest" \ --build-arg ORT_VERSION="$ORT_VERSION" \ --build-context "ort=docker-image://${DOCKER_IMAGE_ROOT}/ort:${ORT_VERSION}" \ --build-context "sbt=docker-image://${DOCKER_IMAGE_ROOT}/ort/sbt:latest" \ @@ -168,4 +175,3 @@ docker buildx build \ --build-context "haskell=docker-image://${DOCKER_IMAGE_ROOT}/ort/haskell:latest" \ --build-context "scala=docker-image://${DOCKER_IMAGE_ROOT}/ort/scala:latest" \ "$@" . -