Notes d’ingénierie Oakmini

Tester les chemins sur un volume APFS sensible à la casse

DevOps et CI/CD ·~6 min de lecture

Tester les chemins sur un volume APFS sensible à la casse

Un même dépôt peut fonctionner parfaitement sur la machine de développement, puis échouer avec Module not found dans une tâche de build distante, ou produire un paquet auquel il manque une ressource. Avant de vider les caches à répétition, examinez la gestion de la casse. Le système de fichiers utilisé par défaut sur macOS ne distingue généralement pas les majuscules des minuscules dans les noms de fichiers : Config.json et config.json peuvent donc désigner le même chemin. Le problème jusque-là invisible n’apparaît que lorsqu’un script, une dépendance ou la cible de déploiement effectue une résolution stricte des chemins. La méthode de diagnostic la plus fiable ne consiste pas à modifier le volume système, mais à monter sur un Mac cloud un volume APFS isolé et sensible à la casse.

Vérifier si l’échec est lié à la casse des chemins

Commencez par rechercher les chemins concernés dans les journaux d’échec, au lieu de vous limiter au code de sortie de la dernière ligne. Les symptômes suivants méritent une attention prioritaire :

Symptôme Cause possible Vérification
L’import fonctionne en local, mais le module est introuvable pendant le build Le chemin d’import ne correspond pas au nom réel du fichier Comparer le chemin complet avec git ls-files
Après le commit de deux ressources, il n’en reste qu’une Leurs noms ne diffèrent que par la casse Refaire le clone sur un volume sensible à la casse
Le premier build après nettoyage échoue D’anciens artefacts masquaient une référence incorrecte Supprimer le répertoire de sortie et lancer un build complet
Des fichiers sont écrasés pendant la création du paquet Un script uniformise la casse des noms Contrôler les étapes de copie et de renommage

Exécutez également diskutil info / et relevez la valeur de File System Personality pour le volume système actuel. Cette étape sert uniquement à identifier l’environnement. Ne tentez pas de convertir directement le volume système en cours d’utilisation.

Un problème de chemin doit être reproduit dans un espace de travail propre. Copier d’anciens caches sur le volume de test risquerait de masquer à nouveau l’erreur initiale.

Créer un volume de test APFS isolé

Une image disque dynamique n’occupe que l’espace réellement utilisé, ce qui la rend adaptée aux vérifications temporaires. Les commandes ci-dessous créent un volume de test plafonné à 80 Go. Si le projet comporte des dépendances volumineuses, prévoyez une capacité adaptée au pic d’utilisation cumulé du dépôt, des dépendances et des artefacts.

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"

Vérifiez que la sortie indique explicitement que le volume est sensible à la casse et que son point de montage est /Volumes/BuildCase. Ne stockez aucune clé d’accès, donnée de signature ou donnée à conserver durablement sur ce volume temporaire.

Récupérer à nouveau le dépôt sur le nouveau volume

Ne copiez pas directement l’ancien espace de travail par glisser-déposer : certains fichiers en conflit ont peut-être déjà disparu. Reclonez le dépôt depuis sa source contrôlée et créez un répertoire de build indépendant :

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

À ce stade, git status ne doit rien afficher. Si le clonage signale déjà qu’un chemin cible existe, l’arborescence du dépôt contient généralement des chemins dont les noms entrent en collision une fois la casse neutralisée.

Auditer les noms de fichiers Git et les références des scripts

Le script suivant se contente de lire les chemins suivis par Git. Il les convertit dans une forme Unicode normalisée, puis les regroupe sans tenir compte de la casse. Il ne modifie aucun fichier :

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)

Enregistrez-le sous tools/check_path_case.py, puis exécutez python3 tools/check_path_case.py. Si le code de sortie vaut 1, harmonisez les noms et validez les changements avec git mv. Lorsque seule la casse doit changer, passez d’abord par un nom intermédiaire avant d’appliquer le nom définitif. Vous éviterez ainsi que l’espace de travail d’origine ignore la modification :

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

L’absence de collision entre les noms de fichiers ne garantit pas que leurs références soient correctes. Recherchez ensuite les anciens chemins dans les scripts de build, manifestes de ressources, configurations de projet et fixtures de test. Soyez particulièrement attentif aux divergences entre les fichiers générés automatiquement et les configurations rédigées manuellement.

Intégrer le contrôle à un build reproductible

La tâche de test doit d’abord vérifier le point de montage, exécuter ensuite l’audit des chemins, puis lancer le build depuis un répertoire vide. Ainsi, si le volume de test n’est pas monté, aucun fichier ne sera écrit par erreur sur le volume système.

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"

Si le projet ne dispose pas d’un point d’entrée unique pour le build, regroupez d’abord les commandes existantes dans scripts/build.sh et transmettez explicitement le répertoire de sortie. Les caches de dépendances peuvent être montés séparément, mais l’ancienne version du cache doit rester désactivée lors de la première vérification. Réactivez ensuite chaque couche l’une après l’autre afin d’identifier celle qui réintroduit un chemin incorrect.

Pièges fréquents et vérifications finales

Avant de terminer le diagnostic, vérifiez chaque point de la liste suivante :

  • Le dépôt a été recloné sur le volume de test, et non copié depuis un ancien répertoire.
  • Les corrections de noms de fichiers ont été effectuées avec git mv et apparaissent clairement comme des renommages dans le commit.
  • Aucun script ne force les chemins entièrement en minuscules ou en majuscules.
  • Les commandes de copie des ressources échouent si un nom cible existe déjà, au lieu d’écraser silencieusement le fichier.
  • Les artefacts de build, répertoires de dépendances et journaux se trouvent tous sur le point de montage prévu.
  • Un build propre et un build incrémental ont chacun été exécutés une fois et produisent le même résultat.

Une fois la vérification terminée, exportez d’abord les journaux nécessaires, puis démontez le volume de test :

hdiutil detach "/Volumes/BuildCase"

Ne supprimez BuildCase.sparsebundle qu’après avoir confirmé qu’aucune donnée ne doit être conservée. Si ce contrôle doit devenir une barrière qualité permanente, conservez le script de création plutôt que les données de test. Au début de chaque tâche, vérifiez le format du volume, l’espace disponible et le chemin de montage.

Questions fréquentes

Faut-il convertir le volume système du Mac cloud en APFS sensible à la casse ?

Non. Montez un sparse image APFS séparé et placez-y uniquement le dépôt et les répertoires de build. Le volume système reste inchangé.

Pourquoi Git ne signale-t-il pas toujours une collision de casse ?

Git conserve l’orthographe des chemins, mais un répertoire de travail insensible à la casse peut associer deux noms au même fichier. Il faut recloner sur le volume de test.

Besoin d’un nœud physique Mac mini dédié

Consultez les configurations disponibles, les nœuds et les cycles de facturation fixes pour appliquer les étapes de l’article à un environnement Mac dans le cloud utilisable durablement.

Louer un Mac mini maintenant