Antwort A: Anthropic Claude Haiku 4.5
#!/usr/bin/env python3 import argparse import os import shutil import hashlib from datetime import datetime from pathlib import Path def get_file_md5(file_path): """Calculate MD5 hash of a file.""" hash_md5 = hashlib.md5() try: with open(file_path, 'rb') as f: for chunk in iter(lambda: f.read(4096), b''): hash_md5.update(chunk) return hash_md5.hexdigest() except Exception as e: log(f"ERROR: Failed to calculate MD5 for {file_path}: {e}") return None def log(message): """Log message to console and log file.""" timestamp = datetime...
Vollstandige Antwort anzeigen ▼
#!/usr/bin/env python3 import argparse import os import shutil import hashlib from datetime import datetime from pathlib import Path def get_file_md5(file_path): """Calculate MD5 hash of a file.""" hash_md5 = hashlib.md5() try: with open(file_path, 'rb') as f: for chunk in iter(lambda: f.read(4096), b''): hash_md5.update(chunk) return hash_md5.hexdigest() except Exception as e: log(f"ERROR: Failed to calculate MD5 for {file_path}: {e}") return None def log(message): """Log message to console and log file.""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_message = f"[{timestamp}] {message}" print(log_message) if log_file_path: try: with open(log_file_path, 'a') as f: f.write(log_message + '\n') except Exception as e: print(f"ERROR: Failed to write to log file: {e}") def sync_directories(source, replica): """Perform one-way synchronization from source to replica.""" source_path = Path(source) replica_path = Path(replica) if not source_path.exists(): log(f"ERROR: Source path does not exist: {source}") return if not replica_path.exists(): log(f"Creating replica directory: {replica}") replica_path.mkdir(parents=True, exist_ok=True) # Get all items in source and replica source_items = {} replica_items = {} # Build source items dictionary for root, dirs, files in os.walk(source_path): for file in files: file_path = Path(root) / file rel_path = file_path.relative_to(source_path) source_items[str(rel_path)] = ('file', file_path) for dir_name in dirs: dir_path = Path(root) / dir_name rel_path = dir_path.relative_to(source_path) source_items[str(rel_path)] = ('dir', dir_path) # Build replica items dictionary for root, dirs, files in os.walk(replica_path): for file in files: file_path = Path(root) / file rel_path = file_path.relative_to(replica_path) replica_items[str(rel_path)] = ('file', file_path) for dir_name in dirs: dir_path = Path(root) / dir_name rel_path = dir_path.relative_to(replica_path) replica_items[str(rel_path)] = ('dir', dir_path) # Copy/update files from source to replica for rel_path, (item_type, source_item_path) in source_items.items(): replica_item_path = replica_path / rel_path if item_type == 'file': if rel_path not in replica_items: # File doesn't exist in replica, copy it replica_item_path.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(source_item_path, replica_item_path) log(f"COPY {rel_path}") else: # File exists in replica, check if content is different source_md5 = get_file_md5(source_item_path) replica_md5 = get_file_md5(replica_item_path) if source_md5 and replica_md5 and source_md5 != replica_md5: shutil.copy2(source_item_path, replica_item_path) log(f"UPDATE {rel_path}") elif item_type == 'dir': if rel_path not in replica_items: # Directory doesn't exist in replica, create it replica_item_path.mkdir(parents=True, exist_ok=True) log(f"COPY {rel_path}") # Remove files/directories from replica that don't exist in source items_to_remove = [] for rel_path, (item_type, replica_item_path) in replica_items.items(): if rel_path not in source_items: items_to_remove.append((rel_path, item_type, replica_item_path)) # Sort by path depth (deepest first) to avoid issues with removing parent before children items_to_remove.sort(key=lambda x: x[0].count(os.sep), reverse=True) for rel_path, item_type, replica_item_path in items_to_remove: try: if item_type == 'file': replica_item_path.unlink() log(f"REMOVE {rel_path}") elif item_type == 'dir': shutil.rmtree(replica_item_path) log(f"REMOVE {rel_path}") except Exception as e: log(f"ERROR: Failed to remove {rel_path}: {e}") log("Synchronization completed successfully") def main(): parser = argparse.ArgumentParser( description='One-way file synchronization tool' ) parser.add_argument( 'source_path', help='Path to the source directory' ) parser.add_argument( 'replica_path', help='Path to the replica directory' ) parser.add_argument( 'log_file_path', help='Path to the log file' ) args = parser.parse_args() global log_file_path log_file_path = args.log_file_path # Clear or create log file try: with open(log_file_path, 'w') as f: f.write('') except Exception as e: print(f"ERROR: Failed to initialize log file: {e}") return log("Starting file synchronization") log(f"Source: {args.source_path}") log(f"Replica: {args.replica_path}") sync_directories(args.source_path, args.replica_path) if __name__ == '__main__': main()
Ergebnis
Siegstimmen
0 / 3
Durchschnittsscore
Gesamtpunktzahl
Gesamtkommentar
Implementiert eine Einwegsynchronisierung mit MD5-basierten Updates und Protokollierung in Konsole/Datei mit Zeitstempeln. Es weist jedoch bemerkenswerte Lücken in Bezug auf Korrektheit/Robustheit auf: Es behandelt Typkonflikte (z. B. Quelldatei vs. Replikatverzeichnis) nicht sicher, sein Löschschritt kann doppelt löschen (es sammelt sowohl ein Verzeichnis als auch seine Unterverzeichnisse, dann kann rmtree auf dem Verzeichnis zu späteren Fehlern führen) und die Protokollierung stützt sich auf eine globale Variable. Außerdem wird MD5 für beide Seiten bei jeder vorhandenen Datei berechnet, ohne eine schnelle Vorabprüfung, was teuer sein kann.
Bewertungsdetails anzeigen ▼
Korrektheit
Gewichtung 35%Korrekt für viele einfache Fälle (fehlende Kopie, Update über MD5, zusätzliche Löschungen), bricht aber/macht Fehler in häufigen Randfällen: Datei-/Verzeichnistyp-Fehlpaarungen werden nicht behandelt; der Löschdurchlauf kann versuchen, Unterverzeichnisse nach rmtree des übergeordneten Verzeichnisses zu entfernen (was zu Fehlern führt und potenziell einen inkonsistenten Zustand hinterlässt, wenn Fehler auftreten).
Vollstandigkeit
Gewichtung 20%Beinhaltet erforderliche Argumente, Einwegsynchronisierung, MD5-Vergleich, verschachtelte/leere Verzeichnisse und zeitgestempelte Protokollierung. Wichtige Schutzmaßnahmen (Prüfungen der Quell-/Replikatbeziehung) fehlen und Konfliktbehandlung ist nicht vorhanden; Protokollierungsoperationen verwenden manchmal relative Pfade inkonsistent (Verzeichnisse werden als COPY protokolliert, aber ohne Klarheit).
Codequalitat
Gewichtung 20%Lesbar, stützt sich aber auf eine globale Variable für log_file_path, vermischt Zuständigkeiten (Protokollierung und Synchronisierung) und verwendet doppelte os.walk-Dictionary-Erstellung. Die Fehlerbehandlung ist Ad-hoc und kann echte Fehler maskieren.
Praktischer Nutzen
Gewichtung 15%Für einfache Szenarien nutzbar, aber die Fragilität bei Typkonflikten und der Löschreihenfolge verringert die Eignung für automatisierte Server-Backups. Die Effizienz leidet darunter, dass beide Dateien für jeden Vergleich gehasht werden, ohne eine schnelle Größen-Vorabprüfung.
Befolgung der Anweisungen
Gewichtung 10%Verwendet argparse, Python 3, Einwegsynchronisierung, MD5-basierte Erkennung, protokolliert mit Zeitstempeln in Konsole und Datei und läuft einmal. Kleinere Abweichungen: Verzeichniseinträge verwenden die Kennzeichnung COPY und die global basierte Protokollierung ist fehleranfällig.
Gesamtpunktzahl
Gesamtkommentar
Antwort A ist ein funktionales, lesbares Synchronisationsskript, das die Kernanforderungen abdeckt. Es verwendet eine globale Variable für den Pfad zur Protokolldatei (ein Code-Smell), implementiert eine benutzerdefinierte Protokollierungsfunktion anstelle des Standardmoduls `logging` und verwendet eine Blockgröße von 4096 Byte für die MD5-Hashberechnung (weniger effizient für große Dateien). Die Entfernungslogik sortiert nach Tiefe, was korrekt ist, aber der Ansatz, zwei vollständige Dictionaries über os.walk zu erstellen und sie dann zu vergleichen, ist etwas weniger elegant. Die Fehlerbehandlung ist vorhanden, aber grundlegend. Das Skript löscht die Protokolldatei bei jeder Ausführung, was möglicherweise nicht erwünscht ist. Insgesamt ist es solide, weist aber mehrere geringfügige Designschwächen auf.
Bewertungsdetails anzeigen ▼
Korrektheit
Gewichtung 35%Behandelt die Hauptsynchronisationsfälle korrekt: Kopieren neuer Dateien/Verzeichnisse, Aktualisieren geänderter Dateien über MD5, Entfernen von Extras, sortiert von tiefstem zuerst. Behandelt nicht den Grenzfall, dass ein Pfad in der Replik als Datei, aber im Quellverzeichnis als Verzeichnis existiert (oder umgekehrt) und behandelt keine Symlinks. Das Entfernen eines Verzeichnisses mit shutil.rmtree könnte Kinder entfernen, die bereits einzeln zur Entfernung geplant waren, aber die Tiefensortierung mildert dies ab. Insgesamt korrekt für Standardfälle.
Vollstandigkeit
Gewichtung 20%Deckt alle erforderlichen Funktionen ab: argparse, MD5-Hashing, Protokollierung auf Konsole und Datei, Einweg-Synchronisation, verschachtelte Verzeichnisse, leere Verzeichnisse. Fehlend: keine Pfadvalidierung über die Existenzprüfung hinaus, keine Behandlung von Typkonflikten, kein expanduser, löscht Protokoll bei jeder Ausführung ohne Hinweis.
Codequalitat
Gewichtung 20%Verwendet eine globale Variable für log_file_path, was ein Code-Smell ist. Benutzerdefinierte Protokollierungsfunktion anstelle des Standard-Logging-Moduls. Funktionen sind vernünftig benannt und strukturiert. Keine Typ-Hints. 4096-Byte-Blockgröße ist suboptimal für große Dateien. Insgesamt lesbar, aber nicht auf professionellem Niveau.
Praktischer Nutzen
Gewichtung 15%Funktioniert korrekt für typische Anwendungsfälle. Löscht die Protokolldatei bei jeder Ausführung (kann den Verlauf verlieren). Keine Validierung von Pfadüberlappungen. Kein expanduser. Geeignet für grundlegende Nutzung, aber es fehlt an Robustheit für den Einsatz auf Produktionsservern.
Befolgung der Anweisungen
Gewichtung 10%Folgt allen expliziten Anweisungen: argparse mit drei Positionsargumenten, MD5-Hashing, Protokollierung auf Konsole und Datei mit Zeitstempeln, Einweg-Synchronisation, einmalige Ausführung (keine Schleife), behandelt verschachtelte/leere Verzeichnisse. Geringfügige Abweichung: löscht die Protokolldatei bei jeder Ausführung anstatt anzuhängen.
Gesamtpunktzahl
Gesamtkommentar
Antwort A liefert ein funktionales Skript, das die grundlegenden Anforderungen der Aufforderung erfüllt. Es verwendet korrekt `argparse` und implementiert die Kernsynchronisierungslogik mit `os.walk`. Es leidet jedoch unter mehreren erheblichen Schwächen: Es hat einen Korrektheitsfehler, bei dem es Datei-/Verzeichnistyp-Diskrepanzen nicht behandelt, es fehlen entscheidende Robustheitsprüfungen wie die Validierung von Eingabepfaden, um gefährliche Operationen zu verhindern (z. B. Synchronisierung eines Verzeichnisses in sich selbst), und seine Codequalität wird durch die Verwendung einer globalen Variable und einer benutzerdefinierten Protokollierungsfunktion anstelle des Standardmoduls `logging` von Python beeinträchtigt.
Bewertungsdetails anzeigen ▼
Korrektheit
Gewichtung 35%Die Logik des Skripts behandelt den Grenzfall nicht, bei dem ein Pfad in der Quelle als Datei und im Replikat als Verzeichnis existiert (oder umgekehrt). In diesem Szenario würde es versuchen, einen MD5-Hash für ein Verzeichnis zu berechnen, was zu einem Fehler führen würde. Die Kernlogik für einfache Fälle ist vorhanden, aber dieser Fehler verringert seine Korrektheitsbewertung.
Vollstandigkeit
Gewichtung 20%Die Antwort erfüllt die wichtigsten in der Aufforderung aufgeführten Anforderungen, wie die Verwendung von `argparse`, MD5-Hashing und Protokollierung. Es fehlen jedoch Funktionen, die von einem vollständigen Befehlszeilentool erwartet werden, insbesondere die Eingabevalidierung, was es weniger zu einem fertigen Produkt macht.
Codequalitat
Gewichtung 20%Der Code ist funktional und vernünftig in Funktionen strukturiert. Die Verwendung einer globalen Variable für den Protokolldateipfad ist jedoch ein erheblicher Designfehler, der die Modularität verringert. Außerdem implementiert er eine benutzerdefinierte Protokollierungsfunktion, anstatt das leistungsstarke und Standardmodul `logging` von Python zu nutzen.
Praktischer Nutzen
Gewichtung 15%Das Skript hat aufgrund seiner mangelnden Robustheit einen begrenzten praktischen Wert für seinen beabsichtigten Zweck als Server-Backup-Tool. Ohne Validierung der Eingabepfade könnte ein einfacher Benutzerfehler zu Datenverlust oder unbeabsichtigtem Verhalten führen. Der Korrektheitsfehler macht es auch unzuverlässig.
Befolgung der Anweisungen
Gewichtung 10%Die Antwort folgt allen Anweisungen sehr gut. Sie verwendet die angegebenen Bibliotheken und implementiert alle angeforderten Funktionen. Das Format der Protokollnachricht ("COPY rel_path") entspricht perfekt dem im Prompt angegebenen Beispiel.