diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d64062a5..c92f6428 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -5,7 +5,7 @@ on: - cron: '30 5 * * *' jobs: - make_docker_image: + make_docker_gui_debug_image: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -16,13 +16,35 @@ jobs: - name: Setup project environment run: make env - name: Make the build - run: make docker-save + run: | + make docker-gui-debug + make docker-save - name: Upload the build uses: actions/upload-artifact@v4 with: - name: docker_server(release) - path: build/docker/bombsquad_server_docker.tar + name: docker_gui(debug) + path: build/docker/bombsquad_gui_debug_docker.tar + make_docker_server_debug_image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Setup project environment + run: make env + - name: Make the build + run: | + make docker-server-debug + make docker-save + - name: Upload the build + uses: actions/upload-artifact@v4 + with: + name: docker_server(debug) + path: build/docker/bombsquad_server_debug_docker.tar + make_sphinx_docs: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 050ce036..356a19f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -208,7 +208,7 @@ jobs: allowUpdates: true artifacts: windows_x86_server_debug.tar - release_docker_image: + release_docker_gui_image: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -219,12 +219,38 @@ jobs: - name: Setup project environment run: make env - name: Make the build - run: make docker-save + run: | + make docker-gui-release + make docker-save + - name: Rename the build + run: mv build/docker/bombsquad_gui_release_docker.tar build/docker/bombsquad_docker_gui.tar - name: Upload the build uses: ncipollo/release-action@v1 with: allowUpdates: true - artifacts: build/docker/bombsquad_server_docker.tar + artifacts: build/docker/bombsquad_docker_gui.tar + + release_docker_server_image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Setup project environment + run: make env + - name: Make the build + run: | + make docker-server-release + make docker-save + - name: Rename the build + run: mv build/docker/bombsquad_server_release_docker.tar build/docker/bombsquad_docker_server.tar + - name: Upload the build + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifacts: build/docker/bombsquad_docker_server.tar release_sphinx_docs: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index cfe969d9..79fba828 100644 --- a/Makefile +++ b/Makefile @@ -1183,23 +1183,35 @@ clion-staging: assets-cmake resources meta # # ################################################################################ -# Build the docker image named bombsquad_server -docker-build: assets-cmake - $(PCOMMAND) build_docker +# Build the docker image +docker-gui-release: assets-cmake + $(PCOMMAND) build_docker_gui_release -# Run the bombsquad_server image -docker-run: - docker run -it bombsquad_server +# Build the docker image +docker-gui-debug: assets-cmake + $(PCOMMAND) build_docker_gui_debug + +# Build the docker image +docker-server-release: assets-cmake + $(PCOMMAND) build_docker_server_release, + +# Build the docker image +docker-server-debug: assets-cmake + $(PCOMMAND) build_docker_server_debug + +# Build the docker image for arm64 +docker-arm64-gui-release: assets-cmake + $(PCOMMAND) build_docker_arm64 # Save the bombsquad_server docker image to build/docker/bombsquad_server_docker.tar -docker-save: docker-build +docker-save: mkdir -p build/docker/ - docker save bombsquad_server -o build/docker/bombsquad_server_docker.tar + $(PCOMMAND) save_docker_images # Cleanup docker files docker-clean: - rm build/docker/bombsquad_server_docker.tar - docker rmi bombsquad_server --force + rm -rf build/docker/ + $(PCOMMAND) remove_docker_images docker system prune diff --git a/config/docker/Dockerfile b/config/docker/Dockerfile index 957ad891..f6d54d7c 100644 --- a/config/docker/Dockerfile +++ b/config/docker/Dockerfile @@ -1,21 +1,24 @@ # if provided it will make debug build ARG cmake_build_type=Release - -# system to start with the build with -# currently will break for non ubuntu system -ARG base_image=ubuntu:24.04 +# whether to make GUI or headless build (defaults to headless) +ARG headless_build=1 +# system to start with the build with +# currently will break for other images +ARG base_image=ubuntu:latest #-------------------------------BUILDER-------------------------------- # Start with the base image FROM ${base_image} AS builder # Renew the arg +ARG headless_build ARG cmake_build_type ENV LANG en_US.utf8 ENV LANGUAGE=en_US ENV DEBIAN_FRONTEND=noninteractive ENV CMAKE_BUILD_TYPE=${cmake_build_type} +ENV HEADLESS_BUILD=${headless_build} # Install build dependencies RUN apt-get update -y && \ @@ -24,25 +27,31 @@ RUN apt-get update -y && \ python3.12-venv \ python3-pip \ libsdl2-dev \ - libvorbisfile3 \ - freeglut3-dev \ + libglut-dev \ libopenal-dev \ + libvorbis-dev \ make \ curl \ rsync \ clang-format \ - cmake \ - libvorbis-dev + cmake # Copy source code -COPY ./ /home/ubuntu/ballistica +COPY ./ /ballistica -WORKDIR /home/ubuntu/ballistica +WORKDIR /ballistica # Compile the application -RUN make cmake-server-build \ - && mkdir ./../ballistica_cmake_server \ - && mv build/cmake/* ./../ballistica_cmake_server +RUN mkdir /ballistica_cmake && \ + if [ "$HEADLESS_BUILD" != "0" ]; then \ + make cmake-server-build && \ + mv build/cmake/*/ballisticakit_headless build/cmake/*/staged/dist; \ + else \ + make cmake-build && \ + mv build/cmake/*/ballisticakit build/cmake/*/staged/; \ + fi && \ + mv build/cmake/*/staged/* /ballistica_cmake + #-------------------------------RUNNER-------------------------------- # Create a new stage for the runtime environment @@ -53,33 +62,36 @@ ENV LANGUAGE=en_US ENV DEBIAN_FRONTEND=noninteractive # Renew the arg +ARG headless_build +ENV HEADLESS_BUILD=${headless_build} ARG cmake_build_type -LABEL BUILD_TYPE=${cmake_build_type} -ARG bombsquad_build=N/A -LABEL BOMBSQUAD_BUILD=${bombsquad_build} - -ARG bombsquad_version=N/A -LABEL BOMBSQUAD_VERSION=${bombsquad_version} +LABEL BOMBSQUAD_BUILD_TYPE=${cmake_build_type} # Install runtime dependencies RUN apt-get update -y && \ apt-get install -y \ - python3.12-dev \ - && rm -rf /var/lib/apt/lists/* \ - && python3.12 -c "import uuid;print(uuid.uuid4())">/etc/machine-id + python3.12-dev && \ + if [ "$HEADLESS_BUILD" = "0" ]; then \ + apt-get install -y \ + libsdl2-dev \ + libvorbis-dev \ + libglut-dev \ + libopenal-dev; \ + fi && \ + rm -rf /var/lib/apt/lists/* && \ + dbus-uuidgen > /etc/machine-id # Copy the compiled application from the builder stage -COPY --from=builder /home/ubuntu/ballistica_cmake_server/*/staged \ +COPY --from=builder /ballistica_cmake \ /home/ubuntu/ballistica -# ballisticakit_headless in staged is a symlink -COPY --from=builder /home/ubuntu/ballistica_cmake_server/*/ballisticakit_headless \ - /home/ubuntu/ballistica/dist WORKDIR /home/ubuntu/ballistica +RUN ln -s ballisticakit* run + # Expose the necessary port -EXPOSE 43210/udp +EXPOSE 43210/udp # Set the default command to run the application -CMD [ "./ballisticakit_server" ] \ No newline at end of file +CMD [ "./run" ] \ No newline at end of file diff --git a/tools/batools/build.py b/tools/batools/build.py index 940d8d19..bb0bf65c 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -644,59 +644,3 @@ def cmake_prep_dir(dirname: str, verbose: bool = False) -> None: else: if verbose: print(f'{Clr.BLD}{title}:{Clr.RST} Keeping existing build dir.') - - -def _docker_build( - image_name: str, - dockerfile_dir: str, - bombsquad_version: str | None = None, - bombsquad_build: str | int | None = None, - cmake_build_type: str | None = None, -) -> None: - - build_cmd = [ - 'docker', - 'image', - 'build', - '-t', - image_name, - '-f', - dockerfile_dir, - '.', - ] - if bombsquad_version is not None: - build_cmd = build_cmd + [ - '--build-arg', - f'bombsquad_version={bombsquad_version}', - ] - if bombsquad_build is not None: - build_cmd = build_cmd + [ - '--build-arg', - f'bombsquad_build={str(bombsquad_build)}', - ] - if cmake_build_type is not None: - build_cmd = build_cmd + [ - '--build-arg', - f'cmake_build_type={cmake_build_type}', - ] - subprocess.run(build_cmd, check=True) - - -def docker_build() -> None: - """Build docker image.""" - # todo: add option to toggle between prefab and cmake - from batools import version - - version_num, build_num = version.get_current_version() - image_name = 'bombsquad_server' - - print( - f'Building docker image {image_name}' - + 'version {version_num}:{build_num}' - ) - _docker_build( - image_name, - 'config/docker/Dockerfile', - version_num, - build_num, - ) diff --git a/tools/batools/docker.py b/tools/batools/docker.py new file mode 100644 index 00000000..68d6c5d6 --- /dev/null +++ b/tools/batools/docker.py @@ -0,0 +1,173 @@ +# Released under the MIT License. See LICENSE for details. +# +"""General functionality related to docker builds.""" + +import subprocess + + +def _docker_build( + image_name: str, + dockerfile_dir: str, + cmake_build_type: str | None = None, + labels: dict[str, str] | None = None, + platform: str | None = None, + headless_build: bool | str | None = None, +) -> None: + + build_cmd = [ + 'docker', + 'buildx', + 'build', + '--tag', + image_name, + '--file', + dockerfile_dir, + '--load', + '.', + ] + + if cmake_build_type is not None: + build_cmd = build_cmd + [ + '--build-arg', + f'cmake_build_type={cmake_build_type}', + ] + if headless_build is not None: + if headless_build: + headless_build = '1' + else: + headless_build = '0' + build_cmd = build_cmd + [ + '--build-arg', + f'headless_build={headless_build}', + ] + if platform is not None: + build_cmd = build_cmd + [ + '--platform', + platform, + ] + if labels is not None: + build_cmd = build_cmd + [ + f'--label={i}={labels[i]}' for i in labels.keys() + ] + subprocess.run(build_cmd, check=True) + + +def docker_build( + platform: str | None = 'linux/amd64', + headless_build: bool | str | None = None, + build_type: str | None = None, +) -> None: + """Build docker image. + platform == 'linux/arm64' or platform == 'linux/amd64'""" + from batools import version + + version_num, build_num = version.get_current_version() + if headless_build is None: + headless_build = True + if build_type is None: + build_type = 'Release' + + image_name = get_docker_image_name( + headless_build=headless_build, build_type=build_type + ) + + if platform is not None and 'arm64' in platform: + config_file = 'config/docker/Dockerfile_arm64' + else: + config_file = 'config/docker/Dockerfile' + + print( + f'Building docker image {image_name} ' + + f'version {version_num}:{build_num}' + ) + + _docker_build( + image_name, + config_file, + labels={ + 'bombsquad_version': version_num, + 'bombsquad_build': str(build_num), + }, + platform=platform, + headless_build=headless_build, + cmake_build_type=build_type, + ) + + +def get_docker_image_name(headless_build: bool | str, build_type: str) -> str: + """Get name of docker images in predefined format.""" + name = 'bombsquad' + if headless_build: + name += '_server' + else: + name += '_gui' + if 'release' in build_type.lower(): + name += '_release' + else: + name += '_debug' + return name + + +def docker_save_images() -> None: + """Saves bombsquad images loaded into docker.""" + output = subprocess.run( + ['docker', 'images'], capture_output=True, text=True, check=True + ) + save_cmd = ['docker', 'save', '-o'] + # we expect this directory is already present from Makefile + build_save_dir = 'build/docker/' + + img_name = get_docker_image_name(headless_build=True, build_type='Release') + if img_name in output.stdout: + subprocess.run( + save_cmd + [build_save_dir + img_name + '_docker.tar', img_name], + check=True, + ) + + img_name = get_docker_image_name(headless_build=True, build_type='Debug') + if img_name in output.stdout: + subprocess.run( + save_cmd + [build_save_dir + img_name + '_docker.tar', img_name], + check=True, + ) + + img_name = get_docker_image_name(headless_build=False, build_type='Release') + if img_name in output.stdout: + subprocess.run( + save_cmd + [build_save_dir + img_name + '_docker.tar', img_name], + check=True, + ) + + img_name = get_docker_image_name(headless_build=False, build_type='Debug') + if img_name in output.stdout: + subprocess.run( + save_cmd + [build_save_dir + img_name + '_docker.tar', img_name], + check=True, + ) + + +def docker_remove_images() -> None: + """Remove the bombsquad images loaded in docker.""" + output = subprocess.run( + ['docker', 'images'], capture_output=True, text=True, check=True + ) + remove_cmd = [ + 'docker', + 'rmi', + ] + + img_name = get_docker_image_name(headless_build=True, build_type='Release') + if img_name in output.stdout: + subprocess.run(remove_cmd + [img_name], check=True) + + img_name = get_docker_image_name(headless_build=True, build_type='Debug') + if img_name in output.stdout: + subprocess.run(remove_cmd + [img_name], check=True) + + img_name = get_docker_image_name(headless_build=False, build_type='Release') + if img_name in output.stdout: + subprocess.run(remove_cmd + [img_name], check=True) + + img_name = get_docker_image_name(headless_build=False, build_type='Debug') + if img_name in output.stdout: + subprocess.run(remove_cmd + [img_name], check=True) diff --git a/tools/batools/pcommandmain.py b/tools/batools/pcommandmain.py index 581af8d8..d50fa1f1 100644 --- a/tools/batools/pcommandmain.py +++ b/tools/batools/pcommandmain.py @@ -104,7 +104,14 @@ from batools.pcommands import ( ensure_prefab_platform, prefab_run_var, prefab_binary_path, - build_docker, + build_docker_gui_release, + build_docker_gui_debug, + build_docker_server_release, + build_docker_server_debug, + build_docker_arm64_gui_release, + build_docker_arm64_server_release, + save_docker_images, + remove_docker_images, make_prefab, lazybuild, efro_gradle, diff --git a/tools/batools/pcommands.py b/tools/batools/pcommands.py index d5a08277..f8f85203 100644 --- a/tools/batools/pcommands.py +++ b/tools/batools/pcommands.py @@ -9,6 +9,7 @@ import sys from efrotools import pcommand +# pylint: disable=too-many-lines def prune_includes() -> None: """Check for unnecessary includes in C++ files. @@ -667,11 +668,60 @@ def prefab_binary_path() -> None: ) -def build_docker() -> None: - """Build the docker image with bombsquad cmake server.""" - import batools.build +def build_docker_gui_release() -> None: + """Build the docker image with bombsquad cmake gui.""" + import batools.docker - batools.build.docker_build() + batools.docker.docker_build(headless_build=False) + + +def build_docker_gui_debug() -> None: + """Build the docker image with bombsquad debug cmake gui.""" + import batools.docker + + batools.docker.docker_build(headless_build=False, build_type='Debug') + + +def build_docker_server_release() -> None: + """Build the docker image with bombsquad cmake server.""" + import batools.docker + + batools.docker.docker_build() + + +def build_docker_server_debug() -> None: + """Build the docker image with bombsquad debug cmake server.""" + import batools.docker + + batools.docker.docker_build(build_type='Debug') + + +def build_docker_arm64_gui_release() -> None: + """Build the docker image with bombsquad cmake for arm64.""" + import batools.docker + + batools.docker.docker_build(headless_build=False, platform='linux/arm64') + + +def build_docker_arm64_server_release() -> None: + """Build the docker image with bombsquad cmake server for arm64.""" + import batools.docker + + batools.docker.docker_build(platform='linux/arm64') + + +def save_docker_images() -> None: + """Saves bombsquad images loaded into docker.""" + import batools.docker + + batools.docker.docker_save_images() + + +def remove_docker_images() -> None: + """Remove the bombsquad images loaded in docker.""" + import batools.docker + + batools.docker.docker_remove_images() def make_prefab() -> None: