Removed old DataPuller

This commit is contained in:
R Dittberner 2026-03-04 10:16:02 +01:00
parent 12bbe7c9d8
commit d313833642
2 changed files with 145 additions and 302 deletions

272
DataPuller.py Executable file → Normal file
View file

@ -1,157 +1,175 @@
import os
import argparse
import shutil
import filecmp
# --- Hier die Pfade definieren ---
QUELL_ORDNER = input("Quellordner: ")
ZIEL_ORDNER = input("Zielordner: ")
# ---------------------------------
# Argument Parsing
parser = argparse.ArgumentParser(
prog='DataPuller',
description='Check differences between folders and update files if needed')
parser.add_argument('-i', '--input')
parser.add_argument('-o', '--output')
parser.add_argument('-q', '--quiet', action='store_true')
parser.add_argument('-y', '--confirm', action="store_true")
parser.add_argument('-d', '--delete', action="store_true")
parser.add_argument("--dryrun", action="store_true")
def hole_datei_infos(verzeichnis):
"""Sammelt alle Dateien mit ihrer Größe und dem Änderungsdatum."""
datei_infos = {}
if not os.path.exists(verzeichnis):
return datei_infos
args = parser.parse_args()
for ordner_pfad, _, dateien in os.walk(verzeichnis):
for datei in dateien:
voller_pfad = os.path.join(ordner_pfad, datei)
# Relativen Pfad ermitteln (z. B. "unterordner\dokument.docx")
relativer_pfad = os.path.relpath(voller_pfad, verzeichnis)
# Paths
if not args.input:
inpath = input("Source Path: ")
else:
inpath = args.input
if not args.output:
outpath = input("Target Path: ")
else:
outpath = args.output
def get_files(path):
file_info = {}
if not os.path.exists(path):
return file_info
for folder, _, files in os.walk(path):
for file in files:
full_path = os.path.join(folder, file)
rel_path = os.path.relpath(full_path, path)
try:
stat = os.stat(voller_pfad)
datei_infos[relativer_pfad] = {
"groesse": stat.st_size,
"aenderungsdatum": stat.st_mtime,
stat = os.stat(full_path)
file_info[rel_path] = {
"size": stat.st_size,
"modified": stat.st_mtime,
}
except Exception:
pass
return datei_infos
return file_info
def main():
print("=" * 50)
print(" USB-STICK SYNCHRONISATION")
print("=" * 50)
startstring = " FOLDER-SYNC 1.0 "
if not args.quiet:
print(len(startstring)*"=" + "\n" + startstring + "\n" + len(startstring)*"=")
# Prüfen, ob Laufwerke da sind
if not os.path.exists(QUELL_ORDNER):
print(f"Fehler: Das Schul-Laufwerk ({QUELL_ORDNER}) ist nicht erreichbar!")
input("\nDrücke Enter zum Beenden...")
return
# Test Folder availability
if not os.path.exists((inpath)):
print(f"ERROR: The input folder ({inpath}) is unavailable or non-existant.")
if not args.quiet:
input("\nPress ENTER to exit...")
exit(1)
ziel_laufwerk = os.path.splitdrive(ZIEL_ORDNER)[0] + "\\"
if not os.path.exists(ziel_laufwerk):
print(
f"Fehler: Laufwerk {ziel_laufwerk} nicht gefunden. Ist der USB-Stick eingesteckt?"
)
input("\nDrücke Enter zum Beenden...")
return
if not os.path.exists(outpath):
print(f"ERROR: The output folder ({outpath}] is unavailable or non-existant.")
if not args.quiet:
input("\nPress ENTER to exit...")
exit(1)
print("Analysiere Dateien. Bitte warten...\n")
print("Analyzing files. Please wait...\n")
quelle = hole_datei_infos(QUELL_ORDNER)
ziel = hole_datei_infos(ZIEL_ORDNER)
source = get_files(inpath)
target = get_files(outpath)
neu = []
geaendert = []
geloescht = []
new = []
changed = []
deleted = []
# Prüfen, was auf P: neu oder geändert wurde
for pfad, info in quelle.items():
if pfad not in ziel:
neu.append(pfad)
else:
# Wir prüfen die Dateigröße und das Datum (2 Sekunden Toleranz für USB-Sticks)
if (
info["groesse"] != ziel[pfad]["groesse"]
or abs(info["aenderungsdatum"] - ziel[pfad]["aenderungsdatum"]) > 2
):
geaendert.append(pfad)
# Check for file additions and changes
for path, info in source.items():
if path not in target:
new.append(path)
elif not filecmp.cmp(os.path.join(inpath, path), os.path.join(outpath, path)):
changed.append(path)
# Prüfen, was von P: gelöscht wurde und auf dem Stick auch weg kann
for pfad in ziel:
if pfad not in quelle:
geloescht.append(pfad)
# Check for file deletions
for path in target:
if path not in source:
deleted.append(path)
# Wenn alles aktuell ist
if not neu and not geaendert and not geloescht:
print(
"Alles ist bereits auf dem neuesten Stand! Keine Änderungen erforderlich."
)
input("\nDrücke Enter zum Beenden...")
return
if not new and not changed and not deleted:
if not args.quiet:
print("No changes found.")
input("\nPress ENTER to exit...")
exit(0)
# Übersicht ausgeben
print("Folgende Änderungen wurden gefunden:\n")
if neu:
print("NEUE DATEIEN (werden auf den Stick kopiert):")
for d in neu:
print(f" + {d}")
print()
if geaendert:
print("GEÄNDERTE DATEIEN (Inhalt hat sich geändert, werden aktualisiert):")
for d in geaendert:
print(f" ~ {d}")
print()
if geloescht:
print("GELÖSCHTE DATEIEN (sind nicht mehr auf dem Schul-Laufwerk):")
for d in geloescht:
print(f" - {d}")
print()
# Print overview
if not args.quiet:
print("Found the following changes:\n")
if new:
print("Added:")
for i in new:
print(f" + {i}")
print()
if changed:
print("Changed:")
for i in changed:
print(f" ~ {i}")
if deleted:
print("Deleted:")
for i in deleted:
print(f" - {i}")
# --- SCHRITT 1: KOPIEREN & AKTUALISIEREN ---
if neu or geaendert:
antwort_kopieren = (
input("Sollen die NEUEN und GEÄNDERTEN Dateien kopiert werden? (ja/nein): ")
.strip()
.lower()
)
if antwort_kopieren in ["ja", "j", "yes", "y"]:
print("\nKopiere Dateien...")
for pfad in neu + geaendert:
quell_pfad = os.path.join(QUELL_ORDNER, pfad)
ziel_pfad = os.path.join(ZIEL_ORDNER, pfad)
# Copy and update files
if not args.dryrun:
if new or changed:
if args.confirm:
copy_confirm = "y"
else:
copy_confirm = input("Write new and changed files? (y/N): ").strip().lower()
if copy_confirm in ["ja", "j", "yes", "y"]:
if not args.quiet:
print("\nCopying files...")
for path in new + changed:
source_path = os.path.join(inpath, path)
target_path = os.path.join(outpath, path)
# Ordnerstruktur auf dem Stick erstellen, falls ein neuer Unterordner da ist
os.makedirs(os.path.dirname(ziel_pfad), exist_ok=True)
# Create new folders if needed
os.makedirs(os.path.dirname(target_path), exist_ok=True)
# Datei kopieren
shutil.copy2(quell_pfad, ziel_pfad)
print(f"Erfolgreich kopiert: {pfad}")
else:
print("\nKopieren übersprungen.")
# Copy file
try:
shutil.copy(source_path, target_path)
if not args.quiet:
print(f"Successfully copied {path}")
except Exception as error:
print(f"Failed to copy {path} with error {error}")
if not args.confirm:
if not input("Continue? (y/N): ") in ["ja", "j", "yes", "y"]:
exit(1)
elif not args.quiet:
print("\nSkipping changes...")
# --- SCHRITT 2: LÖSCHEN ---
if geloescht:
print("\n" + "!" * 55)
print(" ACHTUNG: Einige Dateien existieren nur auf dem Stick.")
print("!" * 55)
antwort_loeschen = (
input(
"Sollen die GELÖSCHTEN Dateien nun auch vom Stick ENTFERNT werden? (ja/nein): "
)
.strip()
.lower()
)
# Delete files
if not args.dryrun:
if deleted:
alert = " ALERT: Some files only exist at the destination. "
if not args.quiet:
print(f"{len(alert) * '*'}\n{alert}\n{len(alert) * '*'}")
if args.delete:
delete_confirm = "y"
else:
delete_confirm = input("Delete files on the target? (y/N): ").strip().lower()
if delete_confirm in ["ja", "j", "yes", "y"]:
if not args.quiet:
print("\nDeleting files...")
for path in deleted:
target_path = os.path.join(outpath, path)
try:
os.remove(target_path)
if not args.quiet:
print(f"Successfully deleted {path}")
except Exception as error:
print(f"Failed to delete {path} with error {error}")
if not args.confirm:
if not input("Continue? (y/N): ") in ["ja", "j", "yes", "y"]:
exit(1)
elif not args.quiet:
print("\nSkipping deletion...")
if antwort_loeschen in ["ja", "j", "yes", "y"]:
print("\nLösche Dateien...")
for pfad in geloescht:
ziel_pfad = os.path.join(ZIEL_ORDNER, pfad)
try:
os.remove(ziel_pfad)
print(f"Erfolgreich gelöscht: {pfad}")
except Exception as e:
print(f"Fehler beim Löschen von {pfad}: {e}")
else:
print(
"\nLöschen übersprungen. Die Dateien bleiben als Backup auf dem Stick erhalten."
)
if not args.quiet:
print("\nFolder sync finished!")
input("\nPress ENTER to exit...")
print("\nSynchronisation abgeschlossen!")
input("\nDrücke Enter zum Beenden...")
if __name__ == "__main__":
main()
main()