diff --git a/.gitea/workflows/main.yaml b/.gitea/workflows/main.yaml index 9e0e5c0..1802998 100644 --- a/.gitea/workflows/main.yaml +++ b/.gitea/workflows/main.yaml @@ -44,8 +44,68 @@ jobs: - name: Build Arch Linux Package (.pkg.tar.zst) run: | - chmod +x packaging/arch/build-package.sh - ./packaging/arch/build-package.sh + python3 - <<'EOF' + import json, os, subprocess, tempfile, time + + metadata = json.loads(subprocess.check_output(["cargo", "metadata", "--format-version", "1", "--no-deps"])) + pkg = metadata["packages"][0] + name = pkg["name"] + version = pkg["version"] + description = pkg.get("description", "") + license = pkg.get("license", "") + repository = pkg.get("repository", "") + authors = pkg.get("authors", []) + author = authors[0] if authors else "Unknown" + + arch_meta = pkg.get("metadata", {}).get("arch", {}) + pkgrel = arch_meta.get("pkgrel", "1") + arch = arch_meta.get("arch", "x86_64") + depends = arch_meta.get("depends", ["gcc-libs", "glibc", "sudo", "docker"]) + optdepends = arch_meta.get("optdepends", ["docker-compose: Unterstützung für Docker Compose v1"]) + + with tempfile.TemporaryDirectory() as build_dir: + bin_dir = os.path.join(build_dir, "usr/bin") + doc_dir = os.path.join(build_dir, f"usr/share/doc/{name}") + lic_dir = os.path.join(build_dir, f"usr/share/licenses/{name}") + os.makedirs(bin_dir, exist_ok=True) + os.makedirs(doc_dir, exist_ok=True) + os.makedirs(lic_dir, exist_ok=True) + + subprocess.run(["install", "-m", "755", f"target/release/{name}", f"{bin_dir}/{name}"], check=True) + if os.path.exists("LICENSE"): + subprocess.run(["install", "-m", "644", "LICENSE", f"{lic_dir}/LICENSE"], check=True) + if os.path.exists("README.md"): + subprocess.run(["install", "-m", "644", "README.md", f"{doc_dir}/README.md"], check=True) + + installed_size = subprocess.check_output(["du", "-sb", build_dir]).decode().split()[0] + builddate = str(int(time.time())) + + pkginfo_lines = [ + f"pkgname = {name}", + f"pkgbase = {name}", + f"pkgver = {version}-{pkgrel}", + f"pkgdesc = {description}", + f"url = {repository}", + f"builddate = {builddate}", + f"packager = {author}", + f"size = {installed_size}", + f"arch = {arch}", + f"license = {license}", + ] + for dep in depends: + pkginfo_lines.append(f"depend = {dep}") + for optdep in optdepends: + pkginfo_lines.append(f"optdepend = {optdep}") + pkginfo_lines.append("makepkgopt = strip\n") + + with open(os.path.join(build_dir, ".PKGINFO"), "w") as f: + f.write("\n".join(pkginfo_lines)) + + os.makedirs("target/arch", exist_ok=True) + output_file = os.path.abspath(f"target/arch/{name}-{version}-{pkgrel}-{arch}.pkg.tar.zst") + subprocess.run(["tar", "--zstd", "-cf", output_file, ".PKGINFO", "usr"], cwd=build_dir, check=True) + print(f"Arch-Paket erfolgreich erstellt: {output_file}") + EOF - name: Publish Packages to Gitea Package Registry env: diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml index 6a8cef6..19d94dc 100644 --- a/.gitea/workflows/testing.yaml +++ b/.gitea/workflows/testing.yaml @@ -44,8 +44,68 @@ jobs: - name: Build Arch Linux Package (.pkg.tar.zst) run: | - chmod +x packaging/arch/build-package.sh - ./packaging/arch/build-package.sh + python3 - <<'EOF' + import json, os, subprocess, tempfile, time + + metadata = json.loads(subprocess.check_output(["cargo", "metadata", "--format-version", "1", "--no-deps"])) + pkg = metadata["packages"][0] + name = pkg["name"] + version = pkg["version"] + description = pkg.get("description", "") + license = pkg.get("license", "") + repository = pkg.get("repository", "") + authors = pkg.get("authors", []) + author = authors[0] if authors else "Unknown" + + arch_meta = pkg.get("metadata", {}).get("arch", {}) + pkgrel = arch_meta.get("pkgrel", "1") + arch = arch_meta.get("arch", "x86_64") + depends = arch_meta.get("depends", ["gcc-libs", "glibc", "sudo", "docker"]) + optdepends = arch_meta.get("optdepends", ["docker-compose: Unterstützung für Docker Compose v1"]) + + with tempfile.TemporaryDirectory() as build_dir: + bin_dir = os.path.join(build_dir, "usr/bin") + doc_dir = os.path.join(build_dir, f"usr/share/doc/{name}") + lic_dir = os.path.join(build_dir, f"usr/share/licenses/{name}") + os.makedirs(bin_dir, exist_ok=True) + os.makedirs(doc_dir, exist_ok=True) + os.makedirs(lic_dir, exist_ok=True) + + subprocess.run(["install", "-m", "755", f"target/release/{name}", f"{bin_dir}/{name}"], check=True) + if os.path.exists("LICENSE"): + subprocess.run(["install", "-m", "644", "LICENSE", f"{lic_dir}/LICENSE"], check=True) + if os.path.exists("README.md"): + subprocess.run(["install", "-m", "644", "README.md", f"{doc_dir}/README.md"], check=True) + + installed_size = subprocess.check_output(["du", "-sb", build_dir]).decode().split()[0] + builddate = str(int(time.time())) + + pkginfo_lines = [ + f"pkgname = {name}", + f"pkgbase = {name}", + f"pkgver = {version}-{pkgrel}", + f"pkgdesc = {description}", + f"url = {repository}", + f"builddate = {builddate}", + f"packager = {author}", + f"size = {installed_size}", + f"arch = {arch}", + f"license = {license}", + ] + for dep in depends: + pkginfo_lines.append(f"depend = {dep}") + for optdep in optdepends: + pkginfo_lines.append(f"optdepend = {optdep}") + pkginfo_lines.append("makepkgopt = strip\n") + + with open(os.path.join(build_dir, ".PKGINFO"), "w") as f: + f.write("\n".join(pkginfo_lines)) + + os.makedirs("target/arch", exist_ok=True) + output_file = os.path.abspath(f"target/arch/{name}-{version}-{pkgrel}-{arch}.pkg.tar.zst") + subprocess.run(["tar", "--zstd", "-cf", output_file, ".PKGINFO", "usr"], cwd=build_dir, check=True) + print(f"Arch-Paket erfolgreich erstellt: {output_file}") + EOF - name: Publish Packages to Gitea Package Registry env: diff --git a/AGENTS.md b/AGENTS.md index 95bd7d9..b78793a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,17 +31,11 @@ DockerUpdate/ │ └── workflows/ │ ├── testing.yaml # CI/CD für testing-Branch (Tests, Testing-Packages & Preview-Release) │ └── main.yaml # CI/CD für main-Branch (Tests, Stable-Packages & Release) -├── Cargo.toml # Rust-Manifest, Abhängigkeiten und Metadaten für cargo-deb / generate-rpm +├── Cargo.toml # Rust-Manifest, Abhängigkeiten und Metadaten für deb / generate-rpm / arch ├── Cargo.lock ├── LICENSE # GPL-3.0 Lizenztext ├── README.md # Projektdokumentation für Endanwender und Administratoren ├── AGENTS.md # Richtlinien und Dokumentation für Agenten -├── packaging/ -│ ├── arch/ -│ │ ├── PKGBUILD # Arch Linux PKGBUILD -│ │ └── build-package.sh # Hilfsskript zur Erstellung des .pkg.tar.zst-Pakets -│ └── fedora/ -│ └── docker-update.spec # RPM-Spec für Fedora / RHEL / CentOS └── src/ ├── main.rs # Einstiegspunkt, Root-Prüfung, Ausführung ├── program.rs # Hilfsfunktion zur Programmnamensermittlung @@ -83,10 +77,6 @@ DockerUpdate/ - `main.yaml`: Führt bei Push auf `main` Tests und Builds durch, veröffentlicht Pakete in der Gitea Package Registry (`distribution: stable`, `component: main` bzw. Gruppe/Repo `stable`) und erstellt ein Gitea Release mit den Paketen als Assets. -- **`packaging/`**: - - `arch/PKGBUILD`: Quellpaketdefinition für Arch Linux (AUR / Makepkg). - - `arch/build-package.sh`: Hilfsskript zum Bauen des standardkonformen `.pkg.tar.zst`-Pakets aus dem Cargo-Build. - - `fedora/docker-update.spec`: RPM-Spec-Datei für Fedora, RHEL und CentOS. --- @@ -113,9 +103,6 @@ cargo deb # Fedora / RPM-Paket (.rpm) erstellen (benötigt cargo-generate-rpm) cargo generate-rpm - -# Arch Linux-Paket (.pkg.tar.zst) erstellen -./packaging/arch/build-package.sh ``` --- @@ -124,10 +111,10 @@ cargo generate-rpm 1. **Abwärtskompatibilität & Pfade**: Der Standard-Apps-Pfad `/var/apps` und die Konfigurationspfade dürfen nicht ohne triftigen Grund geändert werden. -2. **Paketierungsdefinitionen synchron halten**: - Werden Abhängigkeiten, Metadaten oder Assets geändert, müssen `Cargo.toml` (`[package.metadata.deb]`, - `[package.metadata.generate-rpm]`), `packaging/arch/PKGBUILD`, `packaging/arch/build-package.sh` und - `packaging/fedora/docker-update.spec` entsprechend aktualisiert werden. +2. **Paketierungsdefinitionen in Cargo.toml pflegen**: + Alle Paketierungsdefinitionen für Debian, RPM und Arch Linux werden zentral in `Cargo.toml` verwaltet + (`[package.metadata.deb]`, `[package.metadata.generate-rpm]`, `[package.metadata.arch]`). Es wird kein separater + `packaging/`-Ordner benötigt. 3. **Automatisierung**: Die empfohlene Automatisierungsmethode ist **Cron** (`/etc/cron.d/docker-update` oder `crontab -e`). 4. **Keine Mocking-Bypässe**: diff --git a/Cargo.toml b/Cargo.toml index 2bb358d..a536004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,9 @@ assets = [ { source = "LICENSE", dest = "/usr/share/licenses/docker-update/LICENSE", mode = "644", license = true }, ] requires = { "sudo" = "*", "docker" = "*" } + +[package.metadata.arch] +pkgrel = "1" +arch = "x86_64" +depends = ["gcc-libs", "glibc", "sudo", "docker"] +optdepends = ["docker-compose: Unterstützung für Docker Compose v1"] diff --git a/README.md b/README.md index a06fbff..092e0e7 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ cargo install cargo-deb cargo deb # Installation des erstellten Pakets -sudo dpkg -i target/debian/docker-update_0.1.0-1_amd64.deb +sudo dpkg -i target/debian/docker-update_*.deb ``` Die Paketkonfiguration und Abhängigkeiten (`sudo`, `docker.io | docker-ce`) sind in `Cargo.toml` unter @@ -242,29 +242,93 @@ Die Paketkonfiguration und Abhängigkeiten (`sudo`, `docker.io | docker-ce`) sin --- -### 2. Arch Linux (`PKGBUILD`) +### 2. Arch Linux (`.pkg.tar.zst`) -Für Arch Linux liegt ein `PKGBUILD` im Verzeichnis `packaging/arch/` bereit: +Die Paketmetadaten und Abhängigkeiten für Arch Linux sind direkt in `Cargo.toml` unter `[package.metadata.arch]` +hinterlegt. Das Paket kann nach dem Kompilieren des Release-Builds über das folgende Skript (analog zu CI/CD) erzeugt +werden: ```bash -cd packaging/arch +# Release kompilieren +cargo build --release -# Paket bauen und installieren -makepkg -si +# Arch Linux-Paket (.pkg.tar.zst) erstellen +python3 - <<'EOF' +import json, os, subprocess, tempfile, time + +metadata = json.loads(subprocess.check_output(["cargo", "metadata", "--format-version", "1", "--no-deps"])) +pkg = metadata["packages"][0] +name = pkg["name"] +version = pkg["version"] +description = pkg.get("description", "") +license = pkg.get("license", "") +repository = pkg.get("repository", "") +authors = pkg.get("authors", []) +author = authors[0] if authors else "Unknown" + +arch_meta = pkg.get("metadata", {}).get("arch", {}) +pkgrel = arch_meta.get("pkgrel", "1") +arch = arch_meta.get("arch", "x86_64") +depends = arch_meta.get("depends", ["gcc-libs", "glibc", "sudo", "docker"]) +optdepends = arch_meta.get("optdepends", ["docker-compose: Unterstützung für Docker Compose v1"]) + +with tempfile.TemporaryDirectory() as build_dir: + bin_dir = os.path.join(build_dir, "usr/bin") + doc_dir = os.path.join(build_dir, f"usr/share/doc/{name}") + lic_dir = os.path.join(build_dir, f"usr/share/licenses/{name}") + os.makedirs(bin_dir, exist_ok=True) + os.makedirs(doc_dir, exist_ok=True) + os.makedirs(lic_dir, exist_ok=True) + + subprocess.run(["install", "-m", "755", f"target/release/{name}", f"{bin_dir}/{name}"], check=True) + if os.path.exists("LICENSE"): + subprocess.run(["install", "-m", "644", "LICENSE", f"{lic_dir}/LICENSE"], check=True) + if os.path.exists("README.md"): + subprocess.run(["install", "-m", "644", "README.md", f"{doc_dir}/README.md"], check=True) + + installed_size = subprocess.check_output(["du", "-sb", build_dir]).decode().split()[0] + builddate = str(int(time.time())) + + pkginfo_lines = [ + f"pkgname = {name}", + f"pkgbase = {name}", + f"pkgver = {version}-{pkgrel}", + f"pkgdesc = {description}", + f"url = {repository}", + f"builddate = {builddate}", + f"packager = {author}", + f"size = {installed_size}", + f"arch = {arch}", + f"license = {license}", + ] + for dep in depends: + pkginfo_lines.append(f"depend = {dep}") + for optdep in optdepends: + pkginfo_lines.append(f"optdepend = {optdep}") + pkginfo_lines.append("makepkgopt = strip\n") + + with open(os.path.join(build_dir, ".PKGINFO"), "w") as f: + f.write("\n".join(pkginfo_lines)) + + os.makedirs("target/arch", exist_ok=True) + output_file = os.path.abspath(f"target/arch/{name}-{version}-{pkgrel}-{arch}.pkg.tar.zst") + subprocess.run(["tar", "--zstd", "-cf", output_file, ".PKGINFO", "usr"], cwd=build_dir, check=True) + print(f"Arch-Paket erfolgreich erstellt: {output_file}") +EOF + +# Installation des erstellten Pakets +sudo pacman -U target/arch/docker-update-*.pkg.tar.zst ``` -Alternativ kann das Binary auch manuell mit `pacman -U .pkg.tar.zst` installiert werden. - --- ### 3. Fedora / RHEL / CentOS (`.rpm`) -Für RPM-basierte Distributionen gibt es zwei Möglichkeiten: - -#### Option A: Mit `cargo-generate-rpm` +Das RPM-Paket wird mithilfe von [`cargo-generate-rpm`](https://github.com/cat-in-136/cargo-generate-rpm) direkt aus den +Metadaten in `Cargo.toml` (`[package.metadata.generate-rpm]`) erstellt: ```bash -# cargo-generate-rpm installieren +# cargo-generate-rpm installieren (falls noch nicht vorhanden) cargo install cargo-generate-rpm # Release bauen und RPM erzeugen @@ -272,19 +336,7 @@ cargo build --release cargo generate-rpm # Installation des erstellten RPM-Pakets -sudo dnf install target/generate-rpm/docker-update-0.1.0-1.*.rpm -``` - -#### Option B: Mit `rpmbuild` und Spec-Datei - -Die RPM-Spec-Datei befindet sich in `packaging/fedora/docker-update.spec`: - -```bash -# Erforderliche Build-Werkzeuge installieren -sudo dnf install rpm-build - -# Paket über rpmbuild erstellen -rpmbuild -ba packaging/fedora/docker-update.spec +sudo dnf install target/generate-rpm/docker-update-*.rpm ``` --- diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD deleted file mode 100644 index 084ca28..0000000 --- a/packaging/arch/PKGBUILD +++ /dev/null @@ -1,40 +0,0 @@ -# Maintainer: DragonSlayer_14 - -pkgname=docker-update -pkgver=0.1.0 -pkgrel=1 -pkgdesc="Automatisches Aktualisieren von Docker-Compose-Anwendungen in /var/apps mit :latest-Images" -arch=('x86_64' 'aarch64') -url="https://gitea.creative-dragonslayer.de/Linuxapps/DockerUpdate" -license=('GPL-3.0-or-later') -depends=('gcc-libs' 'glibc' 'sudo' 'docker') -optdepends=('docker-compose: Unterstützung für Docker Compose v1') -makedepends=('cargo') -source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz") -sha256sums=('SKIP') - -prepare() { - cd "$srcdir/$pkgname-$pkgver" 2>/dev/null || cd "$srcdir/$pkgname" 2>/dev/null || cd "$srcdir" - export RUSTUP_TOOLCHAIN=stable - cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" 2>/dev/null || cargo fetch || true -} - -build() { - cd "$srcdir/$pkgname-$pkgver" 2>/dev/null || cd "$srcdir/$pkgname" 2>/dev/null || cd "$srcdir" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo build --frozen --release --all-targets 2>/dev/null || cargo build --release -} - -check() { - cd "$srcdir/$pkgname-$pkgver" 2>/dev/null || cd "$srcdir/$pkgname" 2>/dev/null || cd "$srcdir" - export RUSTUP_TOOLCHAIN=stable - cargo test --frozen 2>/dev/null || cargo test -} - -package() { - cd "$srcdir/$pkgname-$pkgver" 2>/dev/null || cd "$srcdir/$pkgname" 2>/dev/null || cd "$srcdir" - install -Dm755 "target/release/$pkgname" "$pkgdir/usr/bin/$pkgname" - install -Dm644 "LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE" - install -Dm644 "README.md" "$pkgdir/usr/share/doc/$pkgname/README.md" -} diff --git a/packaging/arch/build-package.sh b/packaging/arch/build-package.sh deleted file mode 100755 index 8c22a03..0000000 --- a/packaging/arch/build-package.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" - -cd "$PROJECT_ROOT" - -if [ ! -f "target/release/docker-update" ]; then - cargo build --release -fi - -VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)" -PKGVER="${VERSION}" -PKGREL="1" -ARCH="x86_64" - -BUILD_DIR="$(mktemp -d)" -trap 'rm -rf "$BUILD_DIR"' EXIT - -mkdir -p "$BUILD_DIR/usr/bin" -mkdir -p "$BUILD_DIR/usr/share/licenses/docker-update" -mkdir -p "$BUILD_DIR/usr/share/doc/docker-update" - -install -m 755 "target/release/docker-update" "$BUILD_DIR/usr/bin/docker-update" -install -m 644 "LICENSE" "$BUILD_DIR/usr/share/licenses/docker-update/LICENSE" -install -m 644 "README.md" "$BUILD_DIR/usr/share/doc/docker-update/README.md" - -INSTALLED_SIZE="$(du -sb "$BUILD_DIR" | awk '{print $1}')" - -cat < "$BUILD_DIR/.PKGINFO" -pkgname = docker-update -pkgbase = docker-update -pkgver = ${PKGVER}-${PKGREL} -pkgdesc = Automatisches Aktualisieren von Docker-Compose-Anwendungen in /var/apps mit :latest-Images -url = https://gitea.creative-dragonslayer.de/Linuxapps/DockerUpdate -builddate = $(date +%s) -packager = DragonSlayer_14 -size = ${INSTALLED_SIZE} -arch = ${ARCH} -license = GPL-3.0-or-later -depend = gcc-libs -depend = glibc -depend = sudo -depend = docker -optdepend = docker-compose: Unterstützung für Docker Compose v1 -makepkgopt = strip -EOF - -mkdir -p "target/arch" -OUTPUT_FILE="$PROJECT_ROOT/target/arch/docker-update-${PKGVER}-${PKGREL}-${ARCH}.pkg.tar.zst" -(cd "$BUILD_DIR" && tar --zstd -cf "$OUTPUT_FILE" .PKGINFO usr) - -echo "Arch-Paket erfolgreich erstellt: $OUTPUT_FILE" diff --git a/packaging/fedora/docker-update.spec b/packaging/fedora/docker-update.spec deleted file mode 100644 index 7db52ce..0000000 --- a/packaging/fedora/docker-update.spec +++ /dev/null @@ -1,42 +0,0 @@ -Name: docker-update -Version: 0.1.0 -Release: 1%{?dist} -Summary: Automatisches Aktualisieren von Docker-Compose-Anwendungen in /var/apps mit :latest-Images - -License: GPL-3.0-or-later -URL: https://gitea.creative-dragonslayer.de/Linuxapps/DockerUpdate -Source0: %{name}-%{version}.tar.gz - -BuildRequires: cargo -BuildRequires: rust -Requires: sudo -Requires: (docker or moby-engine or docker-ce) -Suggests: (docker-compose or docker-compose-plugin) - -%description -DockerUpdate durchsucht Verzeichnisse (standardmäßig in /var/apps) nach -Docker-Compose-Dateien mit ':latest'-Images, prüft auf neuere Images, -lädt diese herunter und startet die betroffenen Container automatisch neu. - -%prep -%autosetup - -%build -cargo build --release - -%check -cargo test - -%install -install -D -p -m 0755 target/release/%{name} %{buildroot}%{_bindir}/%{name} -install -D -p -m 0644 README.md %{buildroot}%{_docdir}/%{name}/README.md -install -D -p -m 0644 LICENSE %{buildroot}%{_licensedir}/%{name}/LICENSE - -%files -%license LICENSE -%doc README.md -%{_bindir}/%{name} - -%changelog -* Sun Aug 23 2026 DragonSlayer_14 - 0.1.0-1 -- Erstveröffentlichung von docker-update