1. **Entfernung von 'node_modules'**: Es scheint, dass Sie den 'node_modules'-Ordner entfernt oder aktualisiert haben, da einige Dateien wie '.gitignore', 'package
609 lines
19 KiB
Python
609 lines
19 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
MYP (Manage Your Printers) Installer
|
|
=====================================
|
|
|
|
Universeller Installer für das MYP Druckerverwaltungssystem.
|
|
Unterstützt Installation, Kiosk-Modus und Desktop-Icon-Erstellung.
|
|
|
|
Aufruf vom Stammverzeichnis aus:
|
|
python install.py # Interaktive Installation
|
|
python install.py --kiosk # Direktinstallation mit Kiosk-Modus
|
|
python install.py --desktop-icon # Nur Desktop-Icon erstellen
|
|
python install.py --help # Hilfe anzeigen
|
|
|
|
Autor: Till Tomczak
|
|
Version: 2.0
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import argparse
|
|
import shutil
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
class MYPInstaller:
|
|
"""
|
|
Hauptinstaller-Klasse für das MYP System.
|
|
|
|
Verwaltet die komplette Installation inklusive:
|
|
- Systemabhängigkeiten
|
|
- Python-Packages
|
|
- Kiosk-Modus-Konfiguration
|
|
- Desktop-Integration
|
|
- Service-Setup
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.root_dir = Path(__file__).parent
|
|
self.backend_dir = self.root_dir / "backend"
|
|
self.setup_dir = self.backend_dir / "setup"
|
|
self.is_root = os.geteuid() == 0 if hasattr(os, 'geteuid') else False
|
|
|
|
# System-Erkennung
|
|
self.is_raspberry_pi = self._detect_raspberry_pi()
|
|
self.is_debian = self._detect_debian()
|
|
|
|
print(f"""
|
|
{'='*70}
|
|
🏭 MYP (MANAGE YOUR PRINTERS) INSTALLER
|
|
{'='*70}
|
|
|
|
🎯 Mercedes-Benz Druckerverwaltungssystem
|
|
🔧 Universal-Installer für alle Plattformen
|
|
📍 Arbeitsverzeichnis: {self.root_dir}
|
|
|
|
🔍 SYSTEM-ERKENNUNG:
|
|
• Raspberry Pi: {'✅ JA' if self.is_raspberry_pi else '❌ NEIN'}
|
|
• Debian/Ubuntu: {'✅ JA' if self.is_debian else '❌ NEIN'}
|
|
• Root-Rechte: {'✅ JA' if self.is_root else '❌ NEIN'}
|
|
|
|
{'='*70}
|
|
""")
|
|
|
|
def _detect_raspberry_pi(self):
|
|
"""Erkennt Raspberry Pi Hardware"""
|
|
try:
|
|
with open('/proc/cpuinfo', 'r') as f:
|
|
cpuinfo = f.read()
|
|
return 'raspberry pi' in cpuinfo.lower() or 'bcm' in cpuinfo.lower()
|
|
except:
|
|
return False
|
|
|
|
def _detect_debian(self):
|
|
"""Erkennt Debian-basierte Systeme"""
|
|
try:
|
|
return os.path.exists('/etc/debian_version')
|
|
except:
|
|
return False
|
|
|
|
def check_prerequisites(self):
|
|
"""
|
|
Prüft Systemvoraussetzungen für die Installation.
|
|
|
|
Returns:
|
|
bool: True wenn alle Voraussetzungen erfüllt sind
|
|
"""
|
|
print("🔍 VORAUSSETZUNGSPRÜFUNG")
|
|
print("-" * 40)
|
|
|
|
checks = []
|
|
|
|
# Python-Version
|
|
if sys.version_info >= (3, 8):
|
|
checks.append("✅ Python 3.8+ verfügbar")
|
|
else:
|
|
checks.append("❌ Python 3.8+ erforderlich")
|
|
return False
|
|
|
|
# Git verfügbar
|
|
try:
|
|
subprocess.run(['git', '--version'], capture_output=True, check=True)
|
|
checks.append("✅ Git verfügbar")
|
|
except:
|
|
checks.append("❌ Git nicht gefunden")
|
|
|
|
# Projekt-Struktur
|
|
required_paths = [
|
|
self.backend_dir,
|
|
self.backend_dir / "app.py",
|
|
self.backend_dir / "requirements.txt",
|
|
self.setup_dir
|
|
]
|
|
|
|
for path in required_paths:
|
|
if path.exists():
|
|
checks.append(f"✅ {path.name}")
|
|
else:
|
|
checks.append(f"❌ {path.name} fehlt")
|
|
return False
|
|
|
|
# Systemtools (nur auf Linux)
|
|
if self.is_debian:
|
|
tools = ['systemctl', 'nginx', 'ufw']
|
|
for tool in tools:
|
|
try:
|
|
subprocess.run(['which', tool], capture_output=True, check=True)
|
|
checks.append(f"✅ {tool} verfügbar")
|
|
except:
|
|
checks.append(f"⚠️ {tool} nicht gefunden (wird installiert)")
|
|
|
|
for check in checks:
|
|
print(f" {check}")
|
|
|
|
print("✅ Voraussetzungen erfüllt\n")
|
|
return True
|
|
|
|
def install_system_dependencies(self):
|
|
"""
|
|
Installiert System-Abhängigkeiten über den Package-Manager.
|
|
"""
|
|
if not self.is_debian:
|
|
print("⚠️ Überspringe System-Dependencies (nicht Debian-basiert)")
|
|
return True
|
|
|
|
print("📦 SYSTEM-ABHÄNGIGKEITEN INSTALLIEREN")
|
|
print("-" * 40)
|
|
|
|
# Basis-Pakete
|
|
packages = [
|
|
'python3-pip',
|
|
'python3-venv',
|
|
'nodejs',
|
|
'npm',
|
|
'nginx',
|
|
'ufw',
|
|
'sqlite3',
|
|
'git',
|
|
'curl',
|
|
'wget',
|
|
'unzip'
|
|
]
|
|
|
|
# Raspberry Pi spezifische Pakete
|
|
if self.is_raspberry_pi:
|
|
packages.extend([
|
|
'chromium-browser',
|
|
'xorg',
|
|
'openbox',
|
|
'lightdm',
|
|
'python3-gpiozero' # Für Hardware-Integration
|
|
])
|
|
|
|
try:
|
|
print(" Aktualisiere Package-Listen...")
|
|
subprocess.run(['sudo', 'apt', 'update'], check=True)
|
|
|
|
print(f" Installiere {len(packages)} Pakete...")
|
|
subprocess.run(['sudo', 'apt', 'install', '-y'] + packages, check=True)
|
|
|
|
print("✅ System-Abhängigkeiten installiert\n")
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Fehler bei System-Installation: {e}")
|
|
return False
|
|
|
|
def install_python_dependencies(self):
|
|
"""
|
|
Installiert Python-Dependencies aus requirements.txt.
|
|
"""
|
|
print("🐍 PYTHON-ABHÄNGIGKEITEN INSTALLIEREN")
|
|
print("-" * 40)
|
|
|
|
requirements_file = self.backend_dir / "requirements.txt"
|
|
|
|
try:
|
|
# Virtual Environment erstellen (optional, aber empfohlen)
|
|
venv_path = self.backend_dir / "venv"
|
|
if not venv_path.exists():
|
|
print(" Erstelle Virtual Environment...")
|
|
subprocess.run([sys.executable, '-m', 'venv', str(venv_path)], check=True)
|
|
|
|
# Requirements installieren
|
|
print(" Installiere Python-Packages...")
|
|
if self.is_debian:
|
|
# Auf Debian: --break-system-packages für pip
|
|
subprocess.run([
|
|
sys.executable, '-m', 'pip', 'install', '-r', str(requirements_file),
|
|
'--break-system-packages'
|
|
], check=True, cwd=self.backend_dir)
|
|
else:
|
|
subprocess.run([
|
|
sys.executable, '-m', 'pip', 'install', '-r', str(requirements_file)
|
|
], check=True, cwd=self.backend_dir)
|
|
|
|
print("✅ Python-Dependencies installiert\n")
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Fehler bei Python-Installation: {e}")
|
|
return False
|
|
|
|
def build_frontend_assets(self):
|
|
"""
|
|
Baut Frontend-Assets (CSS, JavaScript).
|
|
"""
|
|
print("🎨 FRONTEND-ASSETS BAUEN")
|
|
print("-" * 40)
|
|
|
|
try:
|
|
# npm-Dependencies installieren
|
|
print(" Installiere npm-Dependencies...")
|
|
subprocess.run(['npm', 'install'], check=True, cwd=self.backend_dir)
|
|
|
|
# TailwindCSS bauen
|
|
print(" Baue TailwindCSS...")
|
|
subprocess.run(['npm', 'run', 'build'], check=True, cwd=self.backend_dir)
|
|
|
|
print("✅ Frontend-Assets gebaut\n")
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Fehler beim Asset-Build: {e}")
|
|
return False
|
|
|
|
def setup_database(self):
|
|
"""
|
|
Initialisiert die SQLite-Datenbank.
|
|
"""
|
|
print("🗄️ DATENBANK INITIALISIEREN")
|
|
print("-" * 40)
|
|
|
|
try:
|
|
# Instance-Verzeichnis erstellen
|
|
instance_dir = self.backend_dir / "instance"
|
|
instance_dir.mkdir(exist_ok=True)
|
|
|
|
# Datenbank initialisieren
|
|
print(" Initialisiere SQLite-Datenbank...")
|
|
subprocess.run([
|
|
sys.executable, '-c',
|
|
'from models import init_database; init_database()'
|
|
], check=True, cwd=self.backend_dir)
|
|
|
|
print("✅ Datenbank initialisiert\n")
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Fehler bei Datenbank-Setup: {e}")
|
|
return False
|
|
|
|
def setup_kiosk_mode(self):
|
|
"""
|
|
Konfiguriert Kiosk-Modus für Raspberry Pi.
|
|
"""
|
|
if not self.is_raspberry_pi:
|
|
print("⚠️ Kiosk-Modus nur auf Raspberry Pi verfügbar")
|
|
return True
|
|
|
|
print("🖥️ KIOSK-MODUS KONFIGURIEREN")
|
|
print("-" * 40)
|
|
|
|
try:
|
|
# Kiosk-Skript erstellen
|
|
kiosk_script = Path("/home/pi/kiosk.sh")
|
|
kiosk_content = """#!/bin/bash
|
|
|
|
# MYP Kiosk-Modus Startskript
|
|
# Startet Chromium im Vollbild-Modus
|
|
|
|
# Warten auf Netzwerk
|
|
sleep 10
|
|
|
|
# Bildschirmschoner deaktivieren
|
|
xset s off
|
|
xset -dpms
|
|
xset s noblank
|
|
|
|
# Chromium im Kiosk-Modus starten
|
|
chromium-browser \\
|
|
--no-sandbox \\
|
|
--disable-infobars \\
|
|
--disable-restore-session-state \\
|
|
--disable-session-crashed-bubble \\
|
|
--disable-features=TranslateUI \\
|
|
--kiosk \\
|
|
--app=https://localhost/
|
|
"""
|
|
|
|
with open(kiosk_script, 'w') as f:
|
|
f.write(kiosk_content)
|
|
|
|
# Ausführbar machen
|
|
kiosk_script.chmod(stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
|
|
|
|
# Autostart konfigurieren
|
|
autostart_dir = Path("/home/pi/.config/autostart")
|
|
autostart_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
desktop_entry = autostart_dir / "myp-kiosk.desktop"
|
|
desktop_content = f"""[Desktop Entry]
|
|
Type=Application
|
|
Name=MYP Kiosk
|
|
Exec={kiosk_script}
|
|
Hidden=false
|
|
NoDisplay=false
|
|
X-GNOME-Autostart-enabled=true
|
|
"""
|
|
|
|
with open(desktop_entry, 'w') as f:
|
|
f.write(desktop_content)
|
|
|
|
print(" ✅ Kiosk-Skript erstellt")
|
|
print(" ✅ Autostart konfiguriert")
|
|
print("✅ Kiosk-Modus konfiguriert\n")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"❌ Fehler bei Kiosk-Setup: {e}")
|
|
return False
|
|
|
|
def create_desktop_icon(self):
|
|
"""
|
|
Erstellt Desktop-Icon für MYP.
|
|
"""
|
|
print("🖱️ DESKTOP-ICON ERSTELLEN")
|
|
print("-" * 40)
|
|
|
|
try:
|
|
# Desktop-Verzeichnis finden
|
|
desktop_dirs = [
|
|
Path.home() / "Desktop",
|
|
Path.home() / "Schreibtisch",
|
|
Path("/home/pi/Desktop")
|
|
]
|
|
|
|
desktop_dir = None
|
|
for dir_path in desktop_dirs:
|
|
if dir_path.exists():
|
|
desktop_dir = dir_path
|
|
break
|
|
|
|
if not desktop_dir:
|
|
print("⚠️ Desktop-Verzeichnis nicht gefunden")
|
|
return True
|
|
|
|
# Icon-Datei kopieren
|
|
icon_source = self.backend_dir / "static" / "favicon.svg"
|
|
icon_dest = desktop_dir / "myp-icon.svg"
|
|
|
|
if icon_source.exists():
|
|
shutil.copy2(icon_source, icon_dest)
|
|
|
|
# Desktop-Entry erstellen
|
|
desktop_file = desktop_dir / "MYP-Druckerverwaltung.desktop"
|
|
desktop_content = f"""
|
|
[Desktop Entry]
|
|
Version=1.0
|
|
Type=Application
|
|
Name=MYP Druckerverwaltung
|
|
Comment=Mercedes-Benz Druckerverwaltungssystem
|
|
Icon={icon_dest}
|
|
Exec=python3 {self.backend_dir}/app.py
|
|
Terminal=false
|
|
Categories=Application;Office;
|
|
StartupNotify=true
|
|
"""
|
|
|
|
with open(desktop_file, 'w') as f:
|
|
f.write(desktop_content)
|
|
|
|
# Ausführbar machen
|
|
desktop_file.chmod(stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
|
|
|
|
print(f" ✅ Desktop-Icon erstellt: {desktop_file}")
|
|
print("✅ Desktop-Integration abgeschlossen\n")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"❌ Fehler bei Desktop-Icon: {e}")
|
|
return False
|
|
|
|
def setup_systemd_services(self):
|
|
"""
|
|
Installiert systemd-Services für automatischen Start.
|
|
"""
|
|
if not self.is_debian or not self.is_root:
|
|
print("⚠️ Service-Setup erfordert Debian + Root-Rechte")
|
|
return True
|
|
|
|
print("⚙️ SYSTEMD-SERVICES INSTALLIEREN")
|
|
print("-" * 40)
|
|
|
|
try:
|
|
# Service-Dateien kopieren
|
|
systemd_dir = self.backend_dir / "systemd"
|
|
if systemd_dir.exists():
|
|
for service_file in systemd_dir.glob("*.service"):
|
|
dest = Path("/etc/systemd/system") / service_file.name
|
|
shutil.copy2(service_file, dest)
|
|
print(f" ✅ {service_file.name} installiert")
|
|
|
|
# Services aktivieren
|
|
services = ["myp-https.service"]
|
|
if self.is_raspberry_pi:
|
|
services.append("myp-kiosk.service")
|
|
|
|
for service in services:
|
|
subprocess.run(['systemctl', 'daemon-reload'], check=True)
|
|
subprocess.run(['systemctl', 'enable', service], check=True)
|
|
print(f" ✅ {service} aktiviert")
|
|
|
|
print("✅ SystemD-Services installiert\n")
|
|
return True
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Fehler bei Service-Setup: {e}")
|
|
return False
|
|
|
|
def run_full_installation(self):
|
|
"""
|
|
Führt die komplette Installation durch.
|
|
"""
|
|
print("🚀 VOLLSTÄNDIGE INSTALLATION STARTEN")
|
|
print("=" * 50)
|
|
|
|
steps = [
|
|
("Voraussetzungen prüfen", self.check_prerequisites),
|
|
("System-Abhängigkeiten", self.install_system_dependencies),
|
|
("Python-Dependencies", self.install_python_dependencies),
|
|
("Frontend-Assets", self.build_frontend_assets),
|
|
("Datenbank", self.setup_database),
|
|
("SystemD-Services", self.setup_systemd_services)
|
|
]
|
|
|
|
for step_name, step_func in steps:
|
|
print(f"\n📋 SCHRITT: {step_name}")
|
|
if not step_func():
|
|
print(f"\n❌ INSTALLATION FEHLGESCHLAGEN bei: {step_name}")
|
|
return False
|
|
|
|
print(f"""
|
|
{'='*70}
|
|
🎉 INSTALLATION ERFOLGREICH ABGESCHLOSSEN!
|
|
{'='*70}
|
|
|
|
✅ MYP Druckerverwaltungssystem wurde installiert
|
|
|
|
🔧 NÄCHSTE SCHRITTE:
|
|
1. System neustarten (empfohlen)
|
|
2. MYP-Service starten: sudo systemctl start myp-https
|
|
3. Browser öffnen: https://localhost/
|
|
|
|
📝 WICHTIGE HINWEISE:
|
|
• Standard-Admin: admin / admin123
|
|
• Logs: {self.backend_dir}/logs/
|
|
• Konfiguration: {self.backend_dir}/config/
|
|
|
|
🎯 MERCEDES-BENZ DRUCKERVERWALTUNG BEREIT!
|
|
{'='*70}
|
|
""")
|
|
return True
|
|
|
|
def run_kiosk_installation(self):
|
|
"""
|
|
Führt Installation mit Kiosk-Modus durch.
|
|
"""
|
|
print("🖥️ KIOSK-INSTALLATION STARTEN")
|
|
print("=" * 40)
|
|
|
|
# Basis-Installation
|
|
if not self.run_full_installation():
|
|
return False
|
|
|
|
# Kiosk-Modus konfigurieren
|
|
if not self.setup_kiosk_mode():
|
|
return False
|
|
|
|
print(f"""
|
|
🎉 KIOSK-INSTALLATION ABGESCHLOSSEN!
|
|
|
|
🖥️ Das System startet automatisch im Kiosk-Modus
|
|
• Vollbild-Browser mit MYP
|
|
• Automatischer Start nach Boot
|
|
• Bildschirmschoner deaktiviert
|
|
|
|
🔄 Neustart erforderlich für Kiosk-Aktivierung
|
|
""")
|
|
return True
|
|
|
|
|
|
def main():
|
|
"""Haupt-Installer-Funktion mit Argument-Parsing"""
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="MYP Druckerverwaltungssystem Installer",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
BEISPIELE:
|
|
python install.py # Interaktive Installation
|
|
python install.py --kiosk # Installation mit Kiosk-Modus
|
|
python install.py --desktop-icon # Nur Desktop-Icon erstellen
|
|
python install.py --full --kiosk # Vollinstallation + Kiosk
|
|
|
|
SYSTEMANFORDERUNGEN:
|
|
• Python 3.8+
|
|
• Debian/Ubuntu (empfohlen)
|
|
• Root-Rechte für System-Services
|
|
• Raspberry Pi für Kiosk-Modus
|
|
"""
|
|
)
|
|
|
|
parser.add_argument('--full', action='store_true',
|
|
help='Vollständige Installation durchführen')
|
|
parser.add_argument('--kiosk', action='store_true',
|
|
help='Kiosk-Modus aktivieren')
|
|
parser.add_argument('--desktop-icon', action='store_true',
|
|
help='Desktop-Icon erstellen')
|
|
parser.add_argument('--no-deps', action='store_true',
|
|
help='System-Dependencies überspringen')
|
|
parser.add_argument('--force', action='store_true',
|
|
help='Installation trotz Warnungen fortsetzen')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Installer initialisieren
|
|
installer = MYPInstaller()
|
|
|
|
# Kein Argument = Interaktive Installation
|
|
if not any([args.full, args.kiosk, args.desktop_icon]):
|
|
print("""
|
|
🤔 INSTALLATIONSART WÄHLEN:
|
|
|
|
1) Vollständige Installation (empfohlen)
|
|
2) Installation mit Kiosk-Modus (Raspberry Pi)
|
|
3) Nur Desktop-Icon erstellen
|
|
4) Abbrechen
|
|
|
|
Ihre Wahl [1-4]: """, end="")
|
|
|
|
try:
|
|
choice = input().strip()
|
|
if choice == '1':
|
|
args.full = True
|
|
elif choice == '2':
|
|
args.kiosk = True
|
|
elif choice == '3':
|
|
args.desktop_icon = True
|
|
else:
|
|
print("Installation abgebrochen.")
|
|
return
|
|
except KeyboardInterrupt:
|
|
print("\nInstallation abgebrochen.")
|
|
return
|
|
|
|
# Installation ausführen
|
|
success = True
|
|
|
|
if args.desktop_icon:
|
|
success = installer.create_desktop_icon()
|
|
elif args.kiosk:
|
|
success = installer.run_kiosk_installation()
|
|
elif args.full:
|
|
success = installer.run_full_installation()
|
|
if success and installer.is_raspberry_pi:
|
|
create_kiosk = input("\n🖥️ Kiosk-Modus aktivieren? [j/N]: ").lower().startswith('j')
|
|
if create_kiosk:
|
|
installer.setup_kiosk_mode()
|
|
|
|
# Ergebnis
|
|
if success:
|
|
print("\n🎉 Installation erfolgreich!")
|
|
|
|
# Desktop-Icon anbieten falls nicht bereits erstellt
|
|
if not args.desktop_icon and not args.kiosk:
|
|
create_icon = input("🖱️ Desktop-Icon erstellen? [j/N]: ").lower().startswith('j')
|
|
if create_icon:
|
|
installer.create_desktop_icon()
|
|
|
|
sys.exit(0)
|
|
else:
|
|
print("\n❌ Installation fehlgeschlagen!")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |