Das Projekt ist eine Nix Flake.
In flake.nix sind die Inputs und Outputs zur Flake deklariert.
Wenn neue Versionen der aufgelisteten Inputs verwendet werden sollen, muss mit nix flake update das flake.lock regeneriert werden.
Es kann nützlich sein dabei nur einzelne inputs zu updaten (siehe man); man will nicht unbedingt immer die Version von nixpkgs updaten, das verursacht wesentliche rebuilds.
In flake.nix findet sich zudem eine Spezifikation welche Dateien für das Kompilieren des front- und backend relevant sind; wenn ein nix build den Eindruck macht, dass etwas fehlt, muss man diese evtl. anpassen.
Die flake produziert folgende Outputs (kommentiert):
gkleen@uni2work-dev1 ~fradrive ❯ nix flake show
git+file:///home/gkleen/projects/fradrive?ref=master&rev=8c981aa407c2d5db55918487ac3dbb5009a95bb6
├───apps
│ └───x86_64-linux
│ ├───calculateMaterializedSha: app # Skript, dass einen hash des aus dem `stack.yaml` und dependencies berechneten build-plan ausgibt; damit kann theoretisch die Latenz, die beim Ausführen jedes `nix`-Befehls am Anfang auftritt reduziert werden; Gregor hat das nicht hinbekommen
│ ├───jqChangelogJson: app # Skript, verhält sich wie `exec -- jq $@ changelog.json`; `changelog.json` hierbei das Ergebnis davon `CHANGELOG.md` in eine JSON-Struktur zu parsen
│ ├───pushCIDocker: app # Skript, kopiert aktuelle Version des `nix-unstable` Docker-image inzu gitlab.com; nimmt alternativ das Ziel, in das kopiert werden soll, als einziges Argument; siehe `skopeo`
│ ├───pushUniworxDemoDocker: app # Skript, kopiert aktuelle Version des `uniworx-demo` Docker-image inzu gitlab.com
│ ├───pushUniworxDocker: app # Skript, kopiert aktuelle Version des `uniworx` Docker-image inzu gitlab.com
│ ├───"uniworx:exe:uniworx": app # Kompilierte Binary `uniworx`
│ ├───"uniworx:exe:uniworx-wflint": app # Kompilierte Binary `uniworx-wflint`
│ ├───"uniworx:exe:uniworxdb": app # Kompilierte Binary `uniworxdb`
│ ├───"uniworx:exe:uniworxload": app # Kompilierte Binary `uniworxload`
│ ├───"uniworx:test:hlint": app # Führt Testsuite `hlint` (also hlint auf den gesamten source tree) aus
│ └───"uniworx:test:yesod": app # Führt Testsuite `yesod` (also haskell property- und unittests) aus
├───checks
│ └───x86_64-linux
│ ├───"uniworx:test:hlint": derivation 'uniworx-test-hlint-25.21.12-check' # Testsuite `hlint` für `nix flake check`
│ ├───"uniworx:test:yesod": derivation 'uniworx-test-yesod-25.21.12-check' # Testsuite `yesod`
│ └───uniworxFrontend: derivation 'uniworx-frontend-check' # Frontend testsuite
├───defaultApp
│ └───x86_64-linux: app # `uniworx`
├───defaultPackage
│ └───x86_64-linux: package 'uniworx-exe-uniworx-25.21.12'
├───devShell
│ └───x86_64-linux: development environment 'uni2work' # Shell für `nix develop` bzw. `direnv`
├───legacyPackages
│ └───x86_64-linux: omitted (use '--legacy' to show)
└───packages
└───x86_64-linux
├───changelogJson: package 'changelog.json' # Ergebnis davon `CHANGELOG.md` inzu json zu parsen
├───ciDocker: package 'docker-image-uniworx-ci.tar.gz'
├───"uniworx:exe:uniworx": package 'uniworx-exe-uniworx-25.21.12'
├───"uniworx:exe:uniworx-wflint": package 'uniworx-exe-uniworx-wflint-25.21.12'
├───"uniworx:exe:uniworxdb": package 'uniworx-exe-uniworxdb-25.21.12'
├───"uniworx:exe:uniworxload": package 'uniworx-exe-uniworxload-25.21.12'
├───"uniworx:lib:uniworx": package 'uniworx-lib-uniworx-25.21.12'
├───"uniworx:test:hlint": package 'uniworx-test-hlint-25.21.12'
├───"uniworx:test:yesod": package 'uniworx-test-yesod-25.21.12'
├───uniworxDemoDocker: package 'docker-image-uniworx-demo.tar.gz'
├───uniworxDocker: package 'docker-image-uniworx.tar.gz'
├───uniworxFrontend: package 'uniworx-frontend' # Fertig kompiliertes Frontend (output von `webpack`)
├───uniworxNodeDependencies: package 'node-dependencies-uni2work-25.21.0' # Frontend dependencies (`node_modules`-Ordner)
└───uniworxWellKnown: package 'uniworx-well-known' # Fixed-Output derivation von den mit web-service generierten Favicons
Die Outputs in apps können ausgeführt werden wie z.B.:
gkleen@uni2work-dev1 ~fradrive ❯ nix run .#jqChangelogJson '.title'
"Changelog"
Alle Tests aus checks können auf einmal ausgeführt werden mit nix flake check.
Die nix-expressions sind aufgeteilt über den nix-Ordner.
Gelegentlich angepasst werden müssen nix/docker/{ci,demo}-version.json (nix/docker/version.json wird von npm run release automatisch gebumpt); genau dann wenn sich die nix-unstable bzw. uniworx-demo docker container semantisch verändern, sonst wird die neue Version i.A. nicht korrekt inzu gitlab.com geschoben und der Fraport tut sich schwer sie zu deployen.
Bei ci-version.json nicht vergessen auch .gitlab-ci.yml anzupassen, damit auch das CI die neue Version benutzt.
Um das Stack Projekt zu bauen wird haskell.nix verwendet.
Es kann in Zukunft lohnenswert sein zu investigieren damit vollständig statisch gelinkte uni2work binaries zu erzeugen; das würde das deployment an der LMU vereinfachen.
Für das Frontend wurde die Expression mit node2nix erzeugt; bei neuen Frontend dependencies muss das evtl. wiederholt werden.
Das betrifft dann alle Dateien in nix/frontend.
uniworxWellKnown ist, weil das generieren der favicons mit realfavicongenerator netzwerk zugriff benötigt, eine fixed output derivation.
D.h. der hash des Ergebnis wird von vorneherein festgelegt und i.A. nicht geprüft, ob dieser auch noch aktuell ist.
Es muss also, wann immer eine Änderung des Ergebnis bei der Generierung der well known files, bzw. der favicons, erwartet wird, manuell eingegriffen werden.
Hierfür in nix/uniworx/well-known.nix den outputHash temporär auf "" ändern und bauen (nix -L build .#uniworxWellKnown). Das wird dann in einer Fehlermeldung bzgl. hash mismatch ändern. Den tatsächlichen Hash kann man dann in den outputHash kopieren (den sha256--Präfix weglassen).
.gitlab-ci.yml enthält die Spezifikation welche Jobs im Gitlab CI ausgeführt werden sollen.
Hierfür hat uni2work-dev2 einen ein-node-Kubernetes-Cluster (k3s) und darin den gitlab-runner installiert.
Wenn ein neuer Commit gepusht wird, queued gitlab2.rz intern die erforderlichen jobs, der runner auf uni2work-dev2 sammelt sie ein und führt sie im Kubernetes auf uni2work-dev2 aus.
Hierfür wird als Environment der nix-unstable docker container verwendet (ist im .gitlab-ci.yml festgelegt). Ein custom-container ist notwendig, damit ein hinreichendes modernes nix für die flake Befehle im Container vorhanden ist.
Das CI führt im Wesentlichen nur nix-Befehle aus und reicht die transitiven closures der build-Produkte als Artefakte von einem Job zum nächsten. Am Ende werden docker container inzu gitlab.com hochgeladen.
Die Credentials hierfür liegen in den CI Variables.
Extrem wichtig für die performance ist adequates caching; da nix vollständig reproduzierbar und isoliert baut, würde sonst jeder der jobs i.A. jede Menge dependencies unnötig neu bauen müssen.
Es ist daher im Kubernetes auf uni2work-dev2 ein Minio (S3-kompatibler Fileserver mit HTTP Api) und nix im build container ist konfiguriert, sodass es nach jedem Build das Ergebnis in den minio schiebt und den minio benutzen kann um dort gecachte build-Ergebnisse zu verwenden statt neu bauen zu müssen.
Es kann passieren, dass der minio auf Dauer voll wird; in diesem Fall kann man getrost alte Builds löschen bzw. den minio komplett leeren.
Das entsprechende Verzeichnis liegt auf uni2work-dev2 unterhalb von /var/lib/rancher/k3s/storage/; aktuell ist es /var/lib/rancher/k3s/storage/pvc-c8eea2d8-b7dd-4cf3-837f-9d36fa31ede3_fradrive_gitlab-runner-cache-pvc/nix-cache.