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

270
DataPuller.py Executable file → Normal file
View file

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

View file

@ -1,175 +0,0 @@
import os
import argparse
import shutil
import filecmp
# 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")
args = parser.parse_args()
# 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(full_path)
file_info[rel_path] = {
"size": stat.st_size,
"modified": stat.st_mtime,
}
except Exception:
pass
return file_info
def main():
startstring = " FOLDER-SYNC 1.0 "
if not args.quiet:
print(len(startstring)*"=" + "\n" + startstring + "\n" + len(startstring)*"=")
# 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)
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("Analyzing files. Please wait...\n")
source = get_files(inpath)
target = get_files(outpath)
new = []
changed = []
deleted = []
# 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)
# Check for file deletions
for path in target:
if path not in source:
deleted.append(path)
if not new and not changed and not deleted:
if not args.quiet:
print("No changes found.")
input("\nPress ENTER to exit...")
exit(0)
# 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}")
# 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)
# Create new folders if needed
os.makedirs(os.path.dirname(target_path), exist_ok=True)
# 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...")
# 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 not args.quiet:
print("\nFolder sync finished!")
input("\nPress ENTER to exit...")
if __name__ == "__main__":
main()