Compare commits

5 Commits
Author SHA1 Message Date
stilobique 7734668166 Build, test and push 2026-07-24 23:50:12 +02:00
stilobique d57e2ac46c Fix log with test 2026-07-24 10:58:45 +02:00
stilobique 062132487b Make a basic setup with invoke.
Fix log information.
Remove unused script file.
2026-07-24 09:53:36 +02:00
stilobique bb3de8fd4e Small update about the 2026-07-23 14:27:08 +02:00
stilobique 0d0eabf0fa Add api about the gitea/docker tags get 2026-07-21 23:53:21 +02:00
12 changed files with 400 additions and 106 deletions
+2 -1
View File
@@ -8,8 +8,9 @@
<env name="PYTHONUNBUFFERED" value="1" /> <env name="PYTHONUNBUFFERED" value="1" />
</envs> </envs>
<option name="SDK_HOME" value="" /> <option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Python 3.12 (BlenderDocker)" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> <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_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" /> <option name="ADD_SOURCE_ROOTS" value="true" />
<option name="DEBUG_JUST_MY_CODE" value="false" /> <option name="DEBUG_JUST_MY_CODE" value="false" />
+2 -1
View File
@@ -8,8 +8,9 @@
<env name="PYTHONUNBUFFERED" value="1" /> <env name="PYTHONUNBUFFERED" value="1" />
</envs> </envs>
<option name="SDK_HOME" value="" /> <option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Python 3.12 (BlenderDocker)" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/" /> <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_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" /> <option name="ADD_SOURCE_ROOTS" value="true" />
<option name="DEBUG_JUST_MY_CODE" value="false" /> <option name="DEBUG_JUST_MY_CODE" value="false" />
+72 -16
View File
@@ -1,4 +1,11 @@
FROM ubuntu:25.10 AS b3dock # 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 # Setup all software version request
ARG b3d_vs_major=5.2 ARG b3d_vs_major=5.2
@@ -8,32 +15,81 @@ LABEL Author="stilobique"
LABEL Title="Blender Docker for Unit Test" LABEL Title="Blender Docker for Unit Test"
LABEL Maintainer="Aurelien Vaillant contact@aurelien-vaillant.net" LABEL Maintainer="Aurelien Vaillant contact@aurelien-vaillant.net"
#ENV TZ=Europe/Paris
#RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
## 01. Start First stage to build blender ## 01. Start First stage to build blender
# Install dependencies # Install dependencies
RUN apt-get update && apt-get install -y git git-lfs python3 sudo RUN apt-get update && apt-get install -y git git-lfs sudo
# Compile Blender # Get source code
RUN git clone --depth 1 --branch v${b3d_vs_major}.${b3d_vs_minor} \ RUN git clone --depth 1 --branch v${b3d_vs_major}.${b3d_vs_minor} \
https://projects.blender.org/blender/blender.git /opt/blender && \ https://projects.blender.org/blender/blender.git /opt/blender
chmod a+x /opt/blender/build_files/build_environment/install_linux_packages.py && \
python3 /opt/blender/build_files/build_environment/install_linux_packages.py
RUN cd /opt/blender && \ # Start build
make update && \ # install_linux_packages.py (default, no --all) skips a handful of packages
make -j$(nproc) # 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 ## 02. Build optimissed image
## Setup a Multistage optimisation ## Setup a Multistage optimisation
FROM ubuntu:25.10 AS final FROM ubuntu:25.10 AS final
#COPY --from=b3dock /opt/blender/build_files/build_environment/packages.txt /tmp/packages.txt # Re-declared: ARGs before the first FROM only apply to that FROM line, not
COPY --from=b3dock /opt/blender/build_files/build_environment/install_linux_packages.py /tmp/install_linux_packages.py # to instructions in later stages.
RUN apt-get update && apt-get install -y python3 sudo ARG python_version=3.13
RUN python3 /tmp/install_linux_packages.py
# 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 RUN useradd -m -s /bin/bash bld
+33 -6
View File
@@ -5,7 +5,22 @@
This repository is an automated blender docker image file generated, it's usefully with blender addon unit test. 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. 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` Python function to install an addon with Blender. The file his named `install.py`
@@ -42,8 +57,20 @@ docker run --rm stilobique/blender:5.1.2 ./blender -b --python-expr "import bpy;
``` ```
# Logs # CLI helper tasks
Some log are generated inside a `logs` folder. Reusable helpers (`tasks.py`) are exposed as [invoke](https://www.pyinvoke.org/) tasks.
- `build`: all operation on build docker file.
- `clean`: from the dedicated function to clean all dockers images and cache. ```shell
- `test`: simple class method to try a specific docker image. # 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
```
+78
View File
@@ -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__())
+124 -25
View File
@@ -1,12 +1,25 @@
import os import os
import re
import docker import docker
import logging import logging
import datetime
import requests
from .version import BlenderVersion from .version import BlenderVersion
from .dependency import BlenderDependency
from pathlib import Path from pathlib import Path
from docker.errors import BuildError, APIError, ContainerError, ImageNotFound 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: class BlenderDocker:
def __init__(self, blender: BlenderVersion, severity: int = logging.WARNING): def __init__(self, blender: BlenderVersion, severity: int = logging.WARNING):
self._blender_version = blender self._blender_version = blender
@@ -22,13 +35,32 @@ class BlenderDocker:
print(f'Dockerfile not found: {self._docker_file}') print(f'Dockerfile not found: {self._docker_file}')
exit(1) exit(1)
self._packages = BlenderDependency(blender)
self._args = { self._args = {
'b3d_vs_major': f'{self._blender_version.major}', 'b3d_vs_major': f'{self._blender_version.major}',
'b3d_vs_minor': f'{self._blender_version.minor}.{self._blender_version.hotfix}', '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 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: def _get_logger(self, name: str) -> logging.Logger:
""" """
Private Method to set a logger for a specific method set (by his name) Private Method to set a logger for a specific method set (by his name)
@@ -66,39 +98,56 @@ class BlenderDocker:
def build(self): def build(self):
"""Build the Blender Docker Image""" """Build the Blender Docker Image"""
logger = self._get_logger('build') time = datetime.datetime.now()
logger = self._get_logger(f'build-{time.strftime("%Y-%m-%d-%H-%M")}')
collected_logs = []
try: try:
print('Building Blender Docker Image') print('Building Blender Docker Image')
logger.info('Building Blender Docker Image') logger.info('Building Blender Docker Image')
logger.info(f'\tBuilds withs args: {self._args}') logger.info(f'\tBuilds withs args: {self._args}')
logger.info(f'\tTag generate: {self._docker_image_name}') logger.info(f'\tTag generate: {self._docker_image_name}')
self._docker_image, build_logs = self._docker_client.images.build( # 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(), path=os.getcwd(),
# nocache=True, # nocache=True,
buildargs=self._args, buildargs=self._args,
tag=self._docker_image_name, tag=self._docker_image_name,
quiet=False,
rm=True, rm=True,
forcerm=True forcerm=True,
decode=True,
) )
# Debug log:
for chunk in build_logs: for chunk in build_logs:
collected_logs.append(chunk)
if 'stream' in chunk: if 'stream' in chunk:
line = chunk['stream'].strip() for raw_line in chunk['stream'].split('\n'):
if line: line = _clean_log_line(raw_line)
logger.debug(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: elif 'error' in chunk:
logger.error(chunk['error']) 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: except BuildError as e:
logger.exception(f'Build docker image failed: {e}') logger.exception(f'Build docker image failed: {e}')
for line in e.build_log:
if 'stream' in line:
logger.debug(line['stream'].strip())
raise raise
@staticmethod @staticmethod
@@ -114,52 +163,102 @@ class BlenderDocker:
:return: True if no issue are returned :return: True if no issue are returned
""" """
logger = self._get_logger('test') logger = self._get_logger('test')
container_name = f"Blender-Docker-Testing-{self._blender_version.tag_name_slugify()}"
command = ['./blender', '--version']
container = None
try: try:
print(f'Testing your Blender Docker image {self._docker_image_name}') print(f'Testing your Blender Docker image {self._docker_image_name}')
logger.info(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)}')
test = self._docker_client.containers.run( # auto_remove is intentionally NOT used: Docker can remove the container
name=f"Blender-Docker-Testing-{self._blender_version.tag_name_slugify()}", # 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, image=self._docker_image_name,
command=['./blender', '--version'], command=command,
auto_remove=True,
remove=True,
detach=True, detach=True,
stdout=True, stdout=True,
stderr=True, stderr=True,
stream=True,
) )
result = test.wait() result = container.wait()
exit_code = result.get('StatusCode') exit_code = result.get('StatusCode')
logger.info(f'Exit code return: {exit_code}') container_logs = container.logs(stdout=True, stderr=True).decode('utf-8', errors='replace').strip()
logger.info(test.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: if exit_code == 0:
logger.info(f'Test succeeded (exit code {exit_code}) for image "{self._docker_image_name}".')
return True 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.') print(f'Testing your Blender Docker image {self._docker_image_name} failed.')
return False return False
except ContainerError as e: except ContainerError as e:
logger.exception(f'Container error while testing "{self._docker_image_name}": {e}')
print(f'Container error: {e}') print(f'Container error: {e}')
exit(1) exit(1)
except ImageNotFound as e: except ImageNotFound as e:
logger.exception(f'Image "{self._docker_image_name}" not found: {e}')
print(f'Image not found: {e}') print(f'Image not found: {e}')
exit(1) exit(1)
except APIError as e: except APIError as e:
logger.exception(f'API error while testing "{self._docker_image_name}": {e}')
print(f'API error: {e}') print(f'API error: {e}')
for line in e.build_log:
if 'stream' in line:
print(line['stream'].strip())
exit(1) exit(1)
finally:
if container is not None:
try:
container.remove(force=True)
except APIError:
pass
def push(self): def push(self):
self._docker_client.images.push( """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, repository=self._repository,
tag=self._blender_version.tag_name(), tag=self._blender_version.tag_name(),
stream=True, 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
+21 -2
View File
@@ -1,6 +1,7 @@
import logging import logging
import os import os
import json import json
import requests
from pathlib import Path from pathlib import Path
from subprocess import run, CalledProcessError from subprocess import run, CalledProcessError
@@ -69,5 +70,23 @@ def clean_all_dockers():
logger.info(f'Contexte restaure: {original_context}') logger.info(f'Contexte restaure: {original_context}')
if __name__ == '__main__': def get_all_tags_from_blender():
clean_all_dockers() """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)
+10
View File
@@ -1,3 +1,4 @@
import re
class BlenderVersion: class BlenderVersion:
@@ -6,6 +7,7 @@ class BlenderVersion:
Need an object like 'X.Y.Z' to work correctly, build a pythonic object about a blender version. Need an object like 'X.Y.Z' to work correctly, build a pythonic object about a blender version.
:param version: :param version:
""" """
self._check_pattern(version)
self.major : str = '' self.major : str = ''
self.minor : str = '' self.minor : str = ''
self.hotfix : str = '' self.hotfix : str = ''
@@ -29,5 +31,13 @@ class BlenderVersion:
def tag_name_slugify(self): def tag_name_slugify(self):
return f'{self.major}-{self.minor}-{self.hotfix}' 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): def __str__(self):
return str(self.major + '.' + self.minor + '.' + self.hotfix) return str(self.major + '.' + self.minor + '.' + self.hotfix)
+2 -4
View File
@@ -4,11 +4,9 @@ from blender.version import BlenderVersion
from blender.docker import BlenderDocker from blender.docker import BlenderDocker
# Todo Update readme file badge with blender version # Todo Update readme file badge with blender version
# Todo
if __name__ == "__main__": if __name__ == "__main__":
# Todo use the manual entry can be error prone (need to make a basic regex to check this entry)
version = BlenderVersion(input("Give the blender version (X.Y.Z): ")) version = BlenderVersion(input("Give the blender version (X.Y.Z): "))
print(f"Build a blender version {version}.") print(f"Build a blender version {version}.")
@@ -19,8 +17,8 @@ if __name__ == "__main__":
test = docker.test() test = docker.test()
if test: if test:
print('Push this image.') print('Test work, push this image.')
# docker.push() docker.push()
# Todo: Add a latest tag, check if this version are the latest # Todo: Add a latest tag, check if this version are the latest
# Todo: Add a LTS tag, check if this version are a LTS # Todo: Add a LTS tag, check if this version are a LTS
+2
View File
@@ -1 +1,3 @@
docker==7.2.0 docker==7.2.0
requests==2.34.2
invoke==3.0.3
-31
View File
@@ -1,31 +0,0 @@
#!/usr/bin/env python3
"""
Lit install_linux_packages.py et génère un fichier .txt avec les paquets
Debian/Ubuntu à installer.
"""
import re
import sys
READER="install_linux_packages.py"
OUT="packages.txt"
def main():
with open(READER, "r", encoding="utf-8") as f:
content = f.read()
# Cherche toutes les lignes du type: DISTRO_ID_DEBIAN: "nom-du-paquet"
packages = re.findall(r'DISTRO_ID_DEBIAN:\s*"([^"]+)"', content)
# Enlève les doublons, trie
packages = sorted(set(packages))
with open(OUT, "w", encoding="utf-8") as f:
for pkg in packages:
f.write(pkg + "\n")
print(f"{len(packages)} paquets écrits dans {OUT}")
if __name__ == "__main__":
main()
+34
View File
@@ -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()