#!/usr/bin/env bash # Deployment script for both NixOS configs and individual services. # # Usage: # push.sh Biz.nix # NixOS deploy (existing behavior) # push.sh Biz/PodcastItLater/Web.py # Service deploy (new behavior) # # For service deploys: # 1. Builds the target with bild (caches to S3 by default) # 2. Updates the manifest.json in S3 with new store path # 3. Deployer on target picks up change within 5 minutes # # Environment: # CODEROOT - Root of the codebase (required) # NIX_CACHE_KEY - Path to signing key (required for service deploys) set -euo pipefail # Colors GRN='\033[0;32m' YLW='\033[0;33m' RED='\033[0;31m' NC='\033[0m' # No Color # Derive service name from target path # Biz/PodcastItLater/Web.py -> podcastitlater-web # Biz/Storybook.py -> storybook derive_service_name() { local target="$1" # Remove extension local base="${target%.*}" # Remove Biz/ prefix if present base="${base#Biz/}" # Convert slashes to hyphens and lowercase echo "$base" | tr '/' '-' | tr '[:upper:]' '[:lower:]' } # NixOS deploy (existing behavior) nixos_deploy() { local target="$1" prefix=${PWD/$CODEROOT} if [[ "$prefix" == "" ]]; then target="$1" else target="$prefix.$1" fi what=$(realpath "${CODEROOT:?}/_/nix/$target") # hack: get the domain from the systemd service where=$(rg --only-matching --replace '$2' --regexp '(domainname ")(.*)(")' \ "$what/etc/systemd/system/domainname.service") nix copy --to ssh://"$USER"@"$where" "$what" ssh "$USER"@"$where" sudo nix-env --profile /nix/var/nix/profiles/system --set "$what" switch_cmd=( systemd-run -E LOCALE_ARCHIVE --setenv=XDG_RUNTIME_DIR="" --collect --no-ask-password --pipe --quiet --service-type=exec --unit=push-switch-to-configuration --wait "$what/bin/switch-to-configuration" "switch" ) # shellcheck disable=SC2029 ssh "$USER"@"$where" sudo "${switch_cmd[@]}" echo -e "${GRN}good: push: $target${NC}" } # Service deploy (new behavior) service_deploy() { local target="$1" local service_name service_name=$(derive_service_name "$target") echo -e "${YLW}info: push: deploying service $service_name${NC}" # 1. Build and cache echo -e "${YLW}info: push: building $target${NC}" if ! bild "$target"; then echo -e "${RED}fail: push: bild failed${NC}" exit 1 fi # Get store path from symlink in _/nix/ local symlink_path="${CODEROOT}/_/nix/${service_name}" if [[ ! -L "$symlink_path" ]]; then echo -e "${RED}fail: push: symlink not found: $symlink_path${NC}" exit 1 fi local store_path store_path=$(readlink "$symlink_path") if [[ -z "$store_path" ]]; then echo -e "${RED}fail: push: could not read store path from symlink${NC}" exit 1 fi echo -e "${YLW}info: push: cached $store_path${NC}" # 2. Get git revision local revision revision=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") # 3. Update manifest in S3 echo -e "${YLW}info: push: updating manifest${NC}" "${CODEROOT}/_/nix/deploy-manifest/bin/deploy-manifest" update "$service_name" "$store_path" "$revision" || { echo -e "${RED}fail: push: manifest update failed${NC}" exit 1 } echo -e "${GRN}good: push: $service_name deployed (deployer will pick up in <5 min)${NC}" } # Main main() { if [[ $# -lt 1 ]]; then echo "Usage: push.sh " echo " target.nix -> NixOS deploy" echo " target.py/.hs/.. -> Service deploy" exit 1 fi local target="$1" if [[ "$target" == *.nix ]]; then nixos_deploy "$target" else service_deploy "$target" fi } main "$@"