diff --git a/Dockerfile b/Dockerfile index 7f73afdf1..b8d47762e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +# syntax=docker/dockerfile:1.7 + FROM ubuntu:26.04 # Set DEBIAN_FRONTEND to noninteractive to avoid prompts during package installations @@ -27,10 +29,6 @@ RUN apt-get update && apt-get install -y \ ARG USER=runner ARG USER_UID=1001 ARG USER_GID=$USER_UID -ARG COMMIT_SHA=main -ARG GITHUB_TOKEN -ARG GITHUB_PR -ENV GITHUB_PR=${GITHUB_PR} RUN set -e; \ groupadd --gid $USER_GID $USER; \ @@ -49,17 +47,29 @@ RUN mkdir -p /etc/nix && \ echo "trusted-users = root $USER" > /etc/nix/nix.conf && \ echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf && \ echo "filter-syscalls = false" >> /etc/nix/nix.conf && \ - echo "sandbox = true" >> /etc/nix/nix.conf && \ - if [ -n "$GITHUB_TOKEN" ]; then \ - echo "access-tokens = github.com=$GITHUB_TOKEN" >> /etc/nix/nix.conf ; \ - fi + echo "sandbox = true" >> /etc/nix/nix.conf + +COPY --chown=$USER:$USER Makefile flake.nix flake.lock /tmp/dotfiles-cache/ +COPY --chown=$USER:$USER lib /tmp/dotfiles-cache/lib +COPY --chown=$USER:$USER install.sh /tmp/dotfiles-cache/install.sh +COPY --chown=$USER:$USER scripts/nix-cache-warmup.sh /tmp/dotfiles-cache/scripts/nix-cache-warmup.sh + +RUN --mount=type=secret,id=github_token,mode=0444 \ + set -e; \ + /usr/bin/nix-daemon & \ + sleep 5 && \ + sudo -u "$USER" -H env GITHUB_TOKEN_FILE=/run/secrets/github_token IN_DOCKER=true USER="$USER" \ + make -C /tmp/dotfiles-cache nix-cache-warmup + +ARG COMMIT_SHA +ARG GITHUB_PR= -RUN /usr/bin/nix-daemon & \ +RUN --mount=type=secret,id=github_token,mode=0444 \ + set -e; \ + /usr/bin/nix-daemon & \ sleep 5 && \ - # Run your dotfiles installation script. - # This script is expected to install fish and other tools. - # Make sure this script is idempotent or handles being run in a fresh environment. - sudo -u $USER -E -H bash -c "curl -fsSL https://raw.githubusercontent.com/shunkakinoki/dotfiles/$COMMIT_SHA/install.sh | bash" + sudo -u "$USER" -H env COMMIT_SHA="$COMMIT_SHA" GITHUB_PR="$GITHUB_PR" GITHUB_TOKEN_FILE=/run/secrets/github_token IN_DOCKER=true USER="$USER" \ + sh /tmp/dotfiles-cache/install.sh # Switch to the non-root user USER $USER diff --git a/Makefile b/Makefile index c6311404f..2aa8fe67f 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,11 @@ ARCH := $(shell uname -m) OS := $(shell uname -s) # Git variables -GIT_REMOTE_ORIGIN_URL := $(shell git config --get remote.origin.url) +GIT_REMOTE_ORIGIN_URL := $(shell git config --get remote.origin.url 2>/dev/null) GITHUB_REPO_PATH := $(shell echo $(GIT_REMOTE_ORIGIN_URL) | sed -n 's/.*github.com[:/]\(.*\)\.git/\1/p') GITHUB_REPO_OWNER := $(shell echo $(GITHUB_REPO_PATH) | cut -d'/' -f1) GITHUB_REPO_NAME := $(shell echo $(GITHUB_REPO_PATH) | cut -d'/' -f2) -GIT_COMMIT_SHA := $(shell git rev-parse --short HEAD) +GIT_COMMIT_SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) # Env ironment variables NIX_ALLOW_UNFREE := NIXPKGS_ALLOW_UNFREE=1 @@ -151,7 +151,7 @@ help: ## Show this help message. ##@ General .PHONY: install -install: setup git-submodule-sync nix-build nix-switch shell-install ## Set up full environment (setup, flake-update, build, switch, shell-install). +install: setup git-submodule-sync nix-build nix-switch shell-install ## Set up full environment (setup, cache warmup, build, switch, shell-install). .PHONY: build build: nix-build ## Build Nix configuration. @@ -432,6 +432,18 @@ nix-install: ## Install Nix if not already installed. fi @echo "✅ Nix environment installed!" +.PHONY: nix-cache-warmup +nix-cache-warmup: ## Warm flake input metadata before build/switch. + @echo "🔥 Warming Nix flake cache..." + @if command -v nix >/dev/null 2>&1; then \ + $(MAKE) nix-connect; \ + $(MAKE) nix-trust; \ + $(NIX_ALLOW_UNFREE) sh ./scripts/nix-cache-warmup.sh . $(NIX_FLAGS); \ + echo "✅ Nix flake cache warmed"; \ + else \ + echo "⚠️ Nix unavailable; skipping cache warmup"; \ + fi + ##@ Nix .PHONY: nix-update @@ -448,6 +460,7 @@ nix-backup: ## Backup configuration files. fi .PHONY: nix-build +nix-build: nix-cache-warmup nix-build: nix-connect nix-trust ## Build Nix configuration. @echo "🏗️ Building Nix configuration for $(NIX_CONFIG_TYPE) on $(OS) $(ARCH) for USER=$(NIX_USERNAME)" @if [ "$$CI" = "true" ] || [ "$$IN_DOCKER" = "true" ]; then \ @@ -594,6 +607,7 @@ nix-lint: ## Lint Nix files with statix from the flake/dev shell. @echo "✅ All Nix files pass lint checks" .PHONY: nix-switch +nix-switch: nix-cache-warmup nix-switch: ## Activate Nix configuration. @echo "🔧 Activating Nix configuration for $(NIX_CONFIG_TYPE) on $(OS) $(ARCH) for USER=$(NIX_USERNAME)" @if [ "$$CI" = "true" ] || [ "$$IN_DOCKER" = "true" ]; then \ diff --git a/config/noctalia/default.nix b/config/noctalia/default.nix index 9ad825351..2d38ec3a8 100644 --- a/config/noctalia/default.nix +++ b/config/noctalia/default.nix @@ -60,6 +60,7 @@ { id = "PowerProfile"; } { id = "Volume"; } { id = "Brightness"; } + { id = "DarkModeToggle"; } { id = "ControlCenter"; } ]; }; diff --git a/install.sh b/install.sh index 74ab8196e..b4323dae3 100755 --- a/install.sh +++ b/install.sh @@ -38,6 +38,24 @@ else echo "USER variable is already set to: $USER. Ensuring it is exported." fi +NIX_GITHUB_TOKEN="" +if [ -n "${GITHUB_TOKEN:-}" ]; then + NIX_GITHUB_TOKEN="$GITHUB_TOKEN" +elif [ -n "${GITHUB_TOKEN_FILE:-}" ] && [ -r "$GITHUB_TOKEN_FILE" ]; then + NIX_GITHUB_TOKEN=$(cat "$GITHUB_TOKEN_FILE") +fi + +if [ -n "$NIX_GITHUB_TOKEN" ]; then + if [ -n "${NIX_CONFIG:-}" ]; then + NIX_CONFIG="${NIX_CONFIG} access-tokens = github.com=$NIX_GITHUB_TOKEN" + else + NIX_CONFIG="access-tokens = github.com=$NIX_GITHUB_TOKEN" + fi + export NIX_CONFIG + echo "Configured a GitHub token for Nix fetches during this install." +fi +unset NIX_GITHUB_TOKEN + # Install Nix if not already installed if ! command -v nix >/dev/null 2>&1; then echo "Installing Nix..." diff --git a/scripts/nix-cache-warmup.sh b/scripts/nix-cache-warmup.sh new file mode 100755 index 000000000..52dd75ae1 --- /dev/null +++ b/scripts/nix-cache-warmup.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +set -e + +repo_dir=${1:-.} +if [ "$#" -gt 0 ]; then + shift +fi + +nix_github_token="" +if [ -n "${GITHUB_TOKEN:-}" ]; then + nix_github_token="$GITHUB_TOKEN" +elif [ -n "${GITHUB_TOKEN_FILE:-}" ] && [ -r "$GITHUB_TOKEN_FILE" ]; then + nix_github_token=$(cat "$GITHUB_TOKEN_FILE") +fi + +if [ -n "$nix_github_token" ]; then + if [ -n "${NIX_CONFIG:-}" ]; then + NIX_CONFIG="${NIX_CONFIG} +access-tokens = github.com=$nix_github_token" + else + NIX_CONFIG="access-tokens = github.com=$nix_github_token" + fi + export NIX_CONFIG +fi +unset nix_github_token + +if ! command -v nix >/dev/null 2>&1; then + echo "Nix unavailable; skipping cache warmup" + exit 0 +fi + +nix flake metadata "$repo_dir" "$@" --no-write-lock-file >/dev/null diff --git a/spec/coverage_spec.sh b/spec/coverage_spec.sh index e33ea195d..a78f21859 100644 --- a/spec/coverage_spec.sh +++ b/spec/coverage_spec.sh @@ -438,6 +438,7 @@ scripts/check-nix-inline-scripts.sh scripts/find-built-iso.sh scripts/fishtape-wrapper.sh scripts/llm-update.sh +scripts/nix-cache-warmup.sh scripts/sync-codex-security.sh scripts/sync-rtk-rewrite.sh scripts/update-gitalias.sh diff --git a/spec/nix_cache_warmup_spec.sh b/spec/nix_cache_warmup_spec.sh new file mode 100644 index 000000000..e626a9bf4 --- /dev/null +++ b/spec/nix_cache_warmup_spec.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2329,SC2034,SC2016 + +Describe 'scripts/nix-cache-warmup.sh' +SCRIPT="$PWD/scripts/nix-cache-warmup.sh" + +Describe 'script properties' +It 'uses sh shebang' +When run bash -c "head -1 '$SCRIPT'" +The output should include '#!/bin/sh' +End + +It 'uses strict mode' +When run bash -c "head -5 '$SCRIPT'" +The output should include 'set -e' +End +End + +Describe 'github token handling' +It 'checks GITHUB_TOKEN env var' +When run bash -c "grep 'GITHUB_TOKEN' '$SCRIPT'" +The output should include 'GITHUB_TOKEN' +End + +It 'checks GITHUB_TOKEN_FILE env var' +When run bash -c "grep 'GITHUB_TOKEN_FILE' '$SCRIPT'" +The output should include 'GITHUB_TOKEN_FILE' +End + +It 'sets access-tokens in NIX_CONFIG' +When run bash -c "grep 'access-tokens' '$SCRIPT'" +The output should include 'access-tokens' +End + +It 'unsets token variable after use' +When run bash -c "grep 'unset nix_github_token' '$SCRIPT'" +The output should include 'unset nix_github_token' +End +End + +Describe 'nix availability check' +It 'checks if nix command exists' +When run bash -c "grep 'command -v nix' '$SCRIPT'" +The output should include 'command -v nix' +End + +It 'skips gracefully when nix is unavailable' +When run bash -c "grep 'skipping cache warmup' '$SCRIPT'" +The output should include 'skipping cache warmup' +End +End + +Describe 'flake metadata' +It 'runs nix flake metadata' +When run bash -c "grep 'nix flake metadata' '$SCRIPT'" +The output should include 'nix flake metadata' +End + +It 'uses --no-write-lock-file flag' +When run bash -c "grep 'no-write-lock-file' '$SCRIPT'" +The output should include '--no-write-lock-file' +End +End + +Describe 'repo directory argument' +It 'sets repo_dir' +When run bash -c "grep 'repo_dir=' '$SCRIPT'" +The output should include 'repo_dir=' +End +End + +Describe 'runtime behavior' +setup_runtime() { + TEMP_DIR=$(mktemp -d) + cp -f "$SCRIPT" "$TEMP_DIR/nix-cache-warmup.sh" + chmod +x "$TEMP_DIR/nix-cache-warmup.sh" + mkdir -p "$TEMP_DIR/bin" +} + +cleanup_runtime() { + rm -rf "$TEMP_DIR" +} + +Before 'setup_runtime' +After 'cleanup_runtime' + +It 'exits successfully when nix is unavailable' +When run env PATH="$TEMP_DIR/bin" /bin/sh "$TEMP_DIR/nix-cache-warmup.sh" "$TEMP_DIR" +The status should be success +The output should include 'Nix unavailable; skipping cache warmup' +End + +It 'invokes nix flake metadata with tokenized NIX_CONFIG' +cat >"$TEMP_DIR/bin/nix" <<'EOF' +#!/bin/sh +echo "ARGS:$*" >>"$TMPDIR/nix.log" +echo "NIX_CONFIG:$NIX_CONFIG" >>"$TMPDIR/nix.log" +EOF +chmod +x "$TEMP_DIR/bin/nix" +mkdir -p "$TEMP_DIR/repo" + +When run bash -c "TMPDIR='$TEMP_DIR' PATH='$TEMP_DIR/bin:$PATH' GITHUB_TOKEN='ghp_test_token' /bin/sh '$TEMP_DIR/nix-cache-warmup.sh' '$TEMP_DIR/repo' --show-trace >/dev/null; cat '$TEMP_DIR/nix.log'" +The status should be success +The output should include 'ARGS:flake metadata' +The output should include '--no-write-lock-file' +The output should include '--show-trace' +The output should include 'NIX_CONFIG:access-tokens = github.com=ghp_test_token' +End +End + +End