Oakmini Engineering Notes

Pfadfehler auf einem APFS-Volume mit Groß-/Kleinschreibung prüfen

DevOps & CI/CD ·ca. 5 Min. Lesezeit

Pfadfehler auf einem APFS-Volume mit Groß-/Kleinschreibung prüfen

Dasselbe Repository funktioniert auf dem Entwicklungsrechner, schlägt im entfernten Build-Job jedoch mit Module not found fehl – oder nach dem Packaging fehlt plötzlich eine Ressource. Leeren Sie nicht vorschnell immer wieder den Cache. Das unter macOS übliche Standarddateisystem unterscheidet bei Dateinamen häufig nicht zwischen Groß- und Kleinschreibung, sodass Config.json und config.json als derselbe Pfad gelten können. Sobald Skripte, Abhängigkeiten oder das Deployment-Ziel Pfade strikt nach Groß-/Kleinschreibung auflösen, treten die bislang verborgenen Fehler zutage. Die zuverlässigste Diagnose besteht nicht darin, das Systemvolume zu verändern, sondern auf einem Cloud Mac ein isoliertes APFS-Volume mit Groß-/Kleinschreibung einzubinden.

Prüfen, ob der Fehler mit der Groß-/Kleinschreibung von Pfaden zusammenhängt

Suchen Sie im Fehlerprotokoll zuerst nach den betroffenen Pfaden, statt nur den Exit-Code in der letzten Zeile zu betrachten. Folgende Symptome sollten vorrangig untersucht werden:

Symptom Mögliche Ursache Prüfung
Lokal funktioniert der Import, im Build-Job wird das Modul nicht gefunden Importpfad und tatsächlicher Dateiname stimmen nicht überein Vollständigen Pfad mit git ls-files abgleichen
Nach dem Commit bleibt von zwei Ressourcen nur eine übrig Die Namen unterscheiden sich nur durch Groß-/Kleinschreibung Auf einem Volume mit Groß-/Kleinschreibung neu klonen
Der erste Build nach einer Bereinigung schlägt fehl Alte Artefakte haben eine fehlerhafte Referenz verdeckt Ausgabeverzeichnis löschen und vollständigen Build ausführen
Dateien werden beim Packaging überschrieben Ein Skript vereinheitlicht die Schreibweise der Namen Kopier- und Umbenennungsschritte prüfen

Führen Sie außerdem diskutil info / aus und notieren Sie für das aktuelle Systemvolume den Wert von File System Personality. Dieser Schritt dient ausschließlich dazu, die Umgebung zu prüfen. Konvertieren Sie nicht das aktive Systemvolume.

Pfadprobleme müssen in einem sauberen Arbeitsverzeichnis reproduziert werden. Wenn alte Caches auf das Testvolume kopiert werden, können sie den ursprünglichen Fehler erneut verdecken.

Isoliertes APFS-Testvolume erstellen

Ein Sparse Image wächst nur entsprechend der tatsächlich geschriebenen Daten und eignet sich daher gut für temporäre Prüfungen. Mit den folgenden Befehlen erstellen Sie ein Testvolume mit einer Obergrenze von 80 GB. Enthält das Projekt umfangreiche Abhängigkeiten, sollte der Speicherbedarf anhand der Spitzenbelegung von Repository, Abhängigkeiten und Artefakten bemessen werden.

mkdir -p "$HOME/apfs-lab"
hdiutil create \
  -size 80g \
  -type SPARSEBUNDLE \
  -fs "Case-sensitive APFS" \
  -volname BuildCase \
  "$HOME/apfs-lab/BuildCase.sparsebundle"

hdiutil attach "$HOME/apfs-lab/BuildCase.sparsebundle"
diskutil info "/Volumes/BuildCase"

Prüfen Sie, ob die Ausgabe das Volume ausdrücklich als case-sensitive ausweist und ob der Mountpoint /Volumes/BuildCase lautet. Speichern Sie auf diesem temporären Volume keine Zugangsschlüssel, Signaturdaten oder dauerhaft benötigten Dateien.

Repository auf dem neuen Volume erneut abrufen

Kopieren Sie das alte Arbeitsverzeichnis nicht per Drag-and-drop, da kollidierende Dateien dort möglicherweise bereits verloren gegangen sind. Klonen Sie stattdessen erneut aus dem kontrollierten Repository und legen Sie ein separates Build-Verzeichnis an:

mkdir -p /Volumes/BuildCase/work
cd /Volumes/BuildCase/work
git clone "$REPOSITORY_URL" project
cd project
git status --short

git status sollte jetzt keine Ausgabe liefern. Meldet bereits der Klonvorgang, dass ein Zielpfad vorhanden ist, enthält der Repository-Baum in der Regel Pfade, deren Namen nach einer Vereinheitlichung der Groß-/Kleinschreibung kollidieren.

Git-Dateinamen und Skriptreferenzen prüfen

Das folgende Skript liest ausschließlich von Git verfolgte Pfade, normalisiert sie in eine kanonische Unicode-Form und gruppiert sie anschließend ohne Berücksichtigung der Groß-/Kleinschreibung. Es verändert keine Dateien:

from collections import defaultdict
import subprocess
import unicodedata

raw = subprocess.check_output(
    ["git", "ls-files", "-z"],
    text=True
)
groups = defaultdict(list)

for path in raw.split(""):
    if not path:
        continue
    key = unicodedata.normalize("NFC", path).casefold()
    groups[key].append(path)

found = False
for paths in groups.values():
    if len(paths) > 1:
        found = True
        print("COLLISION")
        for path in paths:
            print(f"  {path}")

raise SystemExit(1 if found else 0)

Speichern Sie das Skript als tools/check_path_case.py und führen Sie python3 tools/check_path_case.py aus. Bei Exit-Code 1 sollten Sie die Benennung vereinheitlichen und die Änderung mit git mv committen. Wenn nur die Groß-/Kleinschreibung geändert wird, benennen Sie die Datei zunächst in einen Zwischennamen und anschließend in den gewünschten Zielnamen um. So wird verhindert, dass das ursprüngliche Arbeitsverzeichnis die Änderung ignoriert:

git mv Sources/config.json Sources/config.tmp
git mv Sources/config.tmp Sources/Config.json

Kollisionsfreie Dateinamen bedeuten noch nicht, dass alle Referenzen korrekt sind. Suchen Sie anschließend in Build-Skripten, Ressourcenlisten, Projektkonfigurationen und Test-Fixtures nach veralteten Pfaden. Achten Sie besonders auf Abweichungen zwischen automatisch generierten Dateien und manuell gepflegten Konfigurationen.

Prüfung in einen reproduzierbaren Build integrieren

Der Test-Job sollte zunächst den Mountpoint prüfen, danach die Pfadanalyse ausführen und schließlich aus einem leeren Verzeichnis bauen. So landen keine Dateien versehentlich wieder auf dem Systemvolume, falls das Testvolume nicht eingebunden ist.

set -euo pipefail

test -d /Volumes/BuildCase
cd /Volumes/BuildCase/work/project
python3 tools/check_path_case.py

rm -rf .build-output
mkdir .build-output
./scripts/build.sh "$PWD/.build-output"

Falls das Projekt noch keinen einheitlichen Build-Einstiegspunkt besitzt, fassen Sie die vorhandenen Befehle zunächst in scripts/build.sh zusammen und übergeben Sie das Ausgabeverzeichnis explizit. Abhängigkeits-Caches können separat eingebunden werden, sollten bei der ersten Prüfung jedoch deaktiviert bleiben. Aktivieren Sie sie nach einem erfolgreichen Durchlauf einzeln wieder, um festzustellen, welche Ebene einen fehlerhaften Pfad einführt.

Häufige Fallstricke und abschließende Prüfungen

Prüfen Sie vor Abschluss der Diagnose jeden der folgenden Punkte:

  • Das Repository wurde auf dem Testvolume neu geklont und nicht aus einem alten Verzeichnis kopiert.
  • Korrekturen an Dateinamen wurden mit git mv vorgenommen und erscheinen im Commit eindeutig als Umbenennungen.
  • Skripte wandeln Pfade nicht erzwungen vollständig in Klein- oder Großbuchstaben um.
  • Befehle zum Kopieren von Ressourcen schlagen bei einem bereits vorhandenen Zielnamen fehl, statt Dateien stillschweigend zu überschreiben.
  • Build-Artefakte, Abhängigkeitsverzeichnisse und Protokolle befinden sich am vorgesehenen Mountpoint.
  • Ein sauberer und ein inkrementeller Build wurden jeweils einmal ausgeführt und liefern dasselbe Ergebnis.

Exportieren Sie nach Abschluss der Prüfung zunächst alle benötigten Protokolle und hängen Sie dann das Testvolume aus:

hdiutil detach "/Volumes/BuildCase"

Löschen Sie BuildCase.sparsebundle erst, wenn feststeht, dass die enthaltenen Daten nicht mehr benötigt werden. Soll die Prüfung dauerhaft als Quality Gate dienen, bewahren Sie das Erstellungsskript statt der Testdaten auf. Kontrollieren Sie zu Beginn jedes Jobs das Volume-Format, den verfügbaren Speicherplatz und den Mountpfad.

Häufig gestellte Fragen

Muss das Systemvolume des Cloud Mac auf Groß-/Kleinschreibung umgestellt werden?

Nein. Verwenden Sie ein separates APFS-Sparse-Image für Repository und Build-Verzeichnis. Nach dem Test wird es ausgehängt, das Systemvolume bleibt unverändert.

Warum meldet Git Konflikte bei der Schreibweise nicht immer sofort?

Git speichert die Schreibweise, doch ein nicht unterscheidendes Arbeitsverzeichnis kann zwei Namen derselben Datei zuordnen. Klonen Sie daher auf dem Testvolume neu.

Dedizierter physischer Mac-mini-Knoten erforderlich

Verfügbare Konfigurationen, Knoten und feste Abrechnungszeiträume anzeigen und die Schritte des Artikels in einer dauerhaft nutzbaren Cloud-Mac-Umgebung umsetzen.

Mac mini jetzt mieten