Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7734668166 | ||
|
|
d57e2ac46c | ||
|
|
062132487b | ||
|
|
bb3de8fd4e | ||
|
|
0d0eabf0fa | ||
|
|
61f00647f4 | ||
|
|
ce68a96440 | ||
|
|
1457177f6b | ||
|
|
b66f62a3f3 | ||
|
|
5e154cf654 | ||
|
|
fafb076f2b | ||
|
|
693afc76fd | ||
|
|
82653b4fba | ||
|
|
dc2dc84f4f | ||
|
|
db823ebe3f | ||
|
|
1ad119e7d2 | ||
|
|
816e8f5c12 | ||
|
|
39b44c9a08 | ||
|
|
029a7c3b38 | ||
|
|
5ed95e455c | ||
|
|
204c1da235 |
@@ -1,3 +1,9 @@
|
||||
### Logs
|
||||
**/logs/**
|
||||
|
||||
### Config/setup """
|
||||
*.env
|
||||
|
||||
### PyCharm ###
|
||||
.idea/
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
cache:
|
||||
key: blender-source
|
||||
paths:
|
||||
- /opt/blender-git/blender # Blender git repository source
|
||||
- /opt/blender-git/lib # Blender Subversion lib package
|
||||
policy: pull
|
||||
|
||||
update-cache:
|
||||
stage: .pre
|
||||
cache:
|
||||
key: blender-source
|
||||
image: stilobique/csv:latest
|
||||
script:
|
||||
- mkdir -p /opt/blender-git/lib
|
||||
- cd /opt/blender-git
|
||||
- git clone https://projects.blender.org/blender/blender.git
|
||||
- cd /opt/blender-git/blender
|
||||
- git submodule update --init --recursive
|
||||
- cd /opt/blender-git/lib
|
||||
- svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/linux_centos7_x86_64
|
||||
|
||||
build-dockerfile:
|
||||
image: docker:19.03.12
|
||||
rules:
|
||||
- changes:
|
||||
- build.json
|
||||
stage: build
|
||||
services:
|
||||
- docker:dind
|
||||
cache:
|
||||
key: blender-source
|
||||
script:
|
||||
- apk add python3
|
||||
- apk add py3-pip
|
||||
- python3 -m pip install --upgrade pip
|
||||
- python3 -m pip install -r requirement-build.txt
|
||||
- python3 main.py
|
||||
- python3 main.py --tag=latest
|
||||
Generated
+66
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
version="1.1"
|
||||
viewBox="0 0 181 148"
|
||||
xml:space="preserve"
|
||||
id="svg4"
|
||||
sodipodi:docname="blender-docker.svg"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
|
||||
id="defs4" /><sodipodi:namedview
|
||||
id="namedview4"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="5.2541436"
|
||||
inkscape:cx="90.404837"
|
||||
inkscape:cy="74.036803"
|
||||
inkscape:window-width="2648"
|
||||
inkscape:window-height="1350"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g4" />
|
||||
<title
|
||||
id="title1">Blender logo (without text)</title>
|
||||
<g
|
||||
transform="matrix(.281 0 0 .281 -41.8 -43.7)"
|
||||
id="g4"
|
||||
style="fill:#1c90ed;fill-opacity:1">
|
||||
<g
|
||||
transform="matrix(21.6 0 0 21.6 -4857 7665)"
|
||||
id="g1"
|
||||
style="fill:none;fill-opacity:1">
|
||||
<path
|
||||
d="m243-334c0.106-1.89 1.03-3.56 2.43-4.74 1.37-1.16 3.21-1.87 5.23-1.87 2.01 0 3.85 0.709 5.22 1.87 1.4 1.18 2.32 2.85 2.43 4.74 0.106 1.94-0.675 3.75-2.04 5.09-1.4 1.36-3.38 2.22-5.61 2.22s-4.22-0.854-5.61-2.22c-1.37-1.34-2.15-3.14-2.04-5.08z"
|
||||
style="fill-rule:nonzero;fill:none;fill-opacity:1"
|
||||
id="path1" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(11.1,0,0,11.1,-2215,4153)"
|
||||
id="g3"
|
||||
style="display:inline;fill:#1c90ed;fill-opacity:1">
|
||||
<path
|
||||
d="m 243,-334 c 0.106,-1.89 1.03,-3.56 2.43,-4.74 1.37,-1.16 3.21,-1.87 5.23,-1.87 2.01,0 3.85,0.709 5.22,1.87 1.4,1.18 2.32,2.85 2.43,4.74 0.106,1.94 -0.675,3.75 -2.04,5.09 -1.4,1.36 -3.38,2.22 -5.61,2.22 -2.23,0 -4.22,-0.854 -5.61,-2.22 -1.37,-1.34 -2.15,-3.14 -2.04,-5.08 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero"
|
||||
id="path2" />
|
||||
<path
|
||||
d="m 231,-330 c 0.013,0.74 0.249,2.18 0.603,3.3 0.744,2.38 2.01,4.58 3.76,6.51 1.8,1.99 4.02,3.59 6.58,4.73 2.69,1.19 5.61,1.8 8.64,1.8 3.03,-0.004 5.95,-0.624 8.64,-1.83 2.56,-1.15 4.78,-2.75 6.58,-4.75 1.76,-1.95 3.02,-4.15 3.76,-6.53 0.375,-1.2 0.612,-2.42 0.707,-3.64 0.093,-1.2 0.054,-2.41 -0.117,-3.62 -0.334,-2.35 -1.15,-4.56 -2.4,-6.56 -1.14,-1.85 -2.62,-3.46 -4.38,-4.82 l 0.004,-0.003 -17.7,-13.6 c -0.016,-0.012 -0.029,-0.025 -0.046,-0.036 -1.16,-0.892 -3.12,-0.889 -4.39,0.005 -1.29,0.904 -1.44,2.4 -0.29,3.34 l -0.005,0.005 7.39,6.01 -22.5,0.024 h -0.03 c -1.86,0.002 -3.65,1.22 -4,2.77 -0.364,1.57 0.9,2.88 2.84,2.88 l -0.003,0.007 11.4,-0.022 -20.4,15.6 c -0.026,0.019 -0.054,0.039 -0.078,0.058 -1.92,1.47 -2.54,3.92 -1.33,5.46 1.23,1.57 3.84,1.58 5.78,0.009 l 11.1,-9.1 c 0,0 -0.162,1.23 -0.149,1.96 z m 28.6,4.11 c -2.29,2.33 -5.5,3.66 -8.96,3.66 -3.47,0.006 -6.68,-1.3 -8.97,-3.63 -1.12,-1.14 -1.94,-2.44 -2.45,-3.83 -0.497,-1.37 -0.69,-2.82 -0.562,-4.28 0.121,-1.43 0.547,-2.8 1.23,-4.03 0.668,-1.21 1.59,-2.31 2.72,-3.24 2.23,-1.81 5.06,-2.8 8.02,-2.8 2.97,-0.004 5.8,0.969 8.03,2.78 1.13,0.924 2.05,2.02 2.72,3.23 0.683,1.23 1.11,2.59 1.23,4.03 0.126,1.46 -0.067,2.91 -0.564,4.28 -0.508,1.4 -1.33,2.7 -2.45,3.84 z"
|
||||
style="fill:#1c90ed;fill-opacity:1;fill-rule:nonzero"
|
||||
id="path3" />
|
||||
</g>
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata4"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:title>Blender logo (without text)</dc:title></cc:Work></rdf:RDF></metadata></svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -1,17 +1,21 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Make Blender Cache" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="blender-docker" />
|
||||
<configuration default="false" name="Automation Builder" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="rider.module" />
|
||||
<option name="ENV_FILES" value="$PROJECT_DIR$/config.env" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="SDK_NAME" value="Python 3.12 (BlenderDocker)" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="IS_MODULE_SDK" value="false" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/generate-image-repo.py" />
|
||||
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
||||
<option name="RUN_TOOL" value="" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
@@ -1,33 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build Blender" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="stilobique/blender:3.4.0" />
|
||||
<option name="buildArgs">
|
||||
<list>
|
||||
<DockerEnvVarImpl>
|
||||
<option name="name" value="b3d_vs_major" />
|
||||
<option name="value" value="3.4" />
|
||||
</DockerEnvVarImpl>
|
||||
<DockerEnvVarImpl>
|
||||
<option name="name" value="b3d_vs_minor" />
|
||||
<option name="value" value="0" />
|
||||
</DockerEnvVarImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="containerName" value="blender-latest" />
|
||||
<option name="sourceFilePath" value="image/Dockerfile-build-blender" />
|
||||
<option name="volumeBindings">
|
||||
<list>
|
||||
<DockerVolumeBindingImpl>
|
||||
<option name="containerPath" value="/moderlab-plugin" />
|
||||
<option name="hostPath" value="E:\Projects\Git\Blender-Moderlab-Config\addons\moderlab-plugin\moderlab-plugin" />
|
||||
</DockerVolumeBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
</settings>
|
||||
</deployment>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,26 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build BlenderDocker" type="docker-deploy" factoryName="dockerfile" server-name="Docker Desktop">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="stilobique/blender:4.5.11" />
|
||||
<option name="buildArgs">
|
||||
<list>
|
||||
<DockerEnvVarImpl>
|
||||
<option name="name" value="b3d_vs_major" />
|
||||
<option name="value" value="4.5" />
|
||||
</DockerEnvVarImpl>
|
||||
<DockerEnvVarImpl>
|
||||
<option name="name" value="b3d_vs_minor" />
|
||||
<option name="value" value="11" />
|
||||
</DockerEnvVarImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="containerName" value="blender-latest" />
|
||||
<option name="sourceFilePath" value="Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,27 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Clean docker Images " type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="rider.module" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="SDK_NAME" value="Python 3.12 (BlenderDocker)" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/" />
|
||||
<option name="IS_MODULE_SDK" value="false" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
||||
<option name="RUN_TOOL" value="" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/blender/misc.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,34 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Generate image" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="blender-docker" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<EXTENSION ID="net.ashald.envfile">
|
||||
<option name="IS_ENABLED" value="false" />
|
||||
<option name="IS_SUBST" value="false" />
|
||||
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
|
||||
<option name="IS_IGNORE_MISSING_FILES" value="false" />
|
||||
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
|
||||
<ENTRIES>
|
||||
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
|
||||
</ENTRIES>
|
||||
</EXTENSION>
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# Pinned to the exact Python version Blender's own CMake requires for this
|
||||
# release (build_files/cmake/Modules/FindPythonLibsUnix.cmake,
|
||||
# _PYTHON_VERSION_SUPPORTED) - a floating `python` tag drifts to whatever
|
||||
# "latest" currently is, which stops matching once it moves past what an
|
||||
# older/LTS Blender release hard-pins (it has no matching apt package to
|
||||
# install after the fact, unlike a missing library).
|
||||
ARG python_version=3.13
|
||||
FROM python:${python_version} AS b3dock
|
||||
|
||||
# Setup all software version request
|
||||
ARG b3d_vs_major=5.2
|
||||
ARG b3d_vs_minor=0
|
||||
|
||||
LABEL Author="stilobique"
|
||||
LABEL Title="Blender Docker for Unit Test"
|
||||
LABEL Maintainer="Aurelien Vaillant contact@aurelien-vaillant.net"
|
||||
|
||||
## 01. Start First stage to build blender
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y git git-lfs sudo
|
||||
|
||||
# Get source code
|
||||
RUN git clone --depth 1 --branch v${b3d_vs_major}.${b3d_vs_minor} \
|
||||
https://projects.blender.org/blender/blender.git /opt/blender
|
||||
|
||||
# Start build
|
||||
# install_linux_packages.py (default, no --all) skips a handful of packages
|
||||
# that are only provided via the precompiled-libs bundle or via --all:
|
||||
# libepoxy-dev, Boost (all components), OpenImageIO. --all itself is not an
|
||||
# option here: it also checks its own apt catalog for a python3-dev matching
|
||||
# [3.11, 3.13[, which fails on Debian trixie regardless of which Python the
|
||||
# base image runs (that check queries apt's package catalog, not the actual
|
||||
# interpreter on PATH). Since `make update` below skips the precompiled
|
||||
# bundle on Linux by default, these are needed from apt regardless - install
|
||||
# them explicitly instead.
|
||||
RUN cd /opt/blender/build_files/build_environment && \
|
||||
chmod a+x ./install_linux_packages.py && \
|
||||
python install_linux_packages.py && \
|
||||
apt-get install -y libepoxy-dev libboost-all-dev libopenimageio-dev libembree-dev libpugixml-dev && \
|
||||
pip install numpy cython && \
|
||||
cd /opt/blender && make update && make -j$(nproc)
|
||||
|
||||
# Discover Blender's *actual* runtime shared-library needs from the compiled
|
||||
# binary itself (ldd), instead of guessing from install_linux_packages.py
|
||||
# (that script only covers build-time deps; libSM/libICE were never listed
|
||||
# there but the binary needs them at runtime). Every resolved .so is mapped
|
||||
# back to the apt package that owns it, so stage 02 can install exactly that.
|
||||
RUN ldd /opt/build_linux/bin/blender | tee /dev/stderr | grep 'not found' && \
|
||||
(echo 'Unresolved libs in the build stage itself, investigate first' && exit 1) || true
|
||||
# `realpath` is required: /lib is a merged-usr symlink to /usr/lib, and dpkg's
|
||||
# file database is keyed on the canonical /usr/lib/... path (with the full
|
||||
# soname suffix, e.g. libX11.so.6.4.0) — querying the /lib/....so.6 symlink
|
||||
# path directly returns "no path found matching pattern".
|
||||
# These names are resolved against Debian (this stage's distro), but stage 02
|
||||
# installs them on Ubuntu - the two occasionally disagree on a package name
|
||||
# for the same library, and not just cosmetically: Debian's `libjpeg62-turbo`
|
||||
# provides libjpeg.so.62, but Ubuntu's identically-ABI-sounding
|
||||
# `libjpeg-turbo8` actually provides a DIFFERENT soname (libjpeg.so.8) -
|
||||
# Ubuntu ships the old libjpeg.so.62 ABI as a separate `libjpeg62` package.
|
||||
# Debian's generic `libxml2` is Ubuntu's soname-suffixed `libxml2-16`.
|
||||
# Remap the known cases here rather than in stage 02.
|
||||
RUN ldd /opt/build_linux/bin/blender \
|
||||
| awk '{print $3}' | grep '^/' | sort -u \
|
||||
| xargs -r realpath | sort -u \
|
||||
| xargs -r dpkg -S 2>/dev/null | cut -d: -f1 | tr ',' '\n' | sed 's/^ //' | sort -u \
|
||||
| sed -e 's/^libjpeg62-turbo$/libjpeg62/' -e 's/^libxml2$/libxml2-16/' \
|
||||
| tee /opt/build_linux/runtime_packages.txt
|
||||
|
||||
|
||||
## 02. Build optimissed image
|
||||
## Setup a Multistage optimisation
|
||||
FROM ubuntu:25.10 AS final
|
||||
|
||||
# Re-declared: ARGs before the first FROM only apply to that FROM line, not
|
||||
# to instructions in later stages.
|
||||
ARG python_version=3.13
|
||||
|
||||
# Install exactly the runtime packages ldd found the compiled binary needs
|
||||
# (see the b3dock stage above) instead of guessing from Blender's build-time
|
||||
# package list. Ubuntu and Debian share package names for these core libs.
|
||||
COPY --from=b3dock /opt/build_linux/runtime_packages.txt /tmp/runtime_packages.txt
|
||||
RUN apt-get update && \
|
||||
xargs -a /tmp/runtime_packages.txt apt-get install -y --no-install-recommends && \
|
||||
rm -rf /tmp/runtime_packages.txt /var/lib/apt/lists/*
|
||||
|
||||
# libpython<version>.so isn't an apt package: the b3dock base image builds
|
||||
# Python from source into /usr/local, so ldd/dpkg-S (above) can never find an
|
||||
# owning package for it - Ubuntu's apt only ships whatever Python versions it
|
||||
# currently defaults to, which won't match an older/LTS Blender's pin. Copy
|
||||
# the .so Blender actually linked against directly from the build stage.
|
||||
COPY --from=b3dock /usr/local/lib/libpython${python_version}.so.1.0 /usr/local/lib/libpython${python_version}.so.1.0
|
||||
RUN ldconfig
|
||||
|
||||
RUN useradd -m -s /bin/bash bld
|
||||
|
||||
USER bld
|
||||
COPY --from=b3dock /opt/build_linux/bin /opt/blender
|
||||
|
||||
# ARG b3d_vs_major
|
||||
# ENV B3D_ADDON_PATH="/home/bld/.config/blender/${b3d_vs_major}/scripts/addons"
|
||||
|
||||
# Working Directory setup
|
||||
WORKDIR /opt/blender
|
||||
@@ -1,14 +1,26 @@
|
||||
[](https://www.blender.org/download/)
|
||||
[](https://gitlab.com/stilobique/blender-docker/-/commits/main)
|
||||
[](https://www.python.org/)
|
||||
[](https://www.blender.org/download/)
|
||||
|
||||
|
||||
# Blender Docker
|
||||
This repository is an automated blender docker image file generated, it's usefully with blender addon unit test. To
|
||||
build a new specific image, you need to update the `build.json` file with the new version witched ; or
|
||||
This repository is an automated blender docker image file generated, it's usefully with blender addon unit test.
|
||||
|
||||
|
||||
# Adding an Addon
|
||||
# Building
|
||||
## Start your build
|
||||
You can use Invoke to easily start a build, a clean or more.
|
||||
```shell
|
||||
invoke --li
|
||||
```
|
||||
## Debug and logs
|
||||
Some log are generated inside a `logs` folder.
|
||||
- `build`: all operation on build docker file.
|
||||
- `clean`: from the dedicated function to clean all dockers images and cache.
|
||||
- `test`: simple class method to try a specific docker image.
|
||||
|
||||
## Check if the build work
|
||||
|
||||
# Use case
|
||||
## Adding an Addon
|
||||
Mount a new volume with your addon inside a folder (ex `/blender-plugin/plugin-archive.zip`), when you run your docker container add this volume and execute a script to add-it with the blender installed.
|
||||
|
||||
Python function to install an addon with Blender. The file his named `install.py`
|
||||
@@ -27,3 +39,38 @@ Call this function with blender inside this container
|
||||
#!/bin/sh
|
||||
/opt/blender/blender --background --python "install.py"
|
||||
````
|
||||
|
||||
# Check Image build
|
||||
```shell
|
||||
docker run --rm stilobique/blender:5.1.2 ./blender --version
|
||||
```
|
||||
|
||||
```shell
|
||||
# Taille de l'image
|
||||
docker image inspect stilobique/blender:5.1.2 --format='{{.Size}}' | numfmt --to=iec
|
||||
|
||||
# Dépendances manquantes
|
||||
docker run --rm --entrypoint /bin/bash stilobique/blender:5.1.2 -c 'ldd /opt/blender/blender | grep "not found" || echo "All deps OK"'
|
||||
|
||||
# Test fonctionnel
|
||||
docker run --rm stilobique/blender:5.1.2 ./blender -b --python-expr "import bpy; print('OK:', bpy.app.version_string)"
|
||||
```
|
||||
|
||||
|
||||
# CLI helper tasks
|
||||
Reusable helpers (`tasks.py`) are exposed as [invoke](https://www.pyinvoke.org/) tasks.
|
||||
|
||||
```shell
|
||||
# List available tasks
|
||||
invoke clean
|
||||
|
||||
# Clean Docker (all contexts: default, podman, ...)
|
||||
python -m blender.cli clean
|
||||
|
||||
# List Blender tags (Gitea)
|
||||
python -m blender.cli get-tags-release
|
||||
|
||||
# List stilobique/blender tags (Docker Hub)
|
||||
python -m blender.cli get-tags-docker
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import os
|
||||
import requests
|
||||
import tempfile
|
||||
import importlib.util
|
||||
|
||||
from blender.version import BlenderVersion
|
||||
|
||||
# "Wayland Protocols" has no "Library" in its name but is still a
|
||||
# build-critical dependency, so it's matched by name too.
|
||||
_EXTRA_PACKAGE_NAMES = {'wayland protocols'}
|
||||
|
||||
|
||||
class BlenderDependency:
|
||||
def __init__(self, blender: BlenderVersion):
|
||||
self._blender_version = blender
|
||||
self._url = rf'https://projects.blender.org/blender/blender/raw/tag/v{self._blender_version.tag_name()}/build_files/build_environment/install_linux_packages.py'
|
||||
self.module = self._get_source_file()
|
||||
|
||||
self.packages = list()
|
||||
self._get_list()
|
||||
|
||||
self.packages_complete = list()
|
||||
self._get_complete_list()
|
||||
|
||||
def _get_source_file(self):
|
||||
"""Download the Blender dependency script and import it at runtime."""
|
||||
r = requests.get(self._url)
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='wb', suffix='.py', delete=False) as t:
|
||||
t.write(r.content)
|
||||
path = t.name
|
||||
|
||||
try:
|
||||
spec = importlib.util.spec_from_file_location('install_linux_packages', path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
finally:
|
||||
os.remove(path)
|
||||
|
||||
def _get_list(self):
|
||||
"""Keep the mandatory 'library' packages (and Wayland Protocols) as Debian/Ubuntu apt names."""
|
||||
sources = self.module.BUILD_MANDATORY_SUBPACKAGES + self.module.DEPS_CRITICAL_SUBPACKAGES
|
||||
for package in self._flatten(sources):
|
||||
if 'library' not in package.name.lower() and package.name.lower() not in _EXTRA_PACKAGE_NAMES:
|
||||
continue
|
||||
name = package.distro_package_names.get(self.module.DISTRO_ID_DEBIAN)
|
||||
if isinstance(name, str):
|
||||
self.packages.append(name)
|
||||
|
||||
def _get_complete_list(self):
|
||||
"""All packages required to build Blender (PACKAGES_BASICS_BUILD) as Debian/Ubuntu apt names."""
|
||||
for package in self._flatten(self.module.PACKAGES_BASICS_BUILD):
|
||||
name = package.distro_package_names.get(self.module.DISTRO_ID_DEBIAN)
|
||||
if isinstance(name, str):
|
||||
self.packages_complete.append(name)
|
||||
|
||||
def _flatten(self, packages):
|
||||
"""Yield every leaf Package, descending into is_group sub_packages."""
|
||||
for package in packages:
|
||||
if package.is_group:
|
||||
yield from self._flatten(package.sub_packages)
|
||||
else:
|
||||
yield package
|
||||
|
||||
def __str__(self):
|
||||
return ' '.join(self.packages)
|
||||
|
||||
def complete_str(self):
|
||||
return ' '.join(self.packages_complete)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
bld = BlenderVersion(version='5.0.0')
|
||||
dep = BlenderDependency(blender=bld)
|
||||
|
||||
print('Show All packages:')
|
||||
print(dep.__str__())
|
||||
@@ -0,0 +1,264 @@
|
||||
import os
|
||||
import re
|
||||
import docker
|
||||
import logging
|
||||
import datetime
|
||||
import requests
|
||||
|
||||
from .version import BlenderVersion
|
||||
from .dependency import BlenderDependency
|
||||
from pathlib import Path
|
||||
from docker.errors import BuildError, APIError, ContainerError, ImageNotFound
|
||||
|
||||
|
||||
_ANSI_ESCAPE_RE = re.compile(r'\x1b\[[0-9;]*[a-zA-Z]')
|
||||
|
||||
|
||||
def _clean_log_line(text: str) -> str:
|
||||
"""Strip ANSI escape codes and keep only the last update of a \r-rewritten line."""
|
||||
text = _ANSI_ESCAPE_RE.sub('', text)
|
||||
return text.split('\r')[-1].strip()
|
||||
|
||||
|
||||
class BlenderDocker:
|
||||
def __init__(self, blender: BlenderVersion, severity: int = logging.WARNING):
|
||||
self._blender_version = blender
|
||||
# Todo get a user config
|
||||
self._docker_client = docker.DockerClient(base_url=f'unix:///var/run/docker.sock')
|
||||
self.login()
|
||||
self._docker_image = None
|
||||
self._repository = 'stilobique/blender'
|
||||
self._docker_image_name = self._blender_version.format_to_tag(self._repository)
|
||||
|
||||
self._docker_file = Path(os.getcwd(), 'Dockerfile')
|
||||
if not self._docker_file.exists():
|
||||
print(f'Dockerfile not found: {self._docker_file}')
|
||||
exit(1)
|
||||
|
||||
self._packages = BlenderDependency(blender)
|
||||
|
||||
self._args = {
|
||||
'b3d_vs_major': f'{self._blender_version.major}',
|
||||
'b3d_vs_minor': f'{self._blender_version.minor}.{self._blender_version.hotfix}',
|
||||
'b3d_dependency': self._packages.__str__(),
|
||||
'python_version': self._get_required_python_version(),
|
||||
}
|
||||
|
||||
self._severity = severity
|
||||
|
||||
def _get_required_python_version(self) -> str:
|
||||
"""
|
||||
Fetch the exact Python version (major.minor) Blender's own CMake pins for this
|
||||
release, so the build stage's base image can match it instead of drifting with
|
||||
whatever a floating `python` tag currently resolves to.
|
||||
"""
|
||||
url = (f'https://projects.blender.org/blender/blender/raw/tag/'
|
||||
f'v{self._blender_version.tag_name()}/build_files/cmake/Modules/FindPythonLibsUnix.cmake')
|
||||
r = requests.get(url)
|
||||
match = re.search(r'set\(_PYTHON_VERSION_SUPPORTED\s+([0-9]+\.[0-9]+)\)', r.text)
|
||||
if not match:
|
||||
print(f'Could not determine required Python version from {url}')
|
||||
exit(1)
|
||||
return match.group(1)
|
||||
|
||||
def _get_logger(self, name: str) -> logging.Logger:
|
||||
"""
|
||||
Private Method to set a logger for a specific method set (by his name)
|
||||
:param name: Make the logger file name.
|
||||
:return:
|
||||
"""
|
||||
log_dir = Path('logs')
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
logger = logging.getLogger(f'blender_docker.{name}')
|
||||
logger.setLevel(self._severity)
|
||||
logger.propagate = False
|
||||
|
||||
if not logger.handlers:
|
||||
handler = logging.FileHandler(log_dir / f'{name}.log')
|
||||
handler.setFormatter(logging.Formatter(
|
||||
'%(asctime)s | [%(levelname)s] %(message)s'
|
||||
))
|
||||
logger.addHandler(handler)
|
||||
|
||||
return logger
|
||||
|
||||
def login(self):
|
||||
"""Login to the Docker Hub"""
|
||||
try:
|
||||
print('Login to Hub Docker.')
|
||||
self._docker_client.login(
|
||||
username=os.environ['DOCKER_HUB_USER'],
|
||||
password=os.environ['DOCKER_HUB_PASSWORD']
|
||||
)
|
||||
|
||||
except APIError as e:
|
||||
print(f'Login failed with error: {e}')
|
||||
exit(1)
|
||||
|
||||
def build(self):
|
||||
"""Build the Blender Docker Image"""
|
||||
time = datetime.datetime.now()
|
||||
logger = self._get_logger(f'build-{time.strftime("%Y-%m-%d-%H-%M")}')
|
||||
collected_logs = []
|
||||
try:
|
||||
print('Building Blender Docker Image')
|
||||
logger.info('Building Blender Docker Image')
|
||||
logger.info(f'\tBuilds withs args: {self._args}')
|
||||
logger.info(f'\tTag generate: {self._docker_image_name}')
|
||||
|
||||
# Use the low-level API: images.build() only returns once the whole
|
||||
# build is finished, so it gives no live progress. api.build() with
|
||||
# decode=True streams each step (including cache hits) as it happens.
|
||||
build_logs = self._docker_client.api.build(
|
||||
path=os.getcwd(),
|
||||
# nocache=True,
|
||||
buildargs=self._args,
|
||||
tag=self._docker_image_name,
|
||||
rm=True,
|
||||
forcerm=True,
|
||||
decode=True,
|
||||
)
|
||||
|
||||
for chunk in build_logs:
|
||||
collected_logs.append(chunk)
|
||||
|
||||
if 'stream' in chunk:
|
||||
for raw_line in chunk['stream'].split('\n'):
|
||||
line = _clean_log_line(raw_line)
|
||||
if not line:
|
||||
continue
|
||||
if 'Using cache' in line:
|
||||
line = f'[CACHE] {line}'
|
||||
logger.info(line)
|
||||
|
||||
elif 'status' in chunk:
|
||||
status = _clean_log_line(chunk['status'])
|
||||
progress = _clean_log_line(chunk.get('progress', ''))
|
||||
line = f"{status} {chunk.get('id', '')} {progress}".strip()
|
||||
if 'Already exists' in status:
|
||||
line = f'[CACHE] {line}'
|
||||
logger.info(line)
|
||||
|
||||
elif 'error' in chunk:
|
||||
logger.error(chunk['error'])
|
||||
raise BuildError(chunk['error'], collected_logs)
|
||||
|
||||
self._docker_image = self._docker_client.images.get(self._docker_image_name)
|
||||
|
||||
except BuildError as e:
|
||||
logger.exception(f'Build docker image failed: {e}')
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
def tag(self):
|
||||
print('\tSet Tags version and/or Latest')
|
||||
pass
|
||||
|
||||
def test(self) -> bool:
|
||||
"""
|
||||
This method request an image (call the method build before) and try to execute the blender inside the container
|
||||
to check if the program can be correctly executed.
|
||||
Based on `docker run --rm stilobique/blender:5.1.2 ./blender --version`
|
||||
:return: True if no issue are returned
|
||||
"""
|
||||
logger = self._get_logger('test')
|
||||
container_name = f"Blender-Docker-Testing-{self._blender_version.tag_name_slugify()}"
|
||||
command = ['./blender', '--version']
|
||||
container = None
|
||||
try:
|
||||
print(f'Testing your Blender Docker image {self._docker_image_name}')
|
||||
logger.info(f'Testing image "{self._docker_image_name}" in container "{container_name}" '
|
||||
f'with command: {" ".join(command)}')
|
||||
|
||||
# auto_remove is intentionally NOT used: Docker can remove the container
|
||||
# right after it exits, racing with the logs() call below and turning a
|
||||
# real container-side error into an unrelated 409 "dead or marked for
|
||||
# removal" API error. We remove the container ourselves once logs are read.
|
||||
container = self._docker_client.containers.run(
|
||||
name=container_name,
|
||||
image=self._docker_image_name,
|
||||
command=command,
|
||||
detach=True,
|
||||
stdout=True,
|
||||
stderr=True,
|
||||
)
|
||||
result = container.wait()
|
||||
exit_code = result.get('StatusCode')
|
||||
|
||||
container_logs = container.logs(stdout=True, stderr=True).decode('utf-8', errors='replace').strip()
|
||||
for raw_line in container_logs.split('\n'):
|
||||
line = _clean_log_line(raw_line)
|
||||
if line:
|
||||
logger.info(f'[container] {line}')
|
||||
|
||||
if exit_code == 0:
|
||||
logger.info(f'Test succeeded (exit code {exit_code}) for image "{self._docker_image_name}".')
|
||||
return True
|
||||
|
||||
logger.error(f'Test failed (exit code {exit_code}) for image "{self._docker_image_name}".')
|
||||
print(f'Testing your Blender Docker image {self._docker_image_name} failed.')
|
||||
return False
|
||||
|
||||
except ContainerError as e:
|
||||
logger.exception(f'Container error while testing "{self._docker_image_name}": {e}')
|
||||
print(f'Container error: {e}')
|
||||
exit(1)
|
||||
|
||||
except ImageNotFound as e:
|
||||
logger.exception(f'Image "{self._docker_image_name}" not found: {e}')
|
||||
print(f'Image not found: {e}')
|
||||
exit(1)
|
||||
|
||||
except APIError as e:
|
||||
logger.exception(f'API error while testing "{self._docker_image_name}": {e}')
|
||||
print(f'API error: {e}')
|
||||
exit(1)
|
||||
|
||||
finally:
|
||||
if container is not None:
|
||||
try:
|
||||
container.remove(force=True)
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
def push(self):
|
||||
"""Push the Blender Docker Image"""
|
||||
time = datetime.datetime.now()
|
||||
logger = self._get_logger(f'push')
|
||||
collected_logs = []
|
||||
try:
|
||||
print(f'Pushing Blender Docker image {self._docker_image_name}')
|
||||
logger.info(f'Pushing Blender Docker Image')
|
||||
logger.info(f'\tTag pushed: {self._docker_image_name}')
|
||||
|
||||
# Use the low-level API: images.push() only returns once the whole
|
||||
# push is finished, so it gives no live progress. api.push() with
|
||||
# decode=True streams each layer's progress as it happens.
|
||||
push_logs = self._docker_client.api.push(
|
||||
repository=self._repository,
|
||||
tag=self._blender_version.tag_name(),
|
||||
stream=True,
|
||||
decode=True,
|
||||
)
|
||||
|
||||
for chunk in push_logs:
|
||||
collected_logs.append(chunk)
|
||||
|
||||
if 'status' in chunk:
|
||||
status = _clean_log_line(chunk['status'])
|
||||
progress = _clean_log_line(chunk.get('progress', ''))
|
||||
line = f"{status} {chunk.get('id', '')} {progress}".strip()
|
||||
if 'Layer already exists' in status:
|
||||
line = f'[CACHE] {line}'
|
||||
logger.info(line)
|
||||
|
||||
elif 'error' in chunk:
|
||||
logger.error(chunk['error'])
|
||||
raise APIError(chunk['error'])
|
||||
|
||||
logger.info(f'Push succeeded for image "{self._docker_image_name}".')
|
||||
|
||||
except APIError as e:
|
||||
logger.exception(f'Push docker image failed: {e}')
|
||||
raise
|
||||
@@ -0,0 +1,92 @@
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from subprocess import run, CalledProcessError
|
||||
|
||||
|
||||
def clean_all_dockers():
|
||||
"""
|
||||
Nettoie Docker pour tous les contextes disponibles (default, podman, ...).
|
||||
Equivalent a, pour chaque contexte :
|
||||
docker context use <context>
|
||||
docker system prune -a -f
|
||||
Puis remet le contexte d'origine en place a la fin.
|
||||
"""
|
||||
logs_dir = Path(os.getcwd(), 'logs')
|
||||
logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
logger = logging.getLogger('blender_docker.clean')
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.propagate = False
|
||||
if not logger.handlers:
|
||||
handler = logging.FileHandler(logs_dir / 'clean.log')
|
||||
handler.setFormatter(logging.Formatter(
|
||||
'%(asctime)s|%(name)s [%(levelname)s] %(message)s'
|
||||
))
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Contexte courant, pour le restaurer a la fin
|
||||
original_context = run(
|
||||
['docker', 'context', 'show'],
|
||||
capture_output=True, text=True, check=True
|
||||
).stdout.strip()
|
||||
logger.info(f'Contexte d\'origine: {original_context}')
|
||||
|
||||
# Liste de tous les contextes disponibles (format json, un objet par ligne)
|
||||
contexts_raw = run(
|
||||
['docker', 'context', 'ls', '--format', '{{json .}}'],
|
||||
capture_output=True, text=True, check=True
|
||||
).stdout.strip().splitlines()
|
||||
contexts = [json.loads(line)['Name'] for line in contexts_raw if line]
|
||||
|
||||
print(f'\tContextes trouves: {contexts}')
|
||||
logger.info(f'Contextes trouves: {contexts}')
|
||||
|
||||
for context in contexts:
|
||||
try:
|
||||
print(f'\tNettoyage du contexte: {context}')
|
||||
logger.info(f'Nettoyage du contexte: {context}')
|
||||
|
||||
run(['docker', 'context', 'use', context], check=True)
|
||||
|
||||
result = run(
|
||||
['docker', 'system', 'prune', '-a', '-f'],
|
||||
capture_output=True, text=True, check=True
|
||||
)
|
||||
|
||||
print(f'\t{result.stdout.strip()}')
|
||||
logger.info(result.stdout.strip())
|
||||
|
||||
except CalledProcessError as e:
|
||||
print(f'\tErreur sur le contexte {context}: {e.stderr.strip()}')
|
||||
logger.error(f'Erreur sur le contexte {context}: {e.stderr.strip()}')
|
||||
|
||||
# On remet le contexte d'origine
|
||||
run(['docker', 'context', 'use', original_context], check=True)
|
||||
print(f'\tContexte restaure: {original_context}')
|
||||
logger.info(f'Contexte restaure: {original_context}')
|
||||
|
||||
|
||||
def get_all_tags_from_blender():
|
||||
"""From the Gitea api, get all blender tags release"""
|
||||
r = requests.get(r"https://projects.blender.org/api/v1/repos/blender/blender/tags")
|
||||
print(r.text)
|
||||
j = r.json()
|
||||
|
||||
# All tags data:
|
||||
for release in j:
|
||||
print(release)
|
||||
|
||||
|
||||
def get_all_tags_from_docker():
|
||||
"""From the Gitea api, get all blender tags release"""
|
||||
r = requests.get(r"https://hub.docker.com/v2/namespaces/stilobique/repositories/blender/tags")
|
||||
print(r.text)
|
||||
j = r.json()
|
||||
|
||||
# All tags data:
|
||||
for release in j:
|
||||
print(release)
|
||||
@@ -0,0 +1,43 @@
|
||||
import re
|
||||
|
||||
|
||||
class BlenderVersion:
|
||||
def __init__(self, version: str = '5.1.0'):
|
||||
"""
|
||||
Need an object like 'X.Y.Z' to work correctly, build a pythonic object about a blender version.
|
||||
:param version:
|
||||
"""
|
||||
self._check_pattern(version)
|
||||
self.major : str = ''
|
||||
self.minor : str = ''
|
||||
self.hotfix : str = ''
|
||||
self.version_object(version)
|
||||
|
||||
def version_object(self, version: str):
|
||||
"""Set all version properties to a string"""
|
||||
version = version.split('.')
|
||||
self.major = version[0]
|
||||
self.minor = version[1]
|
||||
self.hotfix = version[2]
|
||||
|
||||
def format_to_tag(self, repository: str) -> str:
|
||||
"""From version information, format to return a string"""
|
||||
return f'{repository}:{self.major}.{self.minor}.{self.hotfix}'
|
||||
|
||||
def tag_name(self) -> str:
|
||||
"""Return the tag name 'latest', 'X.Y.Z'..."""
|
||||
return f'{self.major}.{self.minor}.{self.hotfix}'
|
||||
|
||||
def tag_name_slugify(self):
|
||||
return f'{self.major}-{self.minor}-{self.hotfix}'
|
||||
|
||||
@staticmethod
|
||||
def _check_pattern(tested: str):
|
||||
"""Simple test to look if the string give can be a blender version name."""
|
||||
test = re.match(r'^[0-9]{1}.[0-9]+.[0-9]+$', tested)
|
||||
if test is None:
|
||||
print(f'Bad version name set: {tested}')
|
||||
exit(1)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.major + '.' + self.minor + '.' + self.hotfix)
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"tags":
|
||||
[{
|
||||
"b3d_vs_major": 3.4,
|
||||
"b3d_vs_minor": 1
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.4,
|
||||
"b3d_vs_minor": 0
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.3,
|
||||
"b3d_vs_minor": 2
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.3,
|
||||
"b3d_vs_minor": 1
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.3,
|
||||
"b3d_vs_minor": 0
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.2,
|
||||
"b3d_vs_minor": 1
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.2,
|
||||
"b3d_vs_minor": 0
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.1,
|
||||
"b3d_vs_minor": 2
|
||||
},
|
||||
{
|
||||
"b3d_vs_major": 3.1,
|
||||
"b3d_vs_minor": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import docker
|
||||
import os
|
||||
|
||||
|
||||
def get_repo_container():
|
||||
"""
|
||||
- Check if a blender/csv image local exist
|
||||
- If yes, check if a container exist
|
||||
:return:
|
||||
"""
|
||||
client = docker.from_env()
|
||||
|
||||
if os.environ.get('docker_hub_password'):
|
||||
client.login(username=os.environ['docker_hub_user'], password=os.environ['docker_hub_password'])
|
||||
|
||||
dk_tags = 'stilobique/csv'
|
||||
dk_container_name = 'blender-cache-repo'
|
||||
dk_images_local = client.images.list(name=dk_tags)
|
||||
dk_containers_local = client.containers.list(filters={'label': dk_container_name})
|
||||
volumes = ["/scripts/:/scripts"]
|
||||
commandes = ['bash', '/scripts/set_all_repository.sh']
|
||||
|
||||
if dk_containers_local:
|
||||
# The container cache exist, used-it
|
||||
client.containers.run(image=dk_tags, name=dk_container_name)
|
||||
pass
|
||||
elif dk_images_local:
|
||||
# No container, but the image are build, start a container cache
|
||||
client.containers.run(image=dk_tags, name=dk_container_name)
|
||||
pass
|
||||
|
||||
else:
|
||||
# No container, no image ; build a new image and start this cache
|
||||
client.images.build(path="image", dockerfile="Dockerfile-csv", tag=f'{dk_tags}:latest', rm=True)
|
||||
client.containers.run(image=dk_tags, name=dk_container_name, volumes=volumes, command=commandes)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Make or update the docker container
|
||||
get_repo_container()
|
||||
print('Blender repo set')
|
||||
@@ -1,59 +0,0 @@
|
||||
FROM ubuntu:22.04 AS blender
|
||||
|
||||
# Setup all software version request
|
||||
ARG b3d_vs_major=2.90
|
||||
ARG b3d_vs_minor=0
|
||||
ARG subversion=63014
|
||||
|
||||
LABEL Author="stilobique"
|
||||
LABEL Title="Blender Docker for Unit Test"
|
||||
|
||||
ENV TZ=Europe/Paris
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
gcc \
|
||||
git \
|
||||
cmake \
|
||||
libc6-dev \
|
||||
libx11-dev \
|
||||
subversion \
|
||||
libxrandr-dev \
|
||||
libxcursor-dev \
|
||||
libxxf86vm-dev \
|
||||
libxinerama-dev \
|
||||
libglew-dev \
|
||||
libxi-dev \
|
||||
python3
|
||||
|
||||
# Debug
|
||||
RUN echo Build Blender v${b3d_vs_major}.${b3d_vs_minor}
|
||||
|
||||
ADD . /opt/blender-git
|
||||
|
||||
# Compile Blender
|
||||
RUN cd /opt/blender-git/ \
|
||||
&& git checkout v${b3d_vs_major}.${b3d_vs_minor} \
|
||||
&& git config --global user.email "contact@aurelien-vaillant.net" \
|
||||
&& git config --global user.name "Aurelien Vaillant" \
|
||||
&& mkdir /opt/blender-git/lib \
|
||||
&& cd /opt/blender-git/lib \
|
||||
&& svn checkout -r${subversion} \
|
||||
&& make
|
||||
|
||||
# Setup a Multistage optimisation
|
||||
FROM ubuntu:22.04
|
||||
COPY --from=blender /opt/blender-git/build_linux/bin /opt/blender
|
||||
ARG b3d_vs_major
|
||||
ENV B3D_ADDON_PATH "$HOME/.config/blender/${b3d_vs_major}/scripts/addons"
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libxi6 \
|
||||
libxxf86vm1 \
|
||||
libxrender1 \
|
||||
libgl1-mesa-glx
|
||||
|
||||
# Working Directory setup
|
||||
WORKDIR /
|
||||
@@ -1,7 +0,0 @@
|
||||
FROM alpine AS csv
|
||||
|
||||
LABEL Author="stilobique"
|
||||
LABEL Title="Linux image with subversion and git"
|
||||
|
||||
# Install dependencies
|
||||
RUN apk add git && apk add subversion
|
||||
@@ -1,65 +1,24 @@
|
||||
import os
|
||||
import pathlib
|
||||
import json
|
||||
import docker
|
||||
import sys
|
||||
from logging import INFO
|
||||
|
||||
# TODO Update readme file badge with blender version
|
||||
# TODO add a check if the image build are stored in the docker register
|
||||
from blender.version import BlenderVersion
|
||||
from blender.docker import BlenderDocker
|
||||
|
||||
|
||||
def get_data_from_json() -> (str, str):
|
||||
"""From the json file, get blender version (major and minor), and return this information."""
|
||||
file = pathlib.Path(os.getcwd(), 'build.json')
|
||||
|
||||
with open(file, 'r') as f:
|
||||
data = json.load(f)
|
||||
f.close()
|
||||
|
||||
version_values = data['tags'][0]
|
||||
major, minor = version_values['b3d_vs_major'], version_values['b3d_vs_minor']
|
||||
|
||||
return major, minor
|
||||
|
||||
|
||||
def build_docker(b3d_version: (str, str), latest: bool = False):
|
||||
"""
|
||||
Generate docker image, request the blender version (major, minor) with the keyword b3d_version, and can be
|
||||
tagged with latest or only blender version info.
|
||||
"""
|
||||
client = docker.from_env()
|
||||
if os.environ.get('docker_hub_password'):
|
||||
client.login(username=os.environ['docker_hub_user'], password=os.environ['docker_hub_password'])
|
||||
|
||||
# Init all data to build the docker image
|
||||
args = {
|
||||
'b3d_vs_major': str(b3d_version[0]),
|
||||
'b3d_vs_minor': str(b3d_version[1]),
|
||||
}
|
||||
docker_repo = 'stilobique/blender'
|
||||
if latest:
|
||||
tag = 'latest'
|
||||
else:
|
||||
tag = f'{args["b3d_vs_major"]}.{args["b3d_vs_minor"]}'
|
||||
completed_tag_name = f'{docker_repo}:{args["b3d_vs_major"]}.{args["b3d_vs_minor"]}'
|
||||
|
||||
print('\t1 -> Build from image file')
|
||||
client.images.build(path=os.getcwd(), buildargs=args, tag=completed_tag_name, rm=True, forcerm=True)
|
||||
|
||||
print(f'\t2 -> Push the new images with tag {tag}')
|
||||
push = client.images.push(repository=docker_repo, tag=tag, stream=True)
|
||||
print(f'\t\tDebug push :\n\t\t{push}')
|
||||
# Todo Update readme file badge with blender version
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
version = get_data_from_json()
|
||||
print(f'Start -> Setup the package with blender version "{version[0]}.{version[1]}"')
|
||||
for arg in sys.argv:
|
||||
if '--tag=' in arg:
|
||||
print(f'Build with the tag "{arg}".')
|
||||
build_docker(b3d_version=version, latest=True)
|
||||
break
|
||||
else:
|
||||
build_docker(b3d_version=version)
|
||||
print(f'Start to build the docker file.')
|
||||
pass
|
||||
version = BlenderVersion(input("Give the blender version (X.Y.Z): "))
|
||||
|
||||
print(f"Build a blender version {version}.")
|
||||
docker = BlenderDocker(blender=version, severity=INFO)
|
||||
docker.build()
|
||||
|
||||
print('Test your image.')
|
||||
test = docker.test()
|
||||
|
||||
if test:
|
||||
print('Test work, push this image.')
|
||||
docker.push()
|
||||
|
||||
# Todo: Add a latest tag, check if this version are the latest
|
||||
# Todo: Add a LTS tag, check if this version are a LTS
|
||||
@@ -1 +0,0 @@
|
||||
docker
|
||||
@@ -0,0 +1,3 @@
|
||||
docker==7.2.0
|
||||
requests==2.34.2
|
||||
invoke==3.0.3
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "------------------------------";
|
||||
echo " > Get the Blender repository";
|
||||
mkdir -p /opt/blender-git/lib
|
||||
cd /opt.blender-git/lib || exit 1
|
||||
git clone https://projects.blender.org/blender/blender.git
|
||||
|
||||
echo "------------------------------";
|
||||
echo " > Get all Blender submodule";
|
||||
cd /opt/blender-git/blender || exit 1
|
||||
git submodule update --init --recursive
|
||||
|
||||
echo "------------------------------";
|
||||
echo " > Get the all lib Blender (svn)";
|
||||
cd /opt/blender-git/lib || exit 1
|
||||
svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/linux_centos7_x86_64
|
||||
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
Invoke CLI entry point for the reusable helpers in `blender/misc.py`.
|
||||
Ex: python -m blender.cli clean
|
||||
Ex: python -m blender.cli get-tags-release
|
||||
"""
|
||||
|
||||
from invoke import Collection, Program, task
|
||||
|
||||
from blender.misc import clean_all_dockers, get_all_tags_from_blender, get_all_tags_from_docker
|
||||
|
||||
|
||||
@task(name='clean')
|
||||
def clean(ctx):
|
||||
"""Nettoie Docker pour tous les contextes disponibles (default, podman, ...)."""
|
||||
clean_all_dockers()
|
||||
|
||||
|
||||
@task(name='get-tags-release')
|
||||
def get_tags_release(ctx):
|
||||
"""Recupere tous les tags de release Blender depuis Gitea."""
|
||||
get_all_tags_from_blender()
|
||||
|
||||
|
||||
@task(name='get-tags-docker')
|
||||
def get_tags_docker(ctx):
|
||||
"""Recupere tous les tags de l'image Docker stilobique/blender depuis Docker Hub."""
|
||||
get_all_tags_from_docker()
|
||||
|
||||
|
||||
namespace = Collection(clean, get_tags_release, get_tags_docker)
|
||||
program = Program(namespace=namespace, version='0.1.0')
|
||||
|
||||
if __name__ == '__main__':
|
||||
program.run()
|
||||
Reference in New Issue
Block a user