142 lines
4.7 KiB
Python
142 lines
4.7 KiB
Python
import subprocess
|
|
import os
|
|
import shutil
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
|
|
def force_remove_all(path: str):
|
|
"""Erzwingt das Loeschen von Dateien und Ordnern mit chmod 0o666 fuer ALLE."""
|
|
path = Path(path)
|
|
|
|
if not path.exists():
|
|
return
|
|
|
|
# ✅ ZUERST: Alles auf Schreibbar setzen (auch schreibgeschuetzte .git files!)
|
|
for root, dirs, files in os.walk(str(path), topdown=False):
|
|
for d in dirs:
|
|
try:
|
|
dir_path = Path(root) / d
|
|
dir_path.chmod(0o755 | stat.S_IWUSR)
|
|
except Exception:
|
|
pass
|
|
for f in files:
|
|
try:
|
|
file_path = Path(root) / f
|
|
file_path.chmod(0o666) # Wichtig: Alles beschreibbar fuer Loeschen!
|
|
except Exception:
|
|
pass
|
|
|
|
# Jetzt die Root-Ordner auch beschreibbar machen
|
|
try:
|
|
path.chmod(0o755 | stat.S_IWUSR)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def set_permissions(path: str):
|
|
"""Setzt korrekte POSIX-Berechtigungen fuer ein Verzeichnis nach dem Klonen."""
|
|
try:
|
|
# Ordner = 755 (rwxr-xr-x)
|
|
os.chmod(str(path), 0o755)
|
|
|
|
# Rekursiv alle Teildateien bearbeiten
|
|
for root, dirs, files in os.walk(str(path)):
|
|
for d in dirs:
|
|
full_path = os.path.join(root, d)
|
|
try:
|
|
os.chmod(full_path, 0o755)
|
|
except Exception:
|
|
pass
|
|
for f in files:
|
|
full_path = os.path.join(root, f)
|
|
try:
|
|
# Nur les- und schreibbar fuer owner, sonst nur lesen
|
|
os.chmod(full_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
|
|
except Exception:
|
|
pass
|
|
|
|
# Nachher auch den Hauptordner beschreiben machen
|
|
os.chmod(str(path), 0o755)
|
|
except Exception as e:
|
|
print(f"Warnung bei Berechtigungen: {e}")
|
|
|
|
|
|
def clone_repo(repo_url: str, target_dir: Path, token: str = None):
|
|
"""Klont ein Repository in den Zielordner."""
|
|
if not target_dir.exists():
|
|
target_dir.mkdir(parents=True)
|
|
|
|
# URL mit Token (falls noetig)
|
|
if token and "@" not in repo_url:
|
|
repo_url = repo_url.replace("https://", f"https://{token}@")
|
|
|
|
result = subprocess.run(
|
|
["git", "clone", repo_url, str(target_dir)],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
# ✅ BERECHTIGUNGEN NACH DEM KLOONEN SETZEN!
|
|
if result.returncode == 0:
|
|
set_permissions(str(target_dir))
|
|
|
|
return {"success": result.returncode == 0, "output": result.stdout, "error": result.stderr}
|
|
|
|
|
|
def unsubscribe_repo(project_name: str, projects_dir: Path):
|
|
"""Loeschen eines abonnierten Projekts inklusive Berechtigungen."""
|
|
target_dir = projects_dir / project_name
|
|
|
|
if not target_dir.exists():
|
|
return {"success": False, "error": "Projekt nicht gefunden"}
|
|
|
|
try:
|
|
# ✅ SCHRITT 1: Alles CHMOD 0o666 fuer LOESCHEN!
|
|
force_remove_all(str(target_dir))
|
|
|
|
# ✅ SCHRITT 2: Erst jetzt.loeschen
|
|
shutil.rmtree(str(target_dir))
|
|
|
|
return {"success": True, "message": f"{project_name} erfolgreich geloescht"}
|
|
|
|
except Exception as e:
|
|
# Fallback mit rm -rf
|
|
try:
|
|
subprocess.run(["rm", "-rf", str(target_dir)], check=True)
|
|
return {"success": True, "message": f"{project_name} geloescht (Force)"}
|
|
except Exception as e2:
|
|
return {"success": False, "error": f"Konnte nicht loeschen: {e}"}
|
|
|
|
|
|
def push_changes(repo_path: Path, message: str = "Update 🧠", changelog_content: str = None):
|
|
"""Pusht lokale Änderungen ins Repository mit optionalem Changelog-Content."""
|
|
# Optional: Changelog aktualisieren
|
|
if changelog_content:
|
|
changelog_path = repo_path / "CHANGELOG.md"
|
|
changelog_path.write_text(changelog_content)
|
|
|
|
result = subprocess.run(
|
|
["git", "add", "."], cwd=repo_path, capture_output=True, text=True
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
return {"success": False, "error": f"git add fehlgeschlagen: {result.stderr}"}
|
|
|
|
# Commit message mit optionaler Info aus Changelog
|
|
commit_msg = message
|
|
if changelog_content:
|
|
commit_msg += "\n\nChangelog aktualisiert"
|
|
|
|
result = subprocess.run(
|
|
["git", "commit", "-m", commit_msg], cwd=repo_path, capture_output=True, text=True
|
|
)
|
|
|
|
if result.returncode != 0 and "nothing to commit" not in result.stderr.lower():
|
|
return {"success": False, "error": f"Commit fehlgeschlagen: {result.stderr}"}
|
|
|
|
result = subprocess.run(
|
|
["git", "push"], cwd=repo_path, capture_output=True, text=True
|
|
)
|
|
|
|
return {"success": result.returncode == 0, "output": result.stdout} |