Optimized Dockerfile and github workflow

This commit is contained in:
Kevin Veen-Birkenbach 2025-07-16 09:38:19 +02:00
parent 241c5c6da8
commit 2d276cfa5e
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
9 changed files with 257 additions and 29 deletions

31
.github/workflows/test-container.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Build & Test Container
on:
push:
branches:
- master
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build -t cymais:latest .
- name: Clean build artifacts
run: |
docker run --rm cymais:latest cymais make clean
- name: Generate project outputs
run: |
docker run --rm cymais:latest cymais make build
- name: Run tests
run: |
docker run --rm cymais:latest cymais make test

View File

@ -1,22 +0,0 @@
name: Build & Test on Arch Linux
on:
push:
branches: [ master ]
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build & Test in Arch Linux Container
uses: addnab/docker-run-action@v3
with:
image: archlinux:latest
options: -v ${{ github.workspace }}:/workspace -w /workspace
run: |
pacman -Sy --noconfirm base-devel git python python-pip docker make
make build
make test

View File

@ -42,11 +42,23 @@ RUN git clone https://github.com/kevinveenbirkenbach/package-manager.git $PKGMGR
# 5) Ensure pkgmgr venv bin and user-local bin are on PATH # 5) Ensure pkgmgr venv bin and user-local bin are on PATH
ENV PATH="$PKGMGR_VENV/bin:/root/.local/bin:${PATH}" ENV PATH="$PKGMGR_VENV/bin:/root/.local/bin:${PATH}"
# 6) Install CyMaIS (using HTTPS cloning mode) # 6) Copy local CyMaIS source into the image for override
COPY . /opt/cymais-src
# 7) Install CyMaIS via pkgmgr (clone-mode https)
RUN pkgmgr install cymais --clone-mode https RUN pkgmgr install cymais --clone-mode https
# 7) Symlink the cymais CLI into /usr/local/bin so ENTRYPOINT works # 8) Override installed CyMaIS with local source and clean ignored files
RUN ln -s /root/.local/bin/cymais /usr/local/bin/cymais RUN CMAIS_PATH=$(pkgmgr path cymais) && \
rm -rf "$CMAIS_PATH"/* && \
cp -R /opt/cymais-src/* "$CMAIS_PATH"/ && \
cd "$CMAIS_PATH" && \
make clean
# 9) Symlink the cymais script into /usr/local/bin so ENTRYPOINT works
RUN CMAIS_PATH=$(pkgmgr path cymais) && \
ln -sf "$CMAIS_PATH"/main.py /usr/local/bin/cymais && \
chmod +x /usr/local/bin/cymais
ENTRYPOINT ["cymais"] ENTRYPOINT ["cymais"]
CMD ["--help"] CMD ["--help"]

View File

@ -22,8 +22,8 @@ EXTRA_USERS := $(shell \
.PHONY: build install test .PHONY: build install test
clean: clean:
@echo "Removing not tracked git files" @echo "Removing ignored git files"
git clean -fdx git clean -fdX
tree: tree:
@echo Generating Tree @echo Generating Tree

View File

@ -1,6 +1,8 @@
# IT-Infrastructure Automation Framework 🚀 # IT-Infrastructure Automation Framework 🚀
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate) [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate) [![Build Status](https://github.com/kevinveenbirkenbach/cymais/actions/workflows/test-container.yml/badge.svg?branch=master)](https://github.com/kevinveenbirkenbach/cymais/actions/workflows/test-container.yml?query=branch%3Amaster) [![CyMaIS.Cloud](https://img.shields.io/badge/CyMaIS-%2ECloud-000000?labelColor=004B8D&style=flat&borderRadius=8)](https://cymais.cloud)
--- ---
@ -63,6 +65,20 @@ Give CyMaIS a spin at [CyMaIS.cloud](httpy://cymais.cloud) sign up in second
``` ```
--- ---
### Setup with Docker🚢
Get CyMaIS up and running inside Docker in just a few steps. For detailed build options and troubleshooting, see the [Docker Guide](docs/Docker.md).
```bash
# 1. Build the Docker image: the Docker image:
docker build -t cymais:latest .
# 2. Run the CLI interactively:
docker run --rm -it cymais:latest cymais --help
```
---
## License ⚖️ ## License ⚖️
CyMaIS is distributed under the **CyMaIS NonCommercial License**. Please see [LICENSE.md](LICENSE.md) for full terms. CyMaIS is distributed under the **CyMaIS NonCommercial License**. Please see [LICENSE.md](LICENSE.md) for full terms.

50
cli/make.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""
CLI wrapper for Makefile targets within CyMaIS.
Invokes `make` commands in the project root directory.
"""
import argparse
import os
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(
prog='cymais make',
description='Run Makefile targets for CyMaIS project'
)
parser.add_argument(
'targets',
nargs=argparse.REMAINDER,
help='Make targets and options to pass to `make`'
)
args = parser.parse_args()
# Default to 'build' if no target is specified
make_args = args.targets or ['build']
# Determine repository root (one level up from cli/)
script_dir = os.path.dirname(os.path.realpath(__file__))
repo_root = os.path.abspath(os.path.join(script_dir, os.pardir))
# Check for Makefile
makefile_path = os.path.join(repo_root, 'Makefile')
if not os.path.isfile(makefile_path):
print(f"Error: Makefile not found in {repo_root}", file=sys.stderr)
sys.exit(1)
# Invoke make in repo root
cmd = ['make'] + make_args
try:
result = subprocess.run(cmd, cwd=repo_root)
sys.exit(result.returncode)
except FileNotFoundError:
print("Error: 'make' command not found. Please install make.", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
sys.exit(1)
if __name__ == '__main__':
main()

124
docs/Docker.md Normal file
View File

@ -0,0 +1,124 @@
# Docker Build Guide 🚢
This guide explains how to build the **CyMaIS** Docker image with advanced options to avoid common issues (e.g. mirror timeouts) and control build caching.
---
## 1. Enable BuildKit (Optional but Recommended)
Modern versions of Docker support **BuildKit**, which speeds up build processes and offers better caching.
```bash
# On your host, enable BuildKit for the current shell session:
export DOCKER_BUILDKIT=1
```
> **Note:** You only need to set this once per terminal session.
---
## 2. Build Arguments Explained
When you encounter errors like:
```text
:: Synchronizing package databases...
error: failed retrieving file 'core.db' from geo.mirror.pkgbuild.com : Connection timed out after 10002 milliseconds
error: failed to synchronize all databases (failed to retrieve some files)
```
it usually means the default container network cannot reach certain Arch Linux mirrors. To work around this, use:
* `--network=host`
Routes all build-time network traffic through your hosts network stack.
* `--no-cache`
Forces a fresh build of every layer by ignoring Dockers layer cache. Useful if you suspect stale cache entries.
---
## 3. Recommended Build Command
```bash
# 1. (Optional) Enable BuildKit
export DOCKER_BUILDKIT=1
# 2. Build with host networking and no cache
docker build \
--network=host \
--no-cache \
-t cymais:latest \
.
```
**Flags:**
* `--network=host`
Ensures all `pacman -Syu` and other network calls hit your host network directly—eliminating mirror connection timeouts.
* `--no-cache`
Guarantees that changes to package lists or dependencies are picked up immediately by rebuilding every layer.
* `-t cymais:latest`
Tags the resulting image as `cymais:latest`.
---
## 4. Running the Container
Once built, you can run CyMaIS as usual:
```bash
docker run --rm -it \
-v "$(pwd)":/opt/cymais \
-w /opt/cymais \
cymais:latest cymais --help
```
Mount any host directory into `/opt/cymais/logs` to persist logs across runs.
---
## 5. Further Troubleshooting
* **Mirror selection:** If you still see slow or unreachable mirrors, consider customizing `/etc/pacman.d/mirrorlist` in a local Docker stage or on your host to prioritize faster mirrors.
* **Firewall or VPN:** Ensure your hosts firewall or VPN allows outgoing connections on port 443/80 to Arch mirror servers.
* **Docker daemon config:** On some networks, you may need to configure Dockers daemon proxy settings under `/etc/docker/daemon.json`.
## 6. Live Development via Volume Mount
The CyMaIS installation inside the container always resides at:
```
/root/Repositories/github.com/kevinveenbirkenbach/cymais
```
To apply code changes without rebuilding the image, mount your local installation directory into that static path:
```bash
# 1. Determine the CyMaIS install path on your host
CMAIS_PATH=$(pkgmgr path cymais)
# 2. Launch the container with a bind mount:
docker run --rm -it \
-v "${CMAIS_PATH}:/root/Repositories/github.com/kevinveenbirkenbach/cymais" \
-w "/root/Repositories/github.com/kevinveenbirkenbach/cymais" \
cymais:latest cymais make build
```
Or, to test the CLI help interactively:
```bash
docker run --rm -it \
-v "${CMAIS_PATH}:/root/Repositories/github.com/kevinveenbirkenbach/cymais" \
-w "/root/Repositories/github.com/kevinveenbirkenbach/cymais" \
cymais:latest --help
```
Any edits you make in `${CMAIS_PATH}` on your host are immediately reflected inside the container, eliminating the need for repeated `docker build` cycles.
---
With these options, your Docker builds should complete reliably, even in restrictive network environments. Happy building! 🚀

19
main.py
View File

@ -18,7 +18,24 @@ except ImportError:
def __getattr__(self, name): return '' def __getattr__(self, name): return ''
Fore = Back = Style = Dummy() Fore = Back = Style = Dummy()
from cli.sounds import Sound # ensure Sound imported _IN_DOCKER = os.path.exists('/.dockerenv')
if _IN_DOCKER:
class Quiet:
@staticmethod
def play_start_sound(): pass
@staticmethod
def play_cymais_intro_sound(): pass
@staticmethod
def play_finished_successfully_sound(): pass
@staticmethod
def play_finished_failed_sound(): pass
@staticmethod
def play_warning_sound(): pass
Sound = Quiet
else:
from utils.sounds import Sound
def color_text(text, color): def color_text(text, color):