Grails und seine Arbeitsverzeichnisse

Wenn man wie ich aus der Maven-Welt kommt, dann weiß man: Kompilate, generierte Resourcen und temporäre Dateien werden immer im target-Ordner des Projektverzeichnisses abgelegt; eingebundene Plugins und Dependencies liegen dagegen in einem Repository im Nutzerverzeichnis.

Bei Grails ist das ein wenig anders. Dies musste ich feststellen, als ich auf unserem CI-Server Teamcity zwei Builds eines Grails-Projektes parallel angestoßen habe und diese beim Bauen des WARs scheiterten, weil sie das Staging-Verzeichnis nicht löschen konnten. Bei der Überprüfung des Fehlers wurde mir erst bewusst, dass Grails für jedes Projekt ein Arbeitsverzeichnis im Home-Verzeichnis des angemeldeten Nutzers anlegt. Dieses enthält nicht nur die Plugins, die als externe Artefakte nicht in das Projektverzeichnis gehören, sondern auch das Staging-Directory, aus welchem schließlich das WAR erzeugt wird. Solange nur ein Build gleichzeitig auf dem System läuft, ist dies kein Problem, aber bei den zwei parallelen Builds auf Teamcity löschten sich die Builds ihre Artefakte gegenseitig weg, da alle Agents mit dem selben Nutzer angemeldet sind und sich so ein Home-Verzeichnis teilen.

Wie fast alles in Grails kann dieses Verhalten aber an die eigenen Wünsche angepasst werden, und mein Wunsch war nun, dass die Plugins weiterhin im Nutzerverzeichnis bleiben, alle Projektartefakte aber im Projektverzeichnis gebaut werden – eben wie von Maven gewohnt. Letzteres war schnell erreicht. Im Abschnitt Customising the build fand ich den Hinweis auf die Konfigurationsoption projectWorkDir, welche ich einfach auf das bestehende target-Verzeichnis gesetzt habe. Nun wurden aber auch die Plugins dorthin gepackt, da deren Konfigurationsoption projectPluginsDir auf dem projectWorkDir basiert. Also musste ich für diese die Standardbelegung wieder herstellen, was ich mit ein wenig Try & Error schließlich erreicht habe.

Eingetragen in die BuildConfig.groovy sehen die Anpassungen nun wie folgt aus:

grails.project.work.dir = "target"  
grails.project.plugins.dir = "${grailsSettings.grailsWorkDir}/projects/${grailsSettings.baseDir.name}/plugins";  

Ein anderer Weg wäre natürlich gewesen, Grails gleich zu Mavenizen. Dies hätte den positiven Nebeneffekt, Plugins wie das Release-Plugin nutzen zu können, für die es (noch) keine Alternative auf Grails-Seite gibt. Doch da das aktuelle Problem relativ schnell durch etwas Konfiguration zu lösen war, ist diese Idee auf später verschoben worden.