modified: app.py

modified:   config.json
	modified:   projects_list.json
	modified:   templates/available_projects.html
This commit is contained in:
SimolZimol
2025-07-06 23:55:19 +02:00
parent f61aa780de
commit 515a007d39
4 changed files with 267 additions and 10 deletions

120
app.py
View File

@@ -6,6 +6,9 @@ import json
import re
import time
import shutil
import urllib.request
import urllib.error
import tempfile
from urllib.parse import urlparse
import docker
import yaml
@@ -493,6 +496,66 @@ class ProjectManager:
except Exception as e:
return False, f"Fehler beim Herunterladen des Images: {str(e)}"
def load_docker_image_from_url(self, image_url, project_name):
"""Lade Docker-Image von einer URL herunter (z.B. .tar Datei)"""
if not self.docker_available:
return False, "Docker ist nicht verfügbar"
try:
print(f"Lade Docker-Image von URL herunter: {image_url}")
# Temporärer Dateiname für Download
with tempfile.NamedTemporaryFile(suffix='.tar', delete=False) as temp_file:
temp_path = temp_file.name
# Image von URL herunterladen
print(f"Lade Datei herunter: {image_url}")
urllib.request.urlretrieve(image_url, temp_path)
# Docker-Image aus Datei laden
print(f"Importiere Docker-Image aus Datei...")
with open(temp_path, 'rb') as f:
images = self.docker_client.images.load(f)
# Versuche das Image mit Projektname zu taggen
if images:
image = images[0] if isinstance(images, list) else images
image.tag(f"{project_name}:latest")
print(f"✓ Docker-Image von URL erfolgreich geladen und getaggt als {project_name}:latest")
else:
return False, "Kein Image aus der geladenen Datei gefunden"
# Temporäre Datei löschen
os.unlink(temp_path)
# Erstelle minimales Projektverzeichnis für Konfiguration
project_path = os.path.join(PROJECTS_DIR, project_name)
os.makedirs(project_path, exist_ok=True)
# Erstelle .dockerurl Datei um zu markieren, dass es ein URL-Download ist
with open(os.path.join(project_path, '.dockerurl'), 'w', encoding='utf-8') as f:
json.dump({
'image_url': image_url,
'loaded_at': datetime.now().isoformat(),
'installation_method': 'docker_url'
}, f, indent=2)
return True, f"Docker-Image {project_name} erfolgreich von URL geladen"
except urllib.error.URLError as e:
return False, f"URL-Fehler beim Herunterladen: {str(e)}"
except docker.errors.APIError as e:
return False, f"Docker-API-Fehler beim Laden: {str(e)}"
except Exception as e:
return False, f"Fehler beim Laden des Images von URL: {str(e)}"
finally:
# Stelle sicher, dass temporäre Datei gelöscht wird
try:
if 'temp_path' in locals() and os.path.exists(temp_path):
os.unlink(temp_path)
except:
pass
def get_installation_methods(self, project):
"""Ermittle verfügbare Installationsmethoden für ein Projekt"""
methods = []
@@ -1210,25 +1273,73 @@ def install_project():
})
# Neue Installation basierend auf Methode
if installation_method == 'image':
# Docker-Image herunterladen
if installation_method in ['image', 'docker_image', 'docker_registry']:
# Docker-Image herunterladen (aus Registry)
success, message = project_manager.pull_docker_image(project_url, project_name)
if success:
# Nach erfolgreichem Download die Version speichern
try:
project_manager.save_project_version(project_name, project_url, installation_method='image')
project_manager.save_project_version(project_name, project_url, installation_method=installation_method)
except Exception as e:
print(f"Warnung: Konnte Version nach Image-Download nicht speichern: {e}")
return jsonify({
'success': True,
'message': f'{message}. Bereit zum Starten.',
'method': 'image'
'method': installation_method
})
else:
return jsonify({'success': False, 'message': message})
elif installation_method in ['docker_url', 'docker_file']:
# Docker-Image von URL herunterladen (z.B. .tar Datei)
success, message = project_manager.load_docker_image_from_url(project_url, project_name)
if success:
try:
project_manager.save_project_version(project_name, project_url, installation_method=installation_method)
except Exception as e:
print(f"Warnung: Konnte Version nach URL-Download nicht speichern: {e}")
return jsonify({
'success': True,
'message': f'{message}. Bereit zum Starten.',
'method': installation_method
})
else:
return jsonify({'success': False, 'message': message})
elif installation_method in ['dockerfile', 'docker_build']:
# Dockerfile-basierte Installation: Klone Repository und baue Docker-Image
print(f"🐳 Dockerfile-Installation für {project_name} von {project_url}")
# Erst klonen, dann Docker-Image bauen
success, message = project_manager.clone_project(project_url, project_name)
if success:
# Versuche Docker-Image aus Dockerfile zu bauen
build_success, build_message = project_manager.build_project(project_name)
if build_success:
# Nach erfolgreichem Build die Version speichern
try:
project_manager.save_project_version(project_name, project_url, installation_method='dockerfile')
except Exception as e:
print(f"Warnung: Konnte Version nach Docker-Build nicht speichern: {e}")
return jsonify({
'success': True,
'message': f'Projekt geklont und Docker-Image gebaut: {build_message}',
'method': 'dockerfile'
})
else:
return jsonify({
'success': False,
'message': f'Projekt geklont, aber Docker-Build fehlgeschlagen: {build_message}'
})
else:
return jsonify({'success': False, 'message': message})
else:
# Standard: Git Clone
success, message = project_manager.clone_project(project_url, project_name)
@@ -1792,6 +1903,7 @@ def api_check_port(port):
'available': available,
'message': f'Port {port} ist {"verfügbar" if available else "belegt"}'
})
except Exception as e:
return jsonify({
'success': False,

View File

@@ -45,7 +45,7 @@
"description": "Quellcode klonen und selbst bauen"
},
"docker_registry": {
"available": false,
"available": true,
"url": "docker.io/simolzimol/quizify:1.3.0",
"type": "docker_registry",
"description": "Offizielles Docker-Image von Registry"
@@ -57,7 +57,7 @@
"description": "Docker-Image-Datei von Webserver"
},
"docker_url": {
"available": false,
"available": true,
"url": "https://simolzimol.eu/images/quizify-1.3.0.tar",
"type": "docker_url",
"description": "Docker-Image direkt von URL laden"
@@ -73,7 +73,7 @@
"license": "MIT",
"homepage": "https://gitea.simolzimol.net/Simon/quizify",
"documentation": {
"available": true,
"available": false,
"url": "https://gitea.simolzimol.net/Simon/quizify/wiki"
},
"issues": {

View File

@@ -34,9 +34,21 @@
"url": "docker.io/simolzimol/quizify:1.3.0",
"type": "docker",
"description": "Vorgefertigtes Docker-Image herunterladen"
},
"docker_registry": {
"available": true,
"url": "simolzimol/quizify:latest",
"type": "docker",
"description": "Von Docker Registry herunterladen"
},
"docker_file": {
"available": true,
"url": "https://simolzimol.eu/images/quizify-1.3.0.tar",
"type": "docker_file",
"description": "Docker-Image-Datei von Webserver herunterladen"
}
},
"preferred": "clone"
"preferred": "image"
},
"metadata": {
"created": "2024-01-15",
@@ -205,6 +217,24 @@
"url": "docker.io/example/media-server:2.1.0",
"type": "docker",
"description": "Fertiges Docker-Image"
},
"docker_registry": {
"available": true,
"url": "example/media-server:2.1.0",
"type": "docker",
"description": "Von Docker Hub Registry"
},
"docker_url": {
"available": true,
"url": "https://github.com/example/media-server/releases/download/v2.1.0/media-server-docker.tar",
"type": "docker",
"description": "Docker-Image als .tar Datei herunterladen"
},
"docker_file": {
"available": true,
"url": "https://github.com/example/media-server",
"type": "dockerfile",
"description": "Mit Dockerfile selbst bauen"
}
},
"preferred": "image"
@@ -265,5 +295,108 @@
"cpu_cores": 2,
"disk_mb": 1000
}
},
{
"url": "https://github.com/nginx/nginx",
"name": "nginx-server",
"description": "High-performance HTTP server und reverse proxy",
"language": "C",
"tags": ["webserver", "proxy", "http", "nginx", "performance"],
"category": "Web Server",
"docker_port": 80,
"environment_vars": {
"NGINX_HOST": "localhost",
"NGINX_PORT": "80"
},
"installation": {
"methods": {
"clone": {
"available": true,
"url": "https://github.com/nginx/nginx",
"type": "git",
"description": "Nginx Quellcode klonen und kompilieren"
},
"image": {
"available": true,
"url": "nginx:latest",
"type": "docker",
"description": "Offizielles Nginx Docker-Image"
},
"docker_registry": {
"available": true,
"url": "nginx:alpine",
"type": "docker",
"description": "Lightweight Alpine Nginx von Registry"
},
"docker_file": {
"available": true,
"url": "https://hub.docker.com/v2/repositories/nginx/tags/alpine/images",
"type": "docker_file",
"description": "Nginx Docker-Image als Archiv herunterladen"
},
"docker_url": {
"available": true,
"url": "https://github.com/nginxinc/docker-nginx/archive/refs/heads/master.tar.gz",
"type": "docker_url",
"description": "Nginx Docker-Build von GitHub"
}
},
"preferred": "image"
},
"metadata": {
"created": "1994-01-01",
"last_updated": "2025-07-06",
"version": "1.24.0",
"author": "Igor Sysoev",
"license": "BSD-2-Clause",
"homepage": "https://nginx.org",
"documentation": {
"available": true,
"url": "https://nginx.org/en/docs/"
},
"issues": {
"available": true,
"url": "https://github.com/nginx/nginx/issues"
},
"downloads": 50000,
"stars": 18500
},
"features": [
"High-performance HTTP server",
"Reverse proxy server",
"Load balancer",
"Mail proxy server",
"HTTP cache",
"SSL/TLS termination",
"WebSocket support",
"HTTP/2 support"
],
"screenshots": {
"available": false,
"urls": []
},
"demo": {
"available": false,
"url": "",
"description": ""
},
"installation_notes": "Standard Nginx-Server. Kann als Webserver oder Reverse Proxy verwendet werden.",
"config_hints": {
"env_example": "Standard Nginx-Konfiguration",
"dockerfile": "Multi-stage Build verfügbar",
"docker_compose": "Einfache Nginx-Konfiguration"
},
"rating": {
"score": 4.8,
"reviews": 850,
"downloads": 50000
},
"size_mb": 25,
"install_time": "30 Sekunden",
"min_resources": {
"ram_mb": 64,
"cpu_cores": 1,
"disk_mb": 100
}
}
]

View File

@@ -255,8 +255,10 @@
data-method="{{ preferred_method }}"
onclick="installProject('{{ preferred.url }}', '{{ project.name }}', '{{ preferred_method }}')">
<i class="fas fa-download me-1"></i>
{% if preferred_method == 'image' %}
{% if preferred_method in ['image', 'docker_registry', 'docker_url', 'docker_file'] %}
<i class="fab fa-docker me-1"></i>Docker
{% elif preferred_method in ['docker_build', 'dockerfile'] %}
<i class="fas fa-cog me-1"></i>Build
{% else %}
<i class="fab fa-git-alt me-1"></i>Code
{% endif %}
@@ -272,8 +274,18 @@
onclick="installProject('{{ method_info.url }}', '{{ project.name }}', '{{ method_type }}'); return false;">
{% if method_type == 'image' %}
<i class="fab fa-docker me-2 text-primary"></i>Docker Image herunterladen
{% else %}
{% elif method_type == 'docker_registry' %}
<i class="fab fa-docker me-2 text-info"></i>Docker Registry Pull
{% elif method_type == 'docker_url' %}
<i class="fas fa-cloud-download-alt me-2 text-warning"></i>Docker .tar von URL laden
{% elif method_type == 'docker_file' %}
<i class="fas fa-file-archive me-2 text-warning"></i>Docker-Image-Datei herunterladen
{% elif method_type == 'docker_build' or method_type == 'dockerfile' %}
<i class="fas fa-cog me-2 text-secondary"></i>Mit Dockerfile bauen
{% elif method_type == 'clone' %}
<i class="fab fa-git-alt me-2 text-success"></i>Quellcode klonen
{% else %}
<i class="fas fa-download me-2"></i>{{ method_type|title }}
{% endif %}
<small class="text-muted d-block">{{ method_info.description }}</small>
</a>