#!/usr/bin/env python3 import subprocess import argparse import os import shutil import sys import re # Sprawdzenie PyYAML try: import yaml except ImportError: print("Błąd: brak modułu 'pyyaml'.") print("Zainstaluj go komendą: pip install pyyaml / zypper in python312-pyaml / apt install python3-yaml") sys.exit(1) def detect_compose_command(): if shutil.which("docker-compose"): return "docker-compose" elif shutil.which("docker"): result = subprocess.run("docker compose version", shell=True, stdout=subprocess.DEVNULL) if result.returncode == 0: return "docker compose" print("Nie znaleziono docker compose ani docker-compose.") sys.exit(1) def run(cmd, capture_output=False): result = subprocess.run(cmd, shell=True, capture_output=capture_output, text=True) if result.returncode != 0: print(f"Błąd: {cmd}") if result.stderr: print(result.stderr) return result.stdout.strip() if capture_output else None def stop_containers(compose_cmd, compose_file, project_name): print("Zatrzymywanie kontenerów...") run(f"{compose_cmd} -p {project_name} -f {compose_file} down") def resolve_env_var(value: str) -> str: pattern = re.compile(r'\$\{([^}:\-]+)(?::-([^}]+))?\}') def replacer(match): var, default = match.groups() return os.environ.get(var, default or "") return pattern.sub(replacer, value) def get_images_from_compose(compose_path): with open(compose_path, "r") as f: data = yaml.safe_load(f) services = data.get("services", {}) resolved_images = [] for svc in services.values(): image = svc.get("image") if image: resolved_images.append(resolve_env_var(image)) return resolved_images def check_for_updates(images): print("Sprawdzanie aktualizacji...") updates = {} for image in images: print(f"- Sprawdzanie obrazu: {image}") pull_result = run(f"docker pull {image}", capture_output=True) if pull_result and "Downloaded newer image" in pull_result: updates[image] = image return updates def remove_conflicting_containers(images): print("Usuwanie kolidujących kontenerów (jeśli istnieją)...") for image in images: name = image.split(":")[0].split("/")[-1] run(f"docker rm -f {name}", capture_output=True) def prune_images(): print("Czyszczenie nieużywanych obrazów...") run("docker image prune -f") def start_containers(compose_cmd, compose_file, project_name): print("Uruchamianie kontenerów...") run(f"{compose_cmd} -p {project_name} -f {compose_file} up -d") def main(): parser = argparse.ArgumentParser(description="Aktualizacja i restart docker-compose projektu.") parser.add_argument('--project-folder', required=True, help='Ścieżka do folderu projektu') parser.add_argument('--compose-file', required=True, help='Ścieżka do pliku docker-compose.yml') parser.add_argument('--project-name', required=True, help='Nazwa projektu docker-compose') args = parser.parse_args() os.chdir(args.project_folder) compose_cmd = detect_compose_command() images = get_images_from_compose(args.compose_file) stop_containers(compose_cmd, args.compose_file, args.project_name) updated = check_for_updates(images) if updated: print("Zaktualizowane obrazy:") for img in updated: print(f"- {img}") prune_images() remove_conflicting_containers(images) start_containers(compose_cmd, args.compose_file, args.project_name) else: print("Obrazy aktualne. Nie uruchamiam kontenerów.") print("Zakończono.") if __name__ == "__main__": main()