feat(macos): setup nix-darwin pour builder l'app Winnie
L'app se build sur le Mac en trois commandes, le toolchain restant dans le devShell du flake winnie (jamais installé sur le Mac) : cd ~/git/nixos && just mac # déploie ce setup winnie-sync # attrape ~/git/winnie depuis tower (rsync ssh) winnie-ios # simulateur ; npm ci + tauri ios init au besoin - modules/home-mac/winnie : winnie-doctor [--fix], winnie-sync [--delete], winnie-shell, winnie-front, winnie-macos, winnie-build-macos, winnie-ios, winnie-build-ios, winnie-verify. Scripts en writeShellApplication (shellcheck au build) ; scripts.nix est séparé du module pour être constructible depuis tower avec les pkgs linux et testable sans Mac. - profiles/macos : flakes + trusted-users dans nix.conf, et system.activationScripts.winnie-xcode (xcode-select -s, licence Xcode, -runFirstLaunch) pour que seule l'installation App Store reste manuelle. - Embarque aussi le setup SSH entrant du Mac (sshd, clé hermes@tower, tunnel inverse autossh) qui était déjà dans l'arbre de travail. Vérifié depuis tower : nix eval du darwinConfigurations.macos (toplevel et home-manager-generation) + build des scripts en x86_64-linux (shellcheck) et rsync de bout en bout depuis le dépôt de tower.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# Environnement de build de l'app Winnie sur le Mac (front Svelte 5 + shell
|
||||
# Tauri), pour que builder soit une commande, pas une procédure.
|
||||
#
|
||||
# Le toolchain (rust + triples iOS, node 22, cocoapods, tauri-cli, postgres) vit
|
||||
# dans le devShell du flake `winnie` : ce module ne fait qu'exposer les
|
||||
# commandes qui l'utilisent, chacune re-rentrant dans `nix develop`.
|
||||
# winnie-doctor état du poste (Xcode, simulateur, dépôt, API) ; --fix
|
||||
# winnie-sync rafraîchit ~/git/winnie depuis tower (LAN ou rack)
|
||||
# winnie-shell devShell interactif
|
||||
# winnie-front serveur Vite (HMR)
|
||||
# winnie-macos app macOS en dev ; winnie-build-macos = .app/.dmg
|
||||
# winnie-ios app iOS dans le simulateur ; winnie-build-ios = archive
|
||||
# winnie-verify front + svelte-check + cargo check
|
||||
#
|
||||
# Ce qui reste manuel, forcément : Xcode (App Store, Apple en interdit la
|
||||
# redistribution), le runtime du simulateur (winnie-doctor --fix le télécharge)
|
||||
# et un compte Apple pour signer un build pour iPhone réel.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.my.winnie;
|
||||
in {
|
||||
options.my.winnie = {
|
||||
enable = lib.mkEnableOption "l'environnement de build Winnie sur macOS";
|
||||
|
||||
repoRel = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "git/winnie";
|
||||
description = "Chemin du dépôt winnie, relatif à $HOME.";
|
||||
};
|
||||
|
||||
towerRepo = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/home/marc/git/winnie";
|
||||
description = "Chemin du même dépôt sur tower, source de winnie-sync (pas de remote git).";
|
||||
};
|
||||
|
||||
towerHosts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = ["towerlocal" "tower"];
|
||||
description = ''
|
||||
Alias ssh essayés dans l'ordre par winnie-sync : le LAN d'abord
|
||||
(towerlocal = 192.168.1.44), puis le tunnel par le VPS
|
||||
(tower = 10.100.0.3 via rack, tenu par l'agent autossh du Mac).
|
||||
'';
|
||||
};
|
||||
|
||||
apiUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://api.winnie.marcpartensky.com";
|
||||
description = "API interrogée par winnie-doctor et par le front.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = lib.attrValues (import ./scripts.nix {
|
||||
inherit pkgs lib;
|
||||
cfg = {
|
||||
inherit (cfg) repoRel towerRepo towerHosts apiUrl;
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
# Commandes de build Winnie pour macOS, en dérivations writeShellApplication :
|
||||
# shellcheck tourne au build et chaque commande est versionnée avec la config.
|
||||
#
|
||||
# Séparé du module home-manager exprès : ce fichier s'importe tel quel depuis
|
||||
# tower avec les pkgs x86_64-linux pour construire et tester les mêmes scripts
|
||||
# sans Mac (le Mac les reconstruit avec ses pkgs darwin).
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
cfg, # { repoRel, towerRepo, towerHosts, apiUrl }
|
||||
}:
|
||||
let
|
||||
subst = text:
|
||||
lib.replaceStrings
|
||||
["@REPO_REL@" "@TOWER_REPO@" "@TOWER_HOSTS@" "@API_URL@" "@WINNIE_SYNC@"]
|
||||
[
|
||||
cfg.repoRel
|
||||
cfg.towerRepo
|
||||
(lib.concatMapStrings (h: "'${h}' ") cfg.towerHosts)
|
||||
cfg.apiUrl
|
||||
(lib.getExe sync)
|
||||
]
|
||||
text;
|
||||
|
||||
# Scripts exécutés DANS le devShell du flake winnie : leurs outils (npm, cargo,
|
||||
# tauri, xcrun, simctl) viennent de ce shell, d'où runtimeInputs vide.
|
||||
inner = name: file: pkgs.writeShellApplication {
|
||||
name = "winnie-${name}-inner";
|
||||
text = subst (builtins.readFile file);
|
||||
};
|
||||
|
||||
# Commandes exposées : cd dans le dépôt puis ré-exécution de l'inner dans
|
||||
# `nix develop`, pour que rien ne dépende du PATH du Mac.
|
||||
dev = name: innerScript: pkgs.writeShellApplication {
|
||||
name = "winnie-${name}";
|
||||
runtimeInputs = [pkgs.nix];
|
||||
text = ''
|
||||
repo="$HOME/${cfg.repoRel}"
|
||||
if [ ! -f "$repo/flake.nix" ]; then
|
||||
echo "winnie-${name} : dépôt absent ($repo). Lance winnie-sync." >&2
|
||||
exit 1
|
||||
fi
|
||||
cd "$repo"
|
||||
exec nix --extra-experimental-features 'nix-command flakes' develop -c ${lib.getExe innerScript} "$@"
|
||||
'';
|
||||
};
|
||||
|
||||
# Rafraîchit le dépôt depuis tower : rsync du dépôt local de tower (le dépôt
|
||||
# n'a pas de remote git, tower est le seul original).
|
||||
sync = pkgs.writeShellApplication {
|
||||
name = "winnie-sync";
|
||||
runtimeInputs = [pkgs.rsync pkgs.openssh];
|
||||
text = subst (builtins.readFile ./scripts/sync.sh);
|
||||
};
|
||||
|
||||
# État du poste : Xcode, SDK iOS, runtime du simulateur, node_modules, API.
|
||||
# Xcode n'est pas dans le store Nix (App Store), donc ce diagnostic est la
|
||||
# seule source de vérité, et --fix automatise tout sauf l'installation d'Xcode.
|
||||
doctor = pkgs.writeShellApplication {
|
||||
name = "winnie-doctor";
|
||||
runtimeInputs = [pkgs.nix pkgs.curl pkgs.coreutils];
|
||||
text = subst (builtins.readFile ./scripts/doctor.sh);
|
||||
};
|
||||
|
||||
# DevShell interactif du projet, sans deviner le chemin du dépôt.
|
||||
shell = pkgs.writeShellApplication {
|
||||
name = "winnie-shell";
|
||||
runtimeInputs = [pkgs.nix];
|
||||
text = ''
|
||||
repo="$HOME/${cfg.repoRel}"
|
||||
if [ ! -f "$repo/flake.nix" ]; then
|
||||
echo "winnie-shell : dépôt absent ($repo). Lance winnie-sync." >&2
|
||||
exit 1
|
||||
fi
|
||||
cd "$repo"
|
||||
exec nix --extra-experimental-features 'nix-command flakes' develop "$@"
|
||||
'';
|
||||
};
|
||||
in {
|
||||
inherit doctor shell sync;
|
||||
|
||||
# Serveur Vite (HMR) du front Svelte.
|
||||
front = dev "front" (inner "front" ./scripts/front.sh);
|
||||
|
||||
# App Tauri : macOS (CLT suffisent) et iOS (Xcode requis).
|
||||
macos = dev "macos" (inner "macos" ./scripts/macos-dev.sh);
|
||||
macos-build = dev "build-macos" (inner "build-macos" ./scripts/macos-build.sh);
|
||||
ios = dev "ios" (inner "ios" ./scripts/ios-dev.sh);
|
||||
ios-build = dev "build-ios" (inner "build-ios" ./scripts/ios-build.sh);
|
||||
|
||||
# Contrôles avant commit (front + svelte-check + cargo check).
|
||||
verify = dev "verify" (inner "verify" ./scripts/verify.sh);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
# winnie-doctor : état du poste Mac pour builder Winnie.
|
||||
# winnie-doctor diagnostic seul
|
||||
# winnie-doctor --fix répare ce qui est automatisable (dépôt, node_modules,
|
||||
# developer dir Xcode, licence, runtime du simulateur)
|
||||
#
|
||||
# Xcode, le SDK iOS et les runtimes du simulateur viennent d'Apple, jamais du
|
||||
# store Nix : ce script est la seule source de vérité sur leur disponibilité.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
api="@API_URL@"
|
||||
sync_bin="@WINNIE_SYNC@"
|
||||
|
||||
fix=0
|
||||
if [ "${1:-}" = "--fix" ]; then
|
||||
fix=1
|
||||
fi
|
||||
|
||||
todo=0
|
||||
line() { printf '%-8s %s\n' "$1" "$2"; }
|
||||
ok() { line "[ok]" "$1"; }
|
||||
missing() { line "[manque]" "$1"; todo=$((todo + 1)); }
|
||||
info() { line "[-]" "$1"; }
|
||||
|
||||
printf 'winnie-doctor\n\n'
|
||||
|
||||
# --- nix ---------------------------------------------------------------
|
||||
if command -v nix >/dev/null 2>&1; then
|
||||
ok "nix : $(nix --version)"
|
||||
else
|
||||
missing "nix absent du PATH"
|
||||
fi
|
||||
|
||||
# --- dépôt winnie ------------------------------------------------------
|
||||
if [ -f "$repo/flake.nix" ]; then
|
||||
ok "dépôt : $repo"
|
||||
if nix --extra-experimental-features 'nix-command flakes' flake metadata "$repo" >/dev/null 2>&1; then
|
||||
ok "flake winnie évaluable"
|
||||
else
|
||||
missing "flake winnie non évaluable (nix flake metadata $repo)"
|
||||
fi
|
||||
else
|
||||
missing "dépôt : $repo"
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo " -> winnie-sync"
|
||||
"$sync_bin" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Xcode : seul le build iOS l'exige ---------------------------------
|
||||
xcode_ok=0
|
||||
if [ -d /Applications/Xcode.app ]; then
|
||||
ok "Xcode.app installé"
|
||||
xcode_ok=1
|
||||
else
|
||||
missing "Xcode.app absent (App Store, recherche « Xcode », ~8 Go)"
|
||||
info "sans Xcode : le front et le build macOS marchent, seul winnie-ios l'exige"
|
||||
info "fiche App Store : open 'macappstore://apps.apple.com/app/id497799835'"
|
||||
fi
|
||||
|
||||
if [ -x /usr/bin/xcode-select ]; then
|
||||
devdir="$(/usr/bin/xcode-select -p 2>/dev/null || true)"
|
||||
if [ "$devdir" = "/Applications/Xcode.app/Contents/Developer" ]; then
|
||||
ok "xcode-select : Xcode"
|
||||
elif [ "$xcode_ok" = 1 ]; then
|
||||
missing "xcode-select : ${devdir:-vide} (attendu /Applications/Xcode.app/Contents/Developer)"
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo " -> sudo xcode-select -s /Applications/Xcode.app (mot de passe macOS demandé)"
|
||||
sudo /usr/bin/xcode-select -s /Applications/Xcode.app
|
||||
sudo /usr/bin/xcodebuild -license accept || true
|
||||
/usr/bin/xcodebuild -runFirstLaunch || true
|
||||
fi
|
||||
else
|
||||
info "xcode-select : ${devdir:-vide} (Command Line Tools, suffisant hors iOS)"
|
||||
fi
|
||||
else
|
||||
info "xcode-select absent (poste non macOS ?)"
|
||||
fi
|
||||
|
||||
if [ "$xcode_ok" = 1 ]; then
|
||||
sdk="$(/usr/bin/xcrun --sdk iphoneos --show-sdk-version 2>/dev/null || true)"
|
||||
if [ -n "$sdk" ]; then
|
||||
ok "SDK iOS : $sdk"
|
||||
else
|
||||
missing "SDK iOS (xcrun --sdk iphoneos --show-sdk-version ; licence Xcode non acceptée ?)"
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo " -> sudo xcodebuild -license accept"
|
||||
sudo /usr/bin/xcodebuild -license accept || true
|
||||
fi
|
||||
fi
|
||||
|
||||
runtime_ok=0
|
||||
if /usr/bin/xcrun simctl list runtimes 2>/dev/null | grep -q 'iOS '; then
|
||||
runtime_ok=1
|
||||
fi
|
||||
if [ "$runtime_ok" = 1 ]; then
|
||||
ok "runtime du simulateur iOS"
|
||||
else
|
||||
missing "runtime du simulateur iOS"
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo " -> xcodebuild -downloadPlatform iOS (~8 Go, plusieurs minutes)"
|
||||
/usr/bin/xcodebuild -downloadPlatform iOS || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- front / node ------------------------------------------------------
|
||||
if [ -f "$repo/app/package.json" ]; then
|
||||
if [ -d "$repo/app/node_modules" ]; then
|
||||
ok "app/node_modules (npm ci fait)"
|
||||
else
|
||||
missing "app/node_modules"
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo " -> npm ci dans le devShell (~1 min)"
|
||||
(cd "$repo" && nix --extra-experimental-features 'nix-command flakes' develop -c bash -c "cd app && npm ci") || true
|
||||
fi
|
||||
fi
|
||||
if [ -d "$repo/app/src-tauri/gen/apple" ]; then
|
||||
ok "projet Xcode généré (src-tauri/gen/apple)"
|
||||
else
|
||||
info "src-tauri/gen/apple absent : winnie-ios le génère (tauri ios init)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- API ---------------------------------------------------------------
|
||||
code="$(curl -sS -m 8 -o /dev/null -w '%{http_code}' "$api/healthz" 2>/dev/null || true)"
|
||||
if [ "$code" = "200" ]; then
|
||||
ok "API : $api"
|
||||
else
|
||||
missing "API : $api/healthz (HTTP ${code:-aucune réponse})"
|
||||
fi
|
||||
|
||||
# --- verdict -----------------------------------------------------------
|
||||
printf '\n'
|
||||
if [ "$todo" -eq 0 ]; then
|
||||
echo "tout est prêt : winnie-ios (simulateur), winnie-front, winnie-macos."
|
||||
exit 0
|
||||
fi
|
||||
echo "$todo contrôle(s) en échec."
|
||||
if [ "$fix" = 1 ]; then
|
||||
echo "relance winnie-doctor pour vérifier ce qui reste."
|
||||
else
|
||||
echo "winnie-doctor --fix répare ce qui est automatisable."
|
||||
fi
|
||||
exit 1
|
||||
@@ -0,0 +1,12 @@
|
||||
# Serveur Vite (HMR) de app/ : joignable sur le LAN (http://<mac>:8080) et sur
|
||||
# dev.winnie.marcpartensky.com via Pangolin. Lancé par winnie-front, donc les
|
||||
# outils (node 22, npm) viennent du devShell du flake winnie.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-front] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
exec npm run dev "$@"
|
||||
@@ -0,0 +1,16 @@
|
||||
# Archive iOS pour un iPhone réel (et export IPA si un compte Apple est
|
||||
# configuré dans Xcode). Le simulateur n'exige aucun compte, pas ceci.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-build-ios] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
if [ ! -d src-tauri/gen/apple ]; then
|
||||
echo "[winnie-build-ios] tauri ios init (projet Xcode + pod install)"
|
||||
./node_modules/.bin/tauri ios init
|
||||
fi
|
||||
|
||||
exec ./node_modules/.bin/tauri ios build --target aarch64 "$@"
|
||||
@@ -0,0 +1,37 @@
|
||||
# App iOS en dev : simulateur (aucun compte Apple requis) ou iPhone branché.
|
||||
# npm ci et `tauri ios init` (projet Xcode + pod install) sont faits au besoin,
|
||||
# donc la toute première exécution est longue.
|
||||
# winnie-ios premier iPhone du simulateur
|
||||
# winnie-ios "iPhone 17 Pro" appareil précis, en argument positionnel
|
||||
# WINNIE_IOS_DEVICE=<nom|udid> winnie-ios
|
||||
# winnie-ios --force-ip-prompt sur le LAN (Vite sert déjà le LAN)
|
||||
# `tauri ios dev` prend l'appareil en positionnel (le champ `device` de la CLI
|
||||
# n'a pas d'attribut clap) et ouvre un menu interactif quand on ne passe rien :
|
||||
# d'où la recherche du premier iPhone pour que la commande marche seule.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-ios] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
if [ ! -d src-tauri/gen/apple ]; then
|
||||
echo "[winnie-ios] tauri ios init (projet Xcode + pod install)"
|
||||
./node_modules/.bin/tauri ios init
|
||||
fi
|
||||
|
||||
args=("$@")
|
||||
if [ "${#args[@]}" -eq 0 ] && [ -n "${WINNIE_IOS_DEVICE:-}" ]; then
|
||||
args=("$WINNIE_IOS_DEVICE")
|
||||
fi
|
||||
|
||||
if [ "${#args[@]}" -eq 0 ]; then
|
||||
sim="$(xcrun simctl list devices available 2>/dev/null | awk -F ' \\(' '/^ *iPhone/ {sub(/^ */, "", $1); print $1; exit}' || true)"
|
||||
if [ -n "$sim" ]; then
|
||||
echo "[winnie-ios] simulateur : $sim"
|
||||
args=("$sim")
|
||||
fi
|
||||
fi
|
||||
|
||||
exec ./node_modules/.bin/tauri ios dev "${args[@]}"
|
||||
@@ -0,0 +1,10 @@
|
||||
# Bundle macOS (.app + .dmg) : app/src-tauri/target/release/bundle/.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-build-macos] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
exec ./node_modules/.bin/tauri build "$@"
|
||||
@@ -0,0 +1,11 @@
|
||||
# App macOS (fenêtre Tauri + Vite en HMR) : ni Xcode ni simulateur, les
|
||||
# Command Line Tools suffisent.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-macos] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
exec ./node_modules/.bin/tauri dev "$@"
|
||||
@@ -0,0 +1,62 @@
|
||||
# winnie-sync : rafraîchit ~/git/winnie depuis tower, la source de vérité
|
||||
# (le dépôt n'a pas de remote git : tower est le seul original).
|
||||
# Le premier alias ssh qui répond gagne : LAN d'abord (towerlocal), puis le
|
||||
# tunnel par le VPS (tower -> 10.100.0.3 via rack, tenu par l'agent autossh).
|
||||
# winnie-sync copie incrémentale, garde les fichiers locaux en trop
|
||||
# winnie-sync --delete miroir strict de tower (supprime les fichiers en trop)
|
||||
repo="$HOME/@REPO_REL@"
|
||||
tower_repo="@TOWER_REPO@"
|
||||
hosts=(@TOWER_HOSTS@)
|
||||
|
||||
delete=()
|
||||
if [ "${1:-}" = "--delete" ]; then
|
||||
delete=(--delete)
|
||||
elif [ -n "${1:-}" ]; then
|
||||
echo "usage: winnie-sync [--delete]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
host=""
|
||||
for h in "${hosts[@]}"; do
|
||||
printf 'winnie-sync : %s... ' "$h"
|
||||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new "$h" true >/dev/null 2>&1; then
|
||||
echo "ok"
|
||||
host="$h"
|
||||
break
|
||||
fi
|
||||
echo "injoignable"
|
||||
done
|
||||
|
||||
if [ -z "$host" ]; then
|
||||
echo "winnie-sync : tower injoignable (essayé : ${hosts[*]})" >&2
|
||||
echo "winnie-sync : LAN = towerlocal (192.168.1.44) ; hors LAN = tower (via rack)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$repo"
|
||||
echo "winnie-sync : $host:$tower_repo -> $repo"
|
||||
|
||||
# La barre de progression seulement sur un terminal (sans quoi un log
|
||||
# redirigé se remplit de retours chariot).
|
||||
progress=()
|
||||
if [ -t 1 ]; then
|
||||
progress=(--info=progress2)
|
||||
fi
|
||||
|
||||
# Ce qui ne traverse jamais : binaires par plateforme (node_modules, tauri-cli)
|
||||
# et artefacts liés à la machine (target, projet Xcode généré, clés de signature).
|
||||
rsync -a --no-owner --no-group "${progress[@]}" \
|
||||
--exclude /.direnv/ \
|
||||
--exclude /backend/target/ \
|
||||
--exclude /ingest/target/ \
|
||||
--exclude /app/node_modules/ \
|
||||
--exclude /app/dist/ \
|
||||
--exclude /app/src-tauri/target/ \
|
||||
--exclude /app/src-tauri/gen/ \
|
||||
--exclude /app/.android-sdk/ \
|
||||
--exclude /app/.android-user/ \
|
||||
--exclude /app/.keys/ \
|
||||
"${delete[@]}" \
|
||||
"$host:$tower_repo/" "$repo/"
|
||||
|
||||
echo "winnie-sync : terminé (winnie-doctor pour l'état du poste)."
|
||||
@@ -0,0 +1,29 @@
|
||||
# Contrôles avant commit, dans l'ordre du projet : build du front (vite),
|
||||
# svelte-check, puis cargo check du backend et de l'ingest.
|
||||
# `npm run check` n'est pas appelé tel quel : son `tsc -p tsconfig.node.json`
|
||||
# échoue sur TS2688 (Cannot find type definition file for 'node', @types/node
|
||||
# absent de app/package.json), une dette antérieure au projet.
|
||||
repo="$HOME/@REPO_REL@"
|
||||
cd "$repo/app"
|
||||
|
||||
if [ ! -d node_modules ]; then
|
||||
echo "[winnie-verify] npm ci"
|
||||
npm ci
|
||||
fi
|
||||
|
||||
echo "[winnie-verify] front : vite build"
|
||||
npm run build
|
||||
|
||||
echo "[winnie-verify] front : svelte-check"
|
||||
./node_modules/.bin/svelte-check --tsconfig ./tsconfig.app.json
|
||||
|
||||
cd "$repo"
|
||||
echo "[winnie-verify] backend : cargo check"
|
||||
cargo check --manifest-path backend/Cargo.toml
|
||||
|
||||
if [ -f ingest/Cargo.toml ]; then
|
||||
echo "[winnie-verify] ingest : cargo check"
|
||||
cargo check --manifest-path ingest/Cargo.toml
|
||||
fi
|
||||
|
||||
echo "[winnie-verify] ok"
|
||||
@@ -38,6 +38,11 @@ in {
|
||||
# inputs.sops.nixosModules.sops # Inclus dans sopswarden
|
||||
|
||||
# ../../services/wg-quick
|
||||
|
||||
# Tunnel SSH inverse Mac -> rack (launchd agent) : expose le sshd du Mac
|
||||
# sur 127.0.0.1:2223 du VPS, pour que tower (ou marc) joigne le Mac hors
|
||||
# LAN. La clé du Mac est déjà autorisée pour root@rack.
|
||||
../../modules/home-mac/autossh
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
@@ -51,6 +56,16 @@ in {
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
networking.hostName = "macos";
|
||||
|
||||
# --- Nix : flakes et utilisateurs de confiance -------------------------
|
||||
# Le Mac build Winnie par `nix develop` (voir modules/home-mac/winnie) : les
|
||||
# flakes doivent être actives dans /etc/nix/nix.conf, pas seulement passées en
|
||||
# ligne de commande, et marc doit être trusted-user pour que le client puisse
|
||||
# charger des substituts ou surcharger une option locale.
|
||||
nix.settings = {
|
||||
experimental-features = ["nix-command" "flakes"];
|
||||
trusted-users = ["root" "@admin"];
|
||||
};
|
||||
|
||||
# services.nix-daemon.enable = true; <- supprime cette ligne
|
||||
|
||||
home-manager = {
|
||||
@@ -69,6 +84,16 @@ in {
|
||||
|
||||
system.primaryUser = "marc";
|
||||
|
||||
# --- SSH entrant : Remote Login + clés -----------------------------------
|
||||
# Active sshd (com.openssh.sshd) : nix-darwin écrit sshd_config.d et fait
|
||||
# `launchctl enable + bootstrap` à l'activation (pas de systemsetup, qui
|
||||
# exige Full Disk Access). La clé hermes@tower est posée dans
|
||||
# /Users/marc/.ssh/authorized_keys par users/mac/home.nix (home.activation).
|
||||
# Reachabilité : LAN direct (tower et le Mac sont sur 192.168.1.0/24) ;
|
||||
# hors LAN via le tunnel inverse autossh (modules/home-mac/autossh) que
|
||||
# tower joint par `ssh -J rack -p 2223 marc@localhost`.
|
||||
services.openssh.enable = true;
|
||||
|
||||
# deactivated
|
||||
homebrew = {
|
||||
enable = false;
|
||||
@@ -101,5 +126,24 @@ in {
|
||||
cp -R ${pangolin-client}/Applications/Pangolin.app /Applications/
|
||||
'';
|
||||
|
||||
# --- Xcode : installation manuelle, reste automatique -------------------
|
||||
# Apple interdit la redistribution du SDK : Xcode vient de l'App Store (aucun
|
||||
# paquet nix ne peut le fournir). Tout ce qui suit l'installation est en
|
||||
# revanche scriptable, et c'est ici : developer dir, licence, premiers
|
||||
# composants. Le runtime du simulateur (~8 Go) n'est pas téléchargé
|
||||
# silencieusement : `winnie-doctor --fix` s'en charge à la demande.
|
||||
system.activationScripts.winnie-xcode.text = ''
|
||||
if [ -d /Applications/Xcode.app ]; then
|
||||
if [ "$(/usr/bin/xcode-select -p 2>/dev/null || true)" != "/Applications/Xcode.app/Contents/Developer" ]; then
|
||||
echo "winnie : xcode-select -> /Applications/Xcode.app" >&2
|
||||
/usr/bin/xcode-select -s /Applications/Xcode.app || true
|
||||
/usr/bin/xcodebuild -license accept || true
|
||||
/usr/bin/xcodebuild -runFirstLaunch || true
|
||||
fi
|
||||
else
|
||||
echo "winnie : Xcode absent (App Store) ; le build macOS marche sans, seul winnie-ios l'exige" >&2
|
||||
fi
|
||||
'';
|
||||
|
||||
system.stateVersion = 6;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
../../modules/home-mac/aerospace
|
||||
../../modules/home-mac/hermes-skins
|
||||
../../modules/home-mac/winnie
|
||||
# ../../modules/home-mac/autossh
|
||||
];
|
||||
|
||||
@@ -120,6 +121,11 @@
|
||||
# Skins Hermes (pack Hermes Menagerie) -> ~/.hermes/skins/
|
||||
my.hermesSkins.enable = true;
|
||||
|
||||
# Build de l'app Winnie sur le Mac : winnie-doctor, winnie-sync, winnie-ios,
|
||||
# winnie-macos, winnie-front, winnie-verify. Le toolchain reste dans le
|
||||
# devShell du flake `winnie`, ces commandes ne font que l'appeler.
|
||||
my.winnie.enable = true;
|
||||
|
||||
# Connexions Eternal Terminal vers les hôtes NixOS : `et tower` = zellij enregistré.
|
||||
my.et = {
|
||||
enable = true;
|
||||
@@ -128,4 +134,35 @@
|
||||
towerlocal = {};
|
||||
};
|
||||
};
|
||||
|
||||
# Clé SSH de l'agent hermes@tower : l'agent (qui tourne sur tower) peut se
|
||||
# connecter au Mac en marc@… (sshd activé par services.openssh dans
|
||||
# profiles/macos/configuration.nix). Append idempotent plutôt que
|
||||
# home.file.".ssh/authorized_keys" : ne remplace JAMAIS un authorized_keys
|
||||
# déjà en place (le .bak de home-manager perdrait les clés existantes).
|
||||
home.activation.addHermesAuthorizedKey = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
key='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKF3huPUXHP6P6SBXHHw9k7HGh6Cs8ntoRk2pnqrG2Hc hermes@tower'
|
||||
mkdir -p "$HOME/.ssh"
|
||||
chmod 700 "$HOME/.ssh"
|
||||
touch "$HOME/.ssh/authorized_keys"
|
||||
grep -qxF "$key" "$HOME/.ssh/authorized_keys" || echo "$key" >> "$HOME/.ssh/authorized_keys"
|
||||
chmod 600 "$HOME/.ssh/authorized_keys"
|
||||
'';
|
||||
|
||||
# Accès distant par rack (VPS à IP publique) : marche depuis n'importe quel
|
||||
# réseau, sans VPN sur le Mac. rack joint tower par le tunnel wg1
|
||||
# (10.100.0.3) et le LAN (192.168.1.0/24) que tower route pour wg1.
|
||||
# mkForce : ces deux entrées remplacent celles du module partagé.
|
||||
programs.ssh.settings = {
|
||||
"tower" = lib.mkForce {
|
||||
HostName = "10.100.0.3";
|
||||
User = "marc";
|
||||
ProxyJump = "rack";
|
||||
};
|
||||
"deck" = lib.mkForce {
|
||||
HostName = "192.168.1.67";
|
||||
User = "marc";
|
||||
ProxyJump = "rack";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user