From dd21b21829c9d79592fc3c11d36eb839af093d7d Mon Sep 17 00:00:00 2001
From: Ad5001 <mail@ad5001.eu>
Date: Thu, 19 Sep 2024 23:28:21 +0200
Subject: [PATCH 1/2] Started automated building

---
 README.md                                   |  14 ++
 build.sh                                    | 150 ++++++++++++++++++++
 pyside2/config.toml                         |  18 +++
 {pyside2-linux => pyside2/linux}/Dockerfile |  14 +-
 {pyside2-wine => pyside2/wine}/Dockerfile   |  14 +-
 pyside6-linux-latex/Dockerfile              |   6 -
 pyside6/config.toml                         |  18 +++
 pyside6/linux-latex/Dockerfile              |  20 +++
 {pyside6-linux => pyside6/linux}/Dockerfile |  13 +-
 {pyside6-wine => pyside6/wine}/Dockerfile   |  16 ++-
 10 files changed, 272 insertions(+), 11 deletions(-)
 create mode 100644 build.sh
 create mode 100644 pyside2/config.toml
 rename {pyside2-linux => pyside2/linux}/Dockerfile (57%)
 rename {pyside2-wine => pyside2/wine}/Dockerfile (86%)
 delete mode 100644 pyside6-linux-latex/Dockerfile
 create mode 100644 pyside6/config.toml
 create mode 100644 pyside6/linux-latex/Dockerfile
 rename {pyside6-linux => pyside6/linux}/Dockerfile (51%)
 rename {pyside6-wine => pyside6/wine}/Dockerfile (84%)

diff --git a/README.md b/README.md
index e22b628..72cab98 100644
--- a/README.md
+++ b/README.md
@@ -28,4 +28,18 @@ Additionally, the linux-6*-latex tag include a full TeXlive installation includi
 
 ---
 
+## Building docker files
+
+It's recommended to use the `build.sh` bash script to build the Docker image. They use the `config.toml` in each directory to provide the data for each build,
+including the specific PySide versions to use for each.
+
+Usage:
+`bash build.sh [--pyside2] [--pyside6] [--latest] [--no-push] [--repo=ad5001/ubuntu-pyside-xvfb]`
+
+- --pyside2: Build PySide2 images.
+- --pyside6: Build PySide6 images.
+- --latest: (Optional) Tag these as latest.
+- --no-push: (Optional) Do not push the tags to the Docker registry.
+- --repo: (Optional) Repository on the Docker registry which to push the images to.
+
 NOTE: In Docker, use xvfb-run to run a program within a Xvfb server.
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..ecc4cab
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,150 @@
+#!/bin/bash
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
+# shellcheck disable=SC2046
+
+# Resets all ansi codes.
+RESET="\e[0m"
+# Sets the forground color to light green.
+L_GREEN_FG="\e[32m"
+# Sets the forground color to red.
+RED_FG="\e[38;5;204m"
+
+# Display text in a box
+# Signature: (<string message>) -> string
+box() {
+    len=${#1}
+    echo "┌─$(yes ─ | head -$len | tr -d "\n")─┐"
+    echo "│ $1 │"
+    echo "└─$(yes ─ | head -$len | tr -d "\n")─┘"
+}
+
+box_red() {
+    echo -n "$RED_FG"
+    box "$@"
+    echo -n "$RESET"
+}
+
+box_green() {
+    echo -n "$L_GREEN_FG"
+    box "$@"
+    echo -n "$RESET"
+}
+
+# Converts arguments from an INI/singular dict TOML file into a list of build args for docker.
+# Signature: (<string source_file>) -> string
+config_to_docker_args() {
+    grep '="' "$1" | sed 's@^@--build-arg @g' | paste -s -d " "
+}
+
+# Queries a value from an INI/singular dict TOML file into for a given key
+# Signature: (<string source_file>, <string key>) -> string
+query_from_config() {
+    grep "$2=" "$1" | cut -d'"' -f 2
+}
+
+pyside6=false
+pyside2=false
+latest=false
+push=true
+repo="ad5001/ubuntu-pyside-xvfb"
+
+# Query arguments
+
+while [ $# -gt 0 ]; do
+    case "$1" in
+        --pyside6)
+            pyside6=true
+            ;;
+        --pyside2)
+            pyside2=true
+            ;;
+        --latest)
+            latest=true
+            ;;
+        --no-push)
+            push=false
+            ;;
+        --repo=*)
+            repo="${1#*=}"
+            ;;
+        *)
+            box "Error: Invalid argument."
+            exit 1
+    esac
+    shift
+done
+
+if [ "$pyside6" = "false" ] && [ "$pyside2" = "false" ]; then
+    box "Must at least either use --pyside2 or --pyside6"
+fi
+
+# Build PySide6
+if [ "$pyside6" != "false" ]; then
+    config="pyside6/config.toml"
+    version=$(query_from_config "$config" "PYSIDE6_VERSION")
+    tag_linux="${repo}:linux-${version}"
+    tag_wine="${repo}:wine-${version}"
+    tag_linux_latex="${repo}:linux-${version}-latex"
+    # Building
+    box "Building PySide6 Linux Image..."
+    docker build -t "${tag_linux}" $(config_to_docker_args "$config") pyside6/linux
+    box "Building PySide6 Wine Image..."
+    docker build -t "${tag_wine}" $(config_to_docker_args "$config") pyside6/wine
+    box "Building PySide6 Linux-Latex Image..."
+    docker build -t "${tag_linux_latex}" $(config_to_docker_args "$config") --build-arg BASE_IMAGE="${tag_linux}" pyside6/linux-latex
+    # Tagging
+    if [ "$latest" != "false" ]; then
+        docker tag "${tag_linux}" "${repo}:linux-6-latest"
+        docker tag "${tag_wine}" "${repo}:wine-6-latest"
+        docker tag "${tag_linux_latex}" "${repo}:linux-6-latest-latex"
+    fi
+    # Pushing
+    if [ "$push" != "true" ]; then
+        docker push "${tag_linux}"
+        docker push "${tag_wine}"
+        docker push "${tag_linux_latex}"
+        if [ "$latest" != "false" ]; then
+            docker push "${repo}:linux-6-latest"
+            docker push "${repo}:wine-6-latest"
+            docker push "${repo}:linux-6-latest-latex"
+        fi
+    fi
+fi
+
+# Build PySide2
+if [ "$pyside2" != "false" ]; then
+    config="pyside2/config.toml"
+    version=$(query_from_config "$config" "PYSIDE2_VERSION")
+    tag_linux="${repo}:linux-${version}"
+    tag_wine="${repo}:wine-${version}"
+    # Building
+    box "Building PySide2 Linux Image..."
+    docker build -t "${tag_linux}" $(config_to_docker_args "$config") pyside2/linux
+    box "Building PySide2 Wine Image..."
+    docker build -t "${tag_wine}" $(config_to_docker_args "$config") pyside2/wine
+    # Tagging
+    if [ "$latest" != "false" ]; then
+        docker tag "${tag_linux}" "${repo}:linux-5-latest"
+        docker tag "${tag_wine}" "${repo}:wine-5-latest"
+    fi
+    # Pushing
+    if [ "$push" != "true" ]; then
+        docker push "${tag_linux}"
+        docker push "${tag_wine}"
+        if [ "$latest" != "false" ]; then
+            docker push "${repo}:linux-5-latest"
+            docker push "${repo}:wine-5-latest"
+        fi
+    fi
+fi
diff --git a/pyside2/config.toml b/pyside2/config.toml
new file mode 100644
index 0000000..4f54971
--- /dev/null
+++ b/pyside2/config.toml
@@ -0,0 +1,18 @@
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
+PYSIDE2_VERSION="5.12.2.1"
+
+# Arguments for wine builds
+PYTHON_VERSION="3.10.11"
+PYINSTALLER_VERSION="6.10.0"
+
diff --git a/pyside2-linux/Dockerfile b/pyside2/linux/Dockerfile
similarity index 57%
rename from pyside2-linux/Dockerfile
rename to pyside2/linux/Dockerfile
index 047ff09..a182252 100644
--- a/pyside2-linux/Dockerfile
+++ b/pyside2/linux/Dockerfile
@@ -1,3 +1,15 @@
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
 FROM ubuntu:jammy
 # Jammy uses python3.10 and not 3.12, which is not compatible with PySide2.
 
@@ -8,7 +20,7 @@ ENV TZ=Europe/Paris
 RUN apt-get update
 RUN apt-get upgrade -y
 RUN apt-get -y install make git rpm dh-python \
-                       xvfb xdotool wmctrl \
+                       xvfb xdotool wmctrl libxcb-cursor0 \
                        python3 python3-pip python3-stdeb python3-requests python3-packaging python3-pip python3-pytest python3-pytest-cov python3-pytestqt \
                        qml-module-qtquick-controls2 qml-module-qtmultimedia qml-module-qtgraphicaleffects qml-module-qtquick2 qml-module-qtqml-models2 qml-module-qtquick-controls
 RUN python3 -m pip install -U pip py certifi setuptools wheel # Upgrading packages that need fixes.
diff --git a/pyside2-wine/Dockerfile b/pyside2/wine/Dockerfile
similarity index 86%
rename from pyside2-wine/Dockerfile
rename to pyside2/wine/Dockerfile
index 30da488..b673b33 100644
--- a/pyside2-wine/Dockerfile
+++ b/pyside2/wine/Dockerfile
@@ -1,3 +1,15 @@
+# 
+# Copyright (c) 2021-2024 Ad5001, 2016 Chris R
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
 FROM ubuntu:noble
 
 ARG PYSIDE2_VERSION=5.15.2.1
@@ -9,7 +21,7 @@ ENV DEBIAN_FRONTEND noninteractive
 
 ARG WINE_VERSION=winehq-staging
 ARG PYTHON_VERSION=3.10.11 # Python3.10 are the last supported version of Python for PySide2.
-ARG PYINSTALLER_VERSION=5.0.1
+ARG PYINSTALLER_VERSION=6.10.0
 
 # we need wine for this all to work, so we'll use the PPA
 RUN set -x \
diff --git a/pyside6-linux-latex/Dockerfile b/pyside6-linux-latex/Dockerfile
deleted file mode 100644
index ba7554e..0000000
--- a/pyside6-linux-latex/Dockerfile
+++ /dev/null
@@ -1,6 +0,0 @@
-FROM ad5001/ubuntu-pyside-xvfb:linux-6.7.2
-
-ENV TZ=Europe/Paris
-RUN apt-get update
-RUN apt-get -y install texlive-base dvipng texlive-latex-extra
-RUN apt clean
diff --git a/pyside6/config.toml b/pyside6/config.toml
new file mode 100644
index 0000000..89f2b8d
--- /dev/null
+++ b/pyside6/config.toml
@@ -0,0 +1,18 @@
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
+PYSIDE6_VERSION="6.7.2"
+
+# Arguments for wine builds
+PYTHON_VERSION="3.12.6"
+PYINSTALLER_VERSION="6.10.0"
+
diff --git a/pyside6/linux-latex/Dockerfile b/pyside6/linux-latex/Dockerfile
new file mode 100644
index 0000000..9ef7349
--- /dev/null
+++ b/pyside6/linux-latex/Dockerfile
@@ -0,0 +1,20 @@
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
+ARG BASE_IMAGE=ad5001/ubuntu-pyside-xvfb:linux-6-latest
+
+FROM ${BASE_IMAGE}
+
+ENV TZ=Europe/Paris
+RUN apt-get update
+RUN apt-get -y install texlive-base dvipng texlive-latex-extra
+RUN apt clean
diff --git a/pyside6-linux/Dockerfile b/pyside6/linux/Dockerfile
similarity index 51%
rename from pyside6-linux/Dockerfile
rename to pyside6/linux/Dockerfile
index e0feb05..0577b43 100644
--- a/pyside6-linux/Dockerfile
+++ b/pyside6/linux/Dockerfile
@@ -1,3 +1,14 @@
+# 
+# Copyright (c) 2021-2024 Ad5001
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
 FROM ubuntu:noble
 
 ARG DEBIAN_FRONTEND=noninteractive
@@ -7,7 +18,7 @@ ENV TZ=Europe/Paris
 RUN apt-get update
 RUN apt-get upgrade -y
 RUN apt-get -y install make git rpm dh-python \
-                       xvfb xdotool wmctrl \
+                       xvfb xdotool wmctrl libxcb-cursor0 \
                        python3 python3-pip python3-stdeb python3-requests python3-packaging python3-pip python3-pytest python3-pytest-cov python3-pytestqt
 RUN rm /usr/lib/python3.*/EXTERNALLY-MANAGED # Disable managed environment. We don't care about breaking system packages here.
 RUN python3 -m pip install -U setuptools # Upgrading packages that need fixes.
diff --git a/pyside6-wine/Dockerfile b/pyside6/wine/Dockerfile
similarity index 84%
rename from pyside6-wine/Dockerfile
rename to pyside6/wine/Dockerfile
index 1639523..1bb223c 100644
--- a/pyside6-wine/Dockerfile
+++ b/pyside6/wine/Dockerfile
@@ -1,6 +1,18 @@
+# 
+# Copyright (c) 2021-2024 Ad5001, 2016 Chris R
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE. 
+# 
+
 FROM ubuntu:noble
 
-ARG PYSIDE2_VERSION=6.7.2
+ARG PYSIDE6_VERSION=6.7.2
 
 # Adapted from https://github.com/cdrx/docker-pyinstaller/blob/master/Dockerfile-py3-win64
 # Upstream hasn't been updated for a while.
@@ -78,4 +90,4 @@ RUN set -x \
 RUN apt install -y wget curl p7zip-full git unzip nsis xvfb xdotool wmctrl
 RUN apt clean
 # Installing pyside6 & pyinstaller
-RUN pip install wheel PySide6==$PYSIDE2_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging
+RUN pip install wheel PySide6==$PYSIDE6_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging

From 236a9c4bc5e31fa6a1bb2bf2a7674cacf9bfced2 Mon Sep 17 00:00:00 2001
From: Ad5001 <mail@ad5001.eu>
Date: Fri, 20 Sep 2024 01:05:08 +0200
Subject: [PATCH 2/2] Build system working with custom config files so I don't
 have to customize the script every time!

---
 build.sh                 | 157 +++++++++++++++++++++------------------
 pyside2/config.toml      |  12 ++-
 pyside2/linux/Dockerfile |   4 +-
 pyside2/wine/Dockerfile  |   4 +-
 pyside6/config.toml      |  16 +++-
 pyside6/linux/Dockerfile |   4 +-
 pyside6/wine/Dockerfile  |   4 +-
 7 files changed, 118 insertions(+), 83 deletions(-)

diff --git a/build.sh b/build.sh
index ecc4cab..493a59b 100644
--- a/build.sh
+++ b/build.sh
@@ -20,6 +20,12 @@ L_GREEN_FG="\e[32m"
 # Sets the forground color to red.
 RED_FG="\e[38;5;204m"
 
+pyside6=false
+pyside2=false
+latest=false
+push=true
+repo="ad5001/ubuntu-pyside-xvfb"
+
 # Display text in a box
 # Signature: (<string message>) -> string
 box() {
@@ -29,36 +35,93 @@ box() {
     echo "└─$(yes ─ | head -$len | tr -d "\n")─┘"
 }
 
-box_red() {
-    echo -n "$RED_FG"
+box-red() {
+    echo -n -e "$RED_FG"
     box "$@"
-    echo -n "$RESET"
+    echo -n -e "$RESET"
 }
 
-box_green() {
-    echo -n "$L_GREEN_FG"
+box-green() {
+    echo -n -e "$L_GREEN_FG"
     box "$@"
-    echo -n "$RESET"
+    echo -n -e "$RESET"
+}
+
+# Returns a string of KEY="VALUES" separated by newlines for the corresponding category.
+# Signature: (<string source_file>, <string dict_name>) -> string
+from-toml-dict() {
+    if [ -z "$2" ]; then
+        sed -n -e '1,/\[/ p' "$1" | grep '="'
+    else
+        sed -n -e '/\['"$2"']/,/\[/ p' "$1" | grep '="'
+    fi
+}
+
+# Replaces {KEY} by value in given context.
+# Signature: stdin+(<string key>, <string value>) -> string
+pass-argument() {
+    while read -r line; do
+        echo "${line//\{$1\}/$2}"
+    done
+}
+
+# Queries a value from an INI/singular dict TOML into for a given key
+# Signature: stdin+(<string key>) -> string
+get-value-of() {
+    while read -r line; do
+        if [ "${line%=*}" = "$1" ]; then
+            echo "$line" | cut -d'"' -f 2
+            return 0
+        fi
+    done
 }
 
 # Converts arguments from an INI/singular dict TOML file into a list of build args for docker.
-# Signature: (<string source_file>) -> string
-config_to_docker_args() {
-    grep '="' "$1" | sed 's@^@--build-arg @g' | paste -s -d " "
+# Signature: stdin+(<string repo>, <string pyside_version>) -> string
+to-docker-args() {
+    # Read stdin
+    out=""
+    while read -r line; do
+        key="${line%=*}"
+        value="$(echo "${line#=*}" | pass-argument REPO "$1" | pass-argument VERSION "$2")"
+        out="$out--build-arg $key=$value";
+    done
+    echo "$out"
 }
 
-# Queries a value from an INI/singular dict TOML file into for a given key
-# Signature: (<string source_file>, <string key>) -> string
-query_from_config() {
-    grep "$2=" "$1" | cut -d'"' -f 2
+# Builds a pyside directory (with a config.toml for additional parameters.
+# Signature (<string directory>) -> void
+build_pyside() {
+    directory=$1
+    cfg="$directory/config.toml"
+    # Query information from config
+    major=$(from-toml-dict "$cfg" | get-value-of MAJOR_VERSION)
+    version=$(from-toml-dict "$cfg" | get-value-of PYSIDE_VERSION)
+    for build in $(from-toml-dict "$cfg" | get-value-of BUILDS); do
+        # Build each build individidually
+        tag="$(from-toml-dict "$cfg" "$build.settings" | get-value-of TAG | pass-argument VERSION "$version")"
+        latest_tag="$(from-toml-dict "$cfg" "$build.settings" | get-value-of TAG | pass-argument VERSION "${major}-latest")"
+        build_args="$(from-toml-dict "$cfg" "$build.docker-args" | to-docker-args "$repo" "$version")"
+        box-green "Building image $tag..."
+        docker build -t "$tag" $build_args "$directory/${build}"
+        # Tag as latest
+        if [ "$latest" != "false" ]; then
+            docker tag "$tag" "$latest_tag"
+        fi
+        # Push builds
+        if [ "$push" != "false" ]; then
+            if [ "$latest" != "false" ]; then
+                box-green "Pushing image $repo/$tag and $repo/$latest_tag..."
+                docker push "$latest_tag"
+                docker push "$tag"
+            else
+                box-green "Pushing image $repo/$tag..."
+                docker push "$tag"
+            fi
+        fi
+    done
 }
 
-pyside6=false
-pyside2=false
-latest=false
-push=true
-repo="ad5001/ubuntu-pyside-xvfb"
-
 # Query arguments
 
 while [ $# -gt 0 ]; do
@@ -86,65 +149,15 @@ while [ $# -gt 0 ]; do
 done
 
 if [ "$pyside6" = "false" ] && [ "$pyside2" = "false" ]; then
-    box "Must at least either use --pyside2 or --pyside6"
+    box-red "Must at least either use --pyside2 or --pyside6"
 fi
 
 # Build PySide6
 if [ "$pyside6" != "false" ]; then
-    config="pyside6/config.toml"
-    version=$(query_from_config "$config" "PYSIDE6_VERSION")
-    tag_linux="${repo}:linux-${version}"
-    tag_wine="${repo}:wine-${version}"
-    tag_linux_latex="${repo}:linux-${version}-latex"
-    # Building
-    box "Building PySide6 Linux Image..."
-    docker build -t "${tag_linux}" $(config_to_docker_args "$config") pyside6/linux
-    box "Building PySide6 Wine Image..."
-    docker build -t "${tag_wine}" $(config_to_docker_args "$config") pyside6/wine
-    box "Building PySide6 Linux-Latex Image..."
-    docker build -t "${tag_linux_latex}" $(config_to_docker_args "$config") --build-arg BASE_IMAGE="${tag_linux}" pyside6/linux-latex
-    # Tagging
-    if [ "$latest" != "false" ]; then
-        docker tag "${tag_linux}" "${repo}:linux-6-latest"
-        docker tag "${tag_wine}" "${repo}:wine-6-latest"
-        docker tag "${tag_linux_latex}" "${repo}:linux-6-latest-latex"
-    fi
-    # Pushing
-    if [ "$push" != "true" ]; then
-        docker push "${tag_linux}"
-        docker push "${tag_wine}"
-        docker push "${tag_linux_latex}"
-        if [ "$latest" != "false" ]; then
-            docker push "${repo}:linux-6-latest"
-            docker push "${repo}:wine-6-latest"
-            docker push "${repo}:linux-6-latest-latex"
-        fi
-    fi
+    build_pyside "pyside6"
 fi
 
 # Build PySide2
 if [ "$pyside2" != "false" ]; then
-    config="pyside2/config.toml"
-    version=$(query_from_config "$config" "PYSIDE2_VERSION")
-    tag_linux="${repo}:linux-${version}"
-    tag_wine="${repo}:wine-${version}"
-    # Building
-    box "Building PySide2 Linux Image..."
-    docker build -t "${tag_linux}" $(config_to_docker_args "$config") pyside2/linux
-    box "Building PySide2 Wine Image..."
-    docker build -t "${tag_wine}" $(config_to_docker_args "$config") pyside2/wine
-    # Tagging
-    if [ "$latest" != "false" ]; then
-        docker tag "${tag_linux}" "${repo}:linux-5-latest"
-        docker tag "${tag_wine}" "${repo}:wine-5-latest"
-    fi
-    # Pushing
-    if [ "$push" != "true" ]; then
-        docker push "${tag_linux}"
-        docker push "${tag_wine}"
-        if [ "$latest" != "false" ]; then
-            docker push "${repo}:linux-5-latest"
-            docker push "${repo}:wine-5-latest"
-        fi
-    fi
+    build_pyside "pyside2"
 fi
diff --git a/pyside2/config.toml b/pyside2/config.toml
index 4f54971..9c683cd 100644
--- a/pyside2/config.toml
+++ b/pyside2/config.toml
@@ -10,9 +10,17 @@
 # SOFTWARE. 
 # 
 
-PYSIDE2_VERSION="5.12.2.1"
+MAJOR_VERSION="5"
+PYSIDE_VERSION="5.12.2.1"
+BUILDS="linux wine"
 
+[linux.settings]
+TAG="linux-{VERSION}"
+
+[wine.settings]
+TAG="wine-{VERSION}"
+
+[wine.docker-args]
 # Arguments for wine builds
 PYTHON_VERSION="3.10.11"
 PYINSTALLER_VERSION="6.10.0"
-
diff --git a/pyside2/linux/Dockerfile b/pyside2/linux/Dockerfile
index a182252..f35432b 100644
--- a/pyside2/linux/Dockerfile
+++ b/pyside2/linux/Dockerfile
@@ -14,7 +14,7 @@ FROM ubuntu:jammy
 # Jammy uses python3.10 and not 3.12, which is not compatible with PySide2.
 
 ARG DEBIAN_FRONTEND=noninteractive
-ARG PYSIDE2_VERSION=5.15.2.1
+ARG PYSIDE_VERSION=5.15.2.1
 
 ENV TZ=Europe/Paris 
 RUN apt-get update
@@ -24,5 +24,5 @@ RUN apt-get -y install make git rpm dh-python \
                        python3 python3-pip python3-stdeb python3-requests python3-packaging python3-pip python3-pytest python3-pytest-cov python3-pytestqt \
                        qml-module-qtquick-controls2 qml-module-qtmultimedia qml-module-qtgraphicaleffects qml-module-qtquick2 qml-module-qtqml-models2 qml-module-qtquick-controls
 RUN python3 -m pip install -U pip py certifi setuptools wheel # Upgrading packages that need fixes.
-RUN python3 -m pip install PySide2==$PYSIDE2_VERSION
+RUN python3 -m pip install PySide2==$PYSIDE_VERSION
 RUN apt clean
diff --git a/pyside2/wine/Dockerfile b/pyside2/wine/Dockerfile
index b673b33..d8ceaf1 100644
--- a/pyside2/wine/Dockerfile
+++ b/pyside2/wine/Dockerfile
@@ -12,7 +12,7 @@
 
 FROM ubuntu:noble
 
-ARG PYSIDE2_VERSION=5.15.2.1
+ARG PYSIDE_VERSION=5.15.2.1
 
 # Adapted from https://github.com/cdrx/docker-pyinstaller/blob/master/Dockerfile-py3-win64
 # Upstream hasn't been updated for a while.
@@ -90,4 +90,4 @@ RUN set -x \
 RUN apt install -y wget curl p7zip-full git unzip nsis xvfb xdotool wmctrl
 RUN apt clean
 # Installing pyside2 & pyinstaller
-RUN pip install wheel PySide2==$PYSIDE2_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging
+RUN pip install wheel PySide2==$PYSIDE_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging
diff --git a/pyside6/config.toml b/pyside6/config.toml
index 89f2b8d..0e123ec 100644
--- a/pyside6/config.toml
+++ b/pyside6/config.toml
@@ -10,9 +10,23 @@
 # SOFTWARE. 
 # 
 
-PYSIDE6_VERSION="6.7.2"
+MAJOR_VERSION="6"
+PYSIDE_VERSION="6.7.2"
+BUILDS="linux wine linux-latex"
 
+[linux.settings]
+TAG="linux-{VERSION}"
+
+[wine.settings]
+TAG="wine-{VERSION}"
+
+[linux-latex.settings]
+TAG="linux-{VERSION}-latex"
+
+[wine.docker-args]
 # Arguments for wine builds
 PYTHON_VERSION="3.12.6"
 PYINSTALLER_VERSION="6.10.0"
 
+[linux-latex.docker-args]
+BASE_IMAGE="{REPO}:linux-{VERSION}"
diff --git a/pyside6/linux/Dockerfile b/pyside6/linux/Dockerfile
index 0577b43..f7446ad 100644
--- a/pyside6/linux/Dockerfile
+++ b/pyside6/linux/Dockerfile
@@ -12,7 +12,7 @@
 FROM ubuntu:noble
 
 ARG DEBIAN_FRONTEND=noninteractive
-ARG PYSIDE2_VERSION=6.7.2
+ARG PYSIDE_VERSION=6.7.2
 
 ENV TZ=Europe/Paris
 RUN apt-get update
@@ -22,5 +22,5 @@ RUN apt-get -y install make git rpm dh-python \
                        python3 python3-pip python3-stdeb python3-requests python3-packaging python3-pip python3-pytest python3-pytest-cov python3-pytestqt
 RUN rm /usr/lib/python3.*/EXTERNALLY-MANAGED # Disable managed environment. We don't care about breaking system packages here.
 RUN python3 -m pip install -U setuptools # Upgrading packages that need fixes.
-RUN python3 -m pip install PySide6==$PYSIDE2_VERSION
+RUN python3 -m pip install PySide6==$PYSIDE_VERSION
 RUN apt clean
diff --git a/pyside6/wine/Dockerfile b/pyside6/wine/Dockerfile
index 1bb223c..03e84c0 100644
--- a/pyside6/wine/Dockerfile
+++ b/pyside6/wine/Dockerfile
@@ -12,7 +12,7 @@
 
 FROM ubuntu:noble
 
-ARG PYSIDE6_VERSION=6.7.2
+ARG PYSIDE_VERSION=6.7.2
 
 # Adapted from https://github.com/cdrx/docker-pyinstaller/blob/master/Dockerfile-py3-win64
 # Upstream hasn't been updated for a while.
@@ -90,4 +90,4 @@ RUN set -x \
 RUN apt install -y wget curl p7zip-full git unzip nsis xvfb xdotool wmctrl
 RUN apt clean
 # Installing pyside6 & pyinstaller
-RUN pip install wheel PySide6==$PYSIDE6_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging
+RUN pip install wheel PySide6==$PYSIDE_VERSION pyinstaller==$PYINSTALLER_VERSION requests pytest pytest-cov pytest-qt packaging