├── .github ├── dependabot.yml └── workflows │ ├── build-template.yml │ ├── build.yml │ ├── lint.yml │ └── update-flake-lock.yml ├── .gitignore ├── LICENSE ├── README.md ├── apps ├── README.md ├── aarch64-darwin │ ├── apply │ ├── build │ ├── build-switch │ ├── check-keys │ ├── copy-keys │ ├── create-keys │ └── rollback ├── aarch64-linux ├── x86_64-darwin │ ├── apply │ ├── build │ ├── build-switch │ ├── check-keys │ ├── copy-keys │ └── create-keys └── x86_64-linux │ ├── apply │ ├── build-switch │ ├── check-keys │ ├── copy-keys │ ├── create-keys │ ├── install │ └── install-with-secrets ├── flake.lock ├── flake.nix ├── hosts ├── darwin │ └── default.nix └── nixos │ └── default.nix ├── modules ├── darwin │ ├── README.md │ ├── casks.nix │ ├── dock │ │ └── default.nix │ ├── files.nix │ ├── home-manager.nix │ ├── packages.nix │ └── secrets.nix ├── nixos │ ├── README.md │ ├── files.nix │ ├── home-manager.nix │ ├── packages.nix │ └── secrets.nix └── shared │ ├── README.md │ ├── cachix │ └── default.nix │ ├── config │ ├── emacs │ │ ├── config.el │ │ ├── config.org │ │ └── init.el │ └── p10k.zsh │ ├── default.nix │ ├── files.nix │ ├── home-manager.nix │ └── packages.nix ├── overlays └── README.md └── templates ├── starter-with-secrets ├── apps │ ├── aarch64-darwin │ │ ├── apply │ │ ├── build │ │ ├── build-switch │ │ ├── check-keys │ │ ├── copy-keys │ │ ├── create-keys │ │ └── rollback │ ├── aarch64-linux │ ├── x86_64-darwin │ │ ├── apply │ │ ├── build │ │ ├── build-switch │ │ ├── check-keys │ │ ├── copy-keys │ │ └── create-keys │ └── x86_64-linux │ │ ├── apply │ │ └── build-switch ├── flake.nix ├── hosts │ ├── darwin │ │ └── default.nix │ └── nixos │ │ └── default.nix ├── modules │ ├── darwin │ │ ├── README.md │ │ ├── casks.nix │ │ ├── dock │ │ │ └── default.nix │ │ ├── files.nix │ │ ├── home-manager.nix │ │ ├── packages.nix │ │ └── secrets.nix │ ├── nixos │ │ ├── README.md │ │ ├── config │ │ │ ├── login-wallpaper.png │ │ │ ├── polybar │ │ │ │ ├── bars.ini │ │ │ │ ├── colors.ini │ │ │ │ ├── config.ini │ │ │ │ ├── modules.ini │ │ │ │ └── user_modules.ini │ │ │ └── rofi │ │ │ │ ├── colors.rasi │ │ │ │ ├── confirm.rasi │ │ │ │ ├── launcher.rasi │ │ │ │ ├── message.rasi │ │ │ │ ├── networkmenu.rasi │ │ │ │ ├── powermenu.rasi │ │ │ │ └── styles.rasi │ │ ├── disk-config.nix │ │ ├── files.nix │ │ ├── home-manager.nix │ │ ├── packages.nix │ │ └── secrets.nix │ └── shared │ │ ├── README.md │ │ ├── config │ │ ├── emacs │ │ │ ├── config.org │ │ │ └── init.el │ │ └── p10k.zsh │ │ ├── default.nix │ │ ├── files.nix │ │ ├── home-manager.nix │ │ └── packages.nix └── overlays │ ├── 10-feather-font.nix │ └── README.md └── starter ├── apps ├── aarch64-darwin │ ├── apply │ ├── build │ ├── build-switch │ └── rollback ├── aarch64-linux ├── x86_64-darwin │ ├── apply │ ├── build │ ├── build-switch │ ├── check-keys │ ├── copy-keys │ └── create-keys └── x86_64-linux │ ├── apply │ └── build-switch ├── flake.nix ├── hosts ├── darwin │ └── default.nix └── nixos │ └── default.nix ├── modules ├── darwin │ ├── README.md │ ├── casks.nix │ ├── dock │ │ └── default.nix │ ├── files.nix │ ├── home-manager.nix │ └── packages.nix ├── nixos │ ├── README.md │ ├── config │ │ ├── login-wallpaper.png │ │ ├── polybar │ │ │ ├── bars.ini │ │ │ ├── colors.ini │ │ │ ├── config.ini │ │ │ ├── modules.ini │ │ │ └── user_modules.ini │ │ └── rofi │ │ │ ├── colors.rasi │ │ │ ├── confirm.rasi │ │ │ ├── launcher.rasi │ │ │ ├── message.rasi │ │ │ ├── networkmenu.rasi │ │ │ ├── powermenu.rasi │ │ │ └── styles.rasi │ ├── disk-config.nix │ ├── files.nix │ ├── home-manager.nix │ └── packages.nix └── shared │ ├── README.md │ ├── config │ ├── emacs │ │ ├── config.org │ │ └── init.el │ └── p10k.zsh │ ├── default.nix │ ├── files.nix │ ├── home-manager.nix │ └── packages.nix └── overlays ├── 10-feather-font.nix └── README.md /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/build-template.yml: -------------------------------------------------------------------------------- 1 | name: Build Template 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | template: 7 | required: true 8 | type: string 9 | arch: 10 | required: true 11 | type: string 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | outputs: 17 | build-success: ${{ steps.build-result.outputs.success }} 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Install Nix 23 | uses: nixbuild/nix-quick-install-action@master 24 | 25 | - name: Set up cache 26 | uses: nix-community/cache-nix-action@main 27 | with: 28 | primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} 29 | restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }} 30 | 31 | - name: Initialize Nix Flake 32 | run: | 33 | mkdir -p my-config && cd my-config 34 | nix flake --extra-experimental-features 'nix-command flakes' init -t github:dustinlyons/nixos-config#${{ inputs.template }} 35 | 36 | - name: Apply CI User Info 37 | run: | 38 | # Set basic values for variables 39 | export USERNAME="ciuser" 40 | export GIT_EMAIL="ciuser@example.com" 41 | export GIT_NAME="CI User" 42 | export PRIMARY_IFACE="eth0" 43 | export HOST_NAME="ci-host" 44 | export BOOT_DISK="sda" 45 | 46 | # Function to replace tokens in each file 47 | replace_tokens() { 48 | local file="$1" 49 | if [[ $(basename "$file") != "apply" ]]; then 50 | sed -i -e "s/%USER%/$USERNAME/g" -e "s/%EMAIL%/$GIT_EMAIL/g" -e "s/%NAME%/$GIT_NAME/g" \ 51 | -e "s/%INTERFACE%/$PRIMARY_IFACE/g" -e "s/%DISK%/$BOOT_DISK/g" -e "s/%HOST%/$HOST_NAME/g" "$file" 52 | fi 53 | } 54 | 55 | # Traverse directories and replace tokens in each Nix file 56 | export -f replace_tokens 57 | cd /home/runner/work/nixos-config/nixos-config/my-config 58 | find . -type f -exec bash -c 'replace_tokens "$0"' {} \; 59 | 60 | echo "$USERNAME" > /tmp/username.txt 61 | 62 | - name: Build Nix Flake 63 | run: | 64 | cd /home/runner/work/nixos-config/nixos-config/my-config 65 | git add . 66 | 67 | echo "Building Flake..." 68 | if nix build --extra-experimental-features 'nix-command flakes' /home/runner/work/nixos-config/nixos-config/my-config#nixosConfigurations."${{ inputs.arch }}".config.system.build.toplevel; then 69 | echo "success=true" >> $GITHUB_ENV 70 | else 71 | echo "Build failed, listing flake.lock for debugging:" 72 | cat flake.lock 73 | echo "success=false" >> $GITHUB_ENV 74 | exit 1 75 | fi 76 | 77 | - name: Determine build result 78 | id: build-result 79 | run: echo "success=${{ env.success }}" >> $GITHUB_OUTPUT 80 | 81 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Starter Template 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'templates/starter/**' 9 | pull_request: 10 | branches: 11 | - main 12 | paths: 13 | - 'templates/starter/**' 14 | 15 | jobs: 16 | build-starter-template: 17 | uses: ./.github/workflows/build-template.yml 18 | with: 19 | template: 'starter' 20 | arch: 'x86_64-linux' 21 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Statix Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '.github/**' 9 | - 'README.md' 10 | pull_request: 11 | branches: 12 | - main 13 | paths-ignore: 14 | - '.github/**' 15 | - 'README.md' 16 | 17 | jobs: 18 | lint: 19 | runs-on: ubuntu-latest 20 | outputs: 21 | lint-success: ${{ steps.build-result.outputs.success }} 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Install Nix 27 | uses: DeterminateSystems/nix-installer-action@main 28 | 29 | - name: Run statix linter 30 | run: | 31 | echo "Linting Flake..." 32 | if nix run --extra-experimental-features 'nix-command flakes' nixpkgs#statix -- check .; then 33 | echo "success=true" >> $GITHUB_ENV 34 | else 35 | echo "Lint failed, listing flake.lock for debugging:" 36 | cat flake.lock 37 | echo "success=false" >> $GITHUB_ENV 38 | exit 1 39 | fi 40 | 41 | - name: Determine lint result 42 | id: build-result 43 | run: echo "success=${{ env.success }}" >> $GITHUB_OUTPUT 44 | -------------------------------------------------------------------------------- /.github/workflows/update-flake-lock.yml: -------------------------------------------------------------------------------- 1 | name: Update Flake Lock 2 | 3 | on: 4 | schedule: 5 | - cron: '0 23 * * 0' # Every Sunday at 11:00 PM 6 | 7 | jobs: 8 | check-build: 9 | uses: ./.github/workflows/build-template.yml 10 | with: 11 | template: 'starter' 12 | arch: 'x86_64-linux' 13 | 14 | update-flake: 15 | runs-on: ubuntu-latest 16 | needs: check-build 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Install Nix 22 | uses: nixbuild/nix-quick-install-action@master 23 | 24 | - name: Set up cache 25 | uses: nix-community/cache-nix-action@main 26 | with: 27 | primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} 28 | restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }} 29 | 30 | - name: Initalize flake 31 | run: | 32 | mkdir -p my-config && cd my-config 33 | nix flake --extra-experimental-features 'nix-command flakes' init -t github:dustinlyons/nixos-config#starter 34 | 35 | - name: Apply CI User Info 36 | run: | 37 | # Set basic values for variables 38 | export USERNAME="ciuser" 39 | export GIT_EMAIL="ciuser@example.com" 40 | export GIT_NAME="CI User" 41 | export PRIMARY_IFACE="eth0" 42 | export HOST_NAME="ci-host" 43 | export BOOT_DISK="sda" 44 | 45 | # Function to replace tokens in each file 46 | replace_tokens() { 47 | local file="$1" 48 | if [[ $(basename "$file") != "apply" ]]; then 49 | sed -i -e "s/%USER%/$USERNAME/g" -e "s/%EMAIL%/$GIT_EMAIL/g" -e "s/%NAME%/$GIT_NAME/g" \ 50 | -e "s/%INTERFACE%/$PRIMARY_IFACE/g" -e "s/%DISK%/$BOOT_DISK/g" -e "s/%HOST%/$HOST_NAME/g" "$file" 51 | fi 52 | } 53 | 54 | # Traverse directories and replace tokens in each Nix file 55 | export -f replace_tokens 56 | cd /home/runner/work/nixos-config/nixos-config/my-config 57 | find . -type f -exec bash -c 'replace_tokens "$0"' {} \; 58 | 59 | echo "$USERNAME" > /tmp/username.txt 60 | 61 | - name: Update flake.lock 62 | uses: DeterminateSystems/update-flake-lock@main 63 | with: 64 | token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} 65 | pr-title: "Update flake.lock" 66 | pr-labels: | 67 | dependencies 68 | automated 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | \#* 2 | *.swp 3 | result 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Dustin Lyons 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /apps/README.md: -------------------------------------------------------------------------------- 1 | # Apps 2 | The [apps](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-run#apps) in this directory are Nix [installables](https://nix.dev/manual/nix/2.22/command-ref/new-cli/nix?search=#installables), created using the [`mkApp`](https://github.com/dustinlyons/nixos-config/blob/main/flake.nix#L49) function declared within my `flake.nix` file. 3 | 4 | These Nix commands are tailored for different systems, including Linux (`x86_64-linux`, `aarch64-linux`) and Darwin (`aarch64-darwin`, `x86_64-darwin`). 5 | 6 | They execute with `nix run` and are referenced as part of the step-by-step instructions found in the [README](https://github.com/dustinlyons/nixos-config/blob/main/README.md). 7 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="aarch64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Cleaning up...${NC}" 17 | unlink ./result 18 | 19 | echo "${GREEN}Switch to new generation complete!${NC}" 20 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="aarch64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Switching to new generation...${NC}" 17 | # See https://github.com/nix-darwin/nix-darwin/issues/1457 on why we need sudo 18 | sudo ./result/sw/bin/darwin-rebuild switch --flake .#${SYSTEM_TYPE} $@ 19 | 20 | echo "${YELLOW}Cleaning up...${NC}" 21 | unlink ./result 22 | 23 | echo "${GREEN}Switch to new generation complete!${NC}" 24 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/check-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | lint_keys() { 12 | if [[ -f "${SSH_DIR}/id_ed25519" && -f "${SSH_DIR}/id_ed25519.pub" && -f "${SSH_DIR}/id_ed25519_agenix" && -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 13 | echo -e "${GREEN}All SSH keys are present.${NC}" 14 | else 15 | echo -e "${RED}Some SSH keys are missing.${NC}" 16 | if [[ ! -f "${SSH_DIR}/id_ed25519" ]]; then 17 | echo -e "${RED}Missing: id_ed25519${NC}" 18 | fi 19 | if [[ ! -f "${SSH_DIR}/id_ed25519.pub" ]]; then 20 | echo -e "${RED}Missing: id_ed25519.pub${NC}" 21 | fi 22 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix" ]]; then 23 | echo -e "${RED}Missing: id_ed25519_agenix${NC}" 24 | fi 25 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 26 | echo -e "${RED}Missing: id_ed25519_agenix.pub${NC}" 27 | fi 28 | echo -e "${GREEN}Run the createKeys command to generate the missing keys.${NC}" 29 | exit 1 30 | fi 31 | } 32 | 33 | lint_keys 34 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/copy-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | handle_no_usb() { 12 | echo -e ${RED}No USB drive found or mounted.${NC}" 13 | echo -e ${GREEN}If you have not yet set up your keys, run the script to generate new SSH keys.${NC}" 14 | exit 1 15 | } 16 | 17 | mount_usb() { 18 | MOUNT_PATH="" 19 | for dev in $(diskutil list | grep -o 'disk[0-9]'); do 20 | MOUNT_PATH="$(diskutil info /dev/${dev} | grep \"Mount Point\" | awk -F: '{print $2}' | xargs)" 21 | if [ -n "${MOUNT_PATH}" ]; then 22 | echo -e "${GREEN}USB drive found at ${MOUNT_PATH}.${NC}" 23 | break 24 | fi 25 | done 26 | 27 | if [ -z "${MOUNT_PATH}" ]; then 28 | echo -e "${RED}No USB drive found.${NC}" 29 | fi 30 | } 31 | 32 | copy_keys() { 33 | if [ -n "${MOUNT_PATH}" ]; then 34 | cp "${MOUNT_PATH}/id_ed25519_agenix.pub" ${SSH_DIR} 35 | cp "${MOUNT_PATH}/id_ed25519_agenix" ${SSH_DIR} 36 | chmod 600 ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 37 | else 38 | echo -e "${RED}No USB drive found. Aborting.${NC}" 39 | exit 1 40 | fi 41 | } 42 | 43 | setup_ssh_directory() { 44 | mkdir -p ${SSH_DIR} 45 | } 46 | 47 | set_keys() { 48 | cp ${MOUNT_PATH}/id_ed25519_github.pub ${SSH_DIR}/id_ed25519.pub 49 | cp ${MOUNT_PATH}/id_ed25519_github ${SSH_DIR}/id_ed25519 50 | chmod 600 ${SSH_DIR}/id_ed25519 51 | chmod 644 ${SSH_DIR}/id_ed25519.pub 52 | } 53 | 54 | change_ownership() { 55 | chown ${username}:staff ${SSH_DIR}/id_ed25519{,.pub} 56 | chown ${username}:staff ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 57 | } 58 | 59 | setup_ssh_directory 60 | mount_usb 61 | 62 | if [ -z "${MOUNT_PATH}" ]; then 63 | handle_no_usb 64 | else 65 | copy_keys 66 | set_keys 67 | change_ownership 68 | fi 69 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/create-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | setup_ssh_directory() { 12 | mkdir -p ${SSH_DIR} 13 | } 14 | 15 | prompt_for_key_generation() { 16 | local key_name=$1 17 | if [[ -f "${SSH_DIR}/${key_name}" ]]; then 18 | echo -e "${RED}Existing SSH key found for ${key_name}.${NC}" 19 | cat "${SSH_DIR}/${key_name}.pub" 20 | read -p "Do you want to replace it? (y/n) " -n 1 -r 21 | echo 22 | if [[ $REPLY =~ ^[Yy]$ ]]; then 23 | return 0 # Indicate key should be replaced 24 | else 25 | return 1 # Indicate key should be kept 26 | fi 27 | fi 28 | return 0 # Indicate no key exists, so it should be created 29 | } 30 | 31 | generate_key() { 32 | local key_name=$1 33 | if prompt_for_key_generation "$key_name"; then 34 | ssh-keygen -t ed25519 -f "${SSH_DIR}/${key_name}" -N "" 35 | chown ${username}:staff "${SSH_DIR}/${key_name}"{,.pub} 36 | else 37 | echo -e "${GREEN}Kept existing ${key_name}.${NC}" 38 | fi 39 | } 40 | 41 | setup_ssh_directory 42 | generate_key "id_ed25519" 43 | generate_key "id_ed25519_agenix" 44 | 45 | echo -e "${GREEN}SSH key setup complete.${NC}" 46 | echo -e "${GREEN}Remember to add the necessary keys to Github or other services as required.${NC}" 47 | -------------------------------------------------------------------------------- /apps/aarch64-darwin/rollback: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | FLAKE="Dustins-MBP" 9 | 10 | echo "${YELLOW}Available generations:${NC}" 11 | /run/current-system/sw/bin/darwin-rebuild --list-generations 12 | 13 | echo "${YELLOW}Enter the generation number for rollback:${NC}" 14 | read GEN_NUM 15 | 16 | if [ -z "$GEN_NUM" ]; then 17 | echo "${RED}No generation number entered. Aborting rollback.${NC}" 18 | exit 1 19 | fi 20 | 21 | echo "${YELLOW}Rolling back to generation $GEN_NUM...${NC}" 22 | /run/current-system/sw/bin/darwin-rebuild switch --flake .#$FLAKE --switch-generation $GEN_NUM 23 | 24 | echo "${GREEN}Rollback to generation $GEN_NUM complete!${NC}" 25 | -------------------------------------------------------------------------------- /apps/aarch64-linux: -------------------------------------------------------------------------------- 1 | x86_64-linux -------------------------------------------------------------------------------- /apps/x86_64-darwin/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="x86_64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Cleaning up...${NC}" 17 | unlink ./result 18 | 19 | echo "${GREEN}Switch to new generation complete!${NC}" 20 | -------------------------------------------------------------------------------- /apps/x86_64-darwin/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="x86_64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Switching to new generation...${NC}" 17 | 18 | # See https://github.com/nix-darwin/nix-darwin/issues/1457 on why we need sudo 19 | sudo ./result/sw/bin/darwin-rebuild switch --flake .#${SYSTEM_TYPE} $@ 20 | 21 | echo "${YELLOW}Cleaning up...${NC}" 22 | unlink ./result 23 | 24 | echo "${GREEN}Switch to new generation complete!${NC}" 25 | -------------------------------------------------------------------------------- /apps/x86_64-darwin/check-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | lint_keys() { 12 | if [[ -f "${SSH_DIR}/id_ed25519" && -f "${SSH_DIR}/id_ed25519.pub" && -f "${SSH_DIR}/id_ed25519_agenix" && -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 13 | echo -e "${GREEN}All SSH keys are present.${NC}" 14 | else 15 | echo -e "${RED}Some SSH keys are missing.${NC}" 16 | if [[ ! -f "${SSH_DIR}/id_ed25519" ]]; then 17 | echo -e "${RED}Missing: id_ed25519${NC}" 18 | fi 19 | if [[ ! -f "${SSH_DIR}/id_ed25519.pub" ]]; then 20 | echo -e "${RED}Missing: id_ed25519.pub${NC}" 21 | fi 22 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix" ]]; then 23 | echo -e "${RED}Missing: id_ed25519_agenix${NC}" 24 | fi 25 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 26 | echo -e "${RED}Missing: id_ed25519_agenix.pub${NC}" 27 | fi 28 | echo -e "${GREEN}Run the createKeys command to generate the missing keys.${NC}" 29 | exit 1 30 | fi 31 | } 32 | 33 | lint_keys 34 | -------------------------------------------------------------------------------- /apps/x86_64-darwin/copy-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | handle_no_usb() { 12 | echo -e ${RED}No USB drive found or mounted.${NC}" 13 | echo -e ${GREEN}If you have not yet set up your keys, run the script to generate new SSH keys.${NC}" 14 | exit 1 15 | } 16 | 17 | mount_usb() { 18 | MOUNT_PATH="" 19 | for dev in $(diskutil list | grep -o 'disk[0-9]'); do 20 | MOUNT_PATH="$(diskutil info /dev/${dev} | grep \"Mount Point\" | awk -F: '{print $2}' | xargs)" 21 | if [ -n "${MOUNT_PATH}" ]; then 22 | echo -e "${GREEN}USB drive found at ${MOUNT_PATH}.${NC}" 23 | break 24 | fi 25 | done 26 | 27 | if [ -z "${MOUNT_PATH}" ]; then 28 | echo -e "${RED}No USB drive found.${NC}" 29 | fi 30 | } 31 | 32 | copy_keys() { 33 | if [ -n "${MOUNT_PATH}" ]; then 34 | cp "${MOUNT_PATH}/id_ed25519_agenix.pub" ${SSH_DIR} 35 | cp "${MOUNT_PATH}/id_ed25519_agenix" ${SSH_DIR} 36 | chmod 600 ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 37 | else 38 | echo -e "${RED}No USB drive found. Aborting.${NC}" 39 | exit 1 40 | fi 41 | } 42 | 43 | setup_ssh_directory() { 44 | mkdir -p ${SSH_DIR} 45 | } 46 | 47 | set_keys() { 48 | cp ${MOUNT_PATH}/id_ed25519_github.pub ${SSH_DIR}/id_ed25519.pub 49 | cp ${MOUNT_PATH}/id_ed25519_github ${SSH_DIR}/id_ed25519 50 | chmod 600 ${SSH_DIR}/id_ed25519 51 | chmod 644 ${SSH_DIR}/id_ed25519.pub 52 | } 53 | 54 | change_ownership() { 55 | chown ${username}:staff ${SSH_DIR}/id_ed25519{,.pub} 56 | chown ${username}:staff ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 57 | } 58 | 59 | setup_ssh_directory 60 | mount_usb 61 | 62 | if [ -z "${MOUNT_PATH}" ]; then 63 | handle_no_usb 64 | else 65 | copy_keys 66 | set_keys 67 | change_ownership 68 | fi 69 | -------------------------------------------------------------------------------- /apps/x86_64-darwin/create-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | setup_ssh_directory() { 12 | mkdir -p ${SSH_DIR} 13 | } 14 | 15 | prompt_for_key_generation() { 16 | local key_name=$1 17 | if [[ -f "${SSH_DIR}/${key_name}" ]]; then 18 | echo -e "${RED}Existing SSH key found for ${key_name}.${NC}" 19 | cat "${SSH_DIR}/${key_name}.pub" 20 | read -p "Do you want to replace it? (y/n) " -n 1 -r 21 | echo 22 | if [[ $REPLY =~ ^[Yy]$ ]]; then 23 | return 0 # Indicate key should be replaced 24 | else 25 | return 1 # Indicate key should be kept 26 | fi 27 | fi 28 | return 0 # Indicate no key exists, so it should be created 29 | } 30 | 31 | generate_key() { 32 | local key_name=$1 33 | if prompt_for_key_generation "$key_name"; then 34 | ssh-keygen -t ed25519 -f "${SSH_DIR}/${key_name}" -N "" 35 | chown ${username}:staff "${SSH_DIR}/${key_name}"{,.pub} 36 | else 37 | echo -e "${GREEN}Kept existing ${key_name}.${NC}" 38 | fi 39 | } 40 | 41 | setup_ssh_directory 42 | generate_key "id_ed25519" 43 | generate_key "id_ed25519_agenix" 44 | 45 | echo -e "${GREEN}SSH key setup complete.${NC}" 46 | echo -e "${GREEN}Remember to add the necessary keys to Github or other services as required.${NC}" 47 | -------------------------------------------------------------------------------- /apps/x86_64-linux/apply: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RED='\033[0;31m' 4 | GREEN='\033[0;32m' 5 | YELLOW='\033[1;33m' 6 | NC='\033[0m' # No Color 7 | 8 | # Determine the operating system 9 | export OS=$(uname) 10 | 11 | # Primary network interface 12 | if [[ "$OS" != "Darwin" ]]; then 13 | export PRIMARY_IFACE=$(ip -o -4 route show to default | awk '{print $5}') 14 | echo -e "${GREEN}Found primary network interface $PRIMARY_IFACE${NC}" 15 | fi 16 | 17 | # Custom print function 18 | _print() { 19 | if [[ "$OS" == "Darwin" ]]; then 20 | echo -e "$1" 21 | else 22 | echo "$1" 23 | fi 24 | } 25 | 26 | # Custom prompt function 27 | _prompt() { 28 | local message="$1" 29 | local variable="$2" 30 | 31 | _print "$message" 32 | read -r $variable 33 | } 34 | 35 | ask_for_star() { 36 | _print "${YELLOW}Would you like to support my work by starring my GitHub repo? yes/no [yes]: ${NC}" 37 | local response 38 | read -r response 39 | response=${response:-yes} # Set default response to 'yes' if input is empty 40 | if [[ "$response" =~ ^[Yy](es)?$ ]] || [[ -z "$response" ]]; then 41 | if [[ "$OS" == "Darwin" ]]; then 42 | open "https://github.com/dustinlyons/nixos-config" 43 | else 44 | xdg-open "https://github.com/dustinlyons/nixos-config" 45 | fi 46 | fi 47 | } 48 | 49 | ask_for_star 50 | 51 | # Fetch username from the system 52 | export USERNAME=$(whoami) 53 | 54 | # If the username is 'nixos' or 'root', ask the user for their username 55 | if [[ "$USERNAME" == "nixos" ]] || [[ "$USERNAME" == "root" ]]; then 56 | _prompt "${YELLOW}You're running as $USERNAME. Please enter your desired username: ${NC}" USERNAME 57 | fi 58 | 59 | # Check if git is available 60 | if command -v git >/dev/null 2>&1; then 61 | # Fetch email and name from git config 62 | export GIT_EMAIL=$(git config --get user.email) 63 | export GIT_NAME=$(git config --get user.name) 64 | else 65 | _print "${RED}Git is not available on this system.${NC}" 66 | fi 67 | 68 | # If git email is not found or git is not available, ask the user 69 | if [[ -z "$GIT_EMAIL" ]]; then 70 | _prompt "${YELLOW}Please enter your email: ${NC}" GIT_EMAIL 71 | fi 72 | 73 | # If git name is not found or git is not available, ask the user 74 | if [[ -z "$GIT_NAME" ]]; then 75 | _prompt "${YELLOW}Please enter your name: ${NC}" GIT_NAME 76 | fi 77 | 78 | select_boot_disk() { 79 | local disks 80 | local _boot_disk 81 | 82 | _print "${YELLOW}Available disks:${NC}" 83 | disks=$(lsblk -nd --output NAME,SIZE | grep -v loop) 84 | echo "$disks" 85 | 86 | # Warning message for data deletion 87 | _print "${RED}WARNING: All data on the chosen disk will be erased during the installation!${NC}" 88 | _prompt "${YELLOW}Please enter the name of your boot disk (e.g., sda, nvme0n1). Do not include the full path ("/dev/"): ${NC}" _boot_disk 89 | 90 | # Confirmation for disk selection to prevent accidental data loss 91 | _print "${YELLOW}You have selected $_boot_disk as the boot disk. This will delete everything on this disk. Are you sure? (Y/N): ${NC}" 92 | read -r confirmation 93 | if [[ "$confirmation" =~ ^[Yy]$ ]]; then 94 | export BOOT_DISK=$_boot_disk 95 | else 96 | _print "${RED}Disk selection cancelled by the user. Please run the script again to select the correct disk.${NC}" 97 | exit 1 98 | fi 99 | } 100 | 101 | # Set hostname and find primary disk if this is NixOS 102 | if [[ "$OS" != "Darwin" ]]; then 103 | _prompt "${YELLOW}Please enter a hostname for the system: ${NC}" HOST_NAME 104 | export HOST_NAME 105 | select_boot_disk 106 | fi 107 | 108 | # Confirmation step 109 | confirm_details() { 110 | _print "${GREEN}Username: $USERNAME" 111 | _print "Email: $GIT_EMAIL" 112 | _print "Name: $GIT_NAME${NC}" 113 | 114 | if([[ "$OS" != "Darwin" ]]); then 115 | _print "${GREEN}Primary interface: $PRIMARY_IFACE" 116 | _print "Boot disk: $BOOT_DISK" 117 | _print "Hostname: $HOST_NAME${NC}" 118 | fi 119 | 120 | _prompt "${YELLOW}Is this correct? yes/no: ${NC}" choice 121 | 122 | case "$choice" in 123 | [Nn] | [Nn][Oo] ) _print "${RED}Exiting script.${NC}" && exit 1;; 124 | [Yy] | [Yy][Ee][Ss] ) _print "${GREEN}Continuing...${NC}";; 125 | * ) _print "${RED}Invalid option. Exiting script.${NC}" && exit 1;; 126 | esac 127 | } 128 | 129 | # Call the confirmation function 130 | confirm_details 131 | 132 | # Function to replace tokens in each file 133 | replace_tokens() { 134 | local file="$1" 135 | if [[ $(basename $1) != "apply" ]]; then 136 | if [[ "$OS" == "Darwin" ]]; then 137 | # macOS 138 | LC_ALL=C LANG=C sed -i '' -e "s/%USER%/$USERNAME/g" "$file" 139 | LC_ALL=C LANG=C sed -i '' -e "s/%EMAIL%/$GIT_EMAIL/g" "$file" 140 | LC_ALL=C LANG=C sed -i '' -e "s/%NAME%/$GIT_NAME/g" "$file" 141 | else 142 | # Linux or other 143 | sed -i -e "s/%USER%/$USERNAME/g" "$file" 144 | sed -i -e "s/%EMAIL%/$GIT_EMAIL/g" "$file" 145 | sed -i -e "s/%NAME%/$GIT_NAME/g" "$file" 146 | sed -i -e "s/%INTERFACE%/$PRIMARY_IFACE/g" "$file" 147 | sed -i -e "s/%DISK%/$BOOT_DISK/g" "$file" 148 | sed -i -e "s/%HOST%/$HOST_NAME/g" "$file" 149 | fi 150 | fi 151 | } 152 | 153 | # Traverse directories and call replace_tokens on each Nix file 154 | export -f replace_tokens 155 | find . -type f -exec bash -c 'replace_tokens "$0"' {} \; 156 | 157 | echo "$USERNAME" > /tmp/username.txt 158 | _print "${GREEN}User $USERNAME information applied.${NC}" 159 | -------------------------------------------------------------------------------- /apps/x86_64-linux/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | RED='\033[1;31m' 4 | GREEN='\033[1;32m' 5 | YELLOW='\033[1;33m' 6 | NC='\033[0m' 7 | 8 | SYSTEM=$(uname -m) 9 | 10 | case "$SYSTEM" in 11 | x86_64) 12 | FLAKE_TARGET="x86_64-linux" 13 | ;; 14 | aarch64) 15 | FLAKE_TARGET="aarch64-linux" 16 | ;; 17 | *) 18 | echo -e "${RED}Unsupported architecture: $SYSTEM${NC}" 19 | exit 1 20 | ;; 21 | esac 22 | 23 | echo -e "${YELLOW}Starting...${NC}" 24 | 25 | # We pass SSH from user to root so root can download secrets from our private Github 26 | sudo SSH_AUTH_SOCK=$SSH_AUTH_SOCK /run/current-system/sw/bin/nixos-rebuild switch --flake .#$FLAKE_TARGET $@ 27 | 28 | echo -e "${GREEN}Switch to new generation complete!${NC}" 29 | -------------------------------------------------------------------------------- /apps/x86_64-linux/check-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | # We're assuming this is being run as root in the NixOS installer 9 | export SSH_DIR=/root/.ssh 10 | 11 | check_keys() { 12 | if [[ -f "${SSH_DIR}/id_ed25519" && -f "${SSH_DIR}/id_ed25519.pub" && -f "${SSH_DIR}/id_ed25519_agenix" && -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 13 | echo -e "${GREEN}All SSH keys are present.${NC}" 14 | else 15 | echo -e "${RED}Some SSH keys are missing.${NC}" 16 | if [[ ! -f "${SSH_DIR}/id_ed25519" ]]; then 17 | echo -e "${RED}Missing: id_ed25519${NC}" 18 | fi 19 | if [[ ! -f "${SSH_DIR}/id_ed25519.pub" ]]; then 20 | echo -e "${RED}Missing: id_ed25519.pub${NC}" 21 | fi 22 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix" ]]; then 23 | echo -e "${RED}Missing: id_ed25519_agenix${NC}" 24 | fi 25 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 26 | echo -e "${RED}Missing: id_ed25519_agenix.pub${NC}" 27 | fi 28 | echo -e "${GREEN}Run the createKeys script to generate the missing keys.${NC}" 29 | exit 1 30 | fi 31 | } 32 | 33 | check_keys 34 | -------------------------------------------------------------------------------- /apps/x86_64-linux/copy-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | unmount_usb() { 5 | if mountpoint -q /mnt/usb; then 6 | sudo umount /mnt/usb 7 | echo -e "\e[0;32mUSB drive unmounted.\e[0m" 8 | fi 9 | } 10 | 11 | mount_usb() { 12 | if mountpoint -q /mnt/usb; then 13 | echo -e "\e[0;32mUSB drive already mounted.\e[0m" 14 | else 15 | device_found=false 16 | for dev in sda sdb sdc sdd sde sdf sdg sdh sdi sdj sdk sdl; do 17 | if sudo blkid /dev/$dev | grep -iq 'TYPE="vfat"'; then 18 | device_found=true 19 | mkdir -p /mnt/usb 20 | sudo mount /dev/$dev /mnt/usb && { echo -e "\e[0;32mUSB drive mounted successfully on /dev/$dev.\e[0m"; break; } || echo -e "\e[0;31mFailed to mount /dev/$dev.\e[0m" 21 | fi 22 | done 23 | if [ "$device_found" = false ]; then 24 | echo -e "\e[0;31mNo USB devices found.\e[0m" 25 | fi 26 | fi 27 | } 28 | 29 | setup_ssh_directory() { 30 | export SSH_DIR=/root/.ssh 31 | mkdir -p $SSH_DIR 32 | } 33 | 34 | check_file_exists() { 35 | if [[ ! -f $1 ]]; then 36 | echo -e "\e[0;31mError: File $1 does not exist.\e[0m" 37 | exit 1 38 | fi 39 | } 40 | 41 | copy_keys() { 42 | check_file_exists "/mnt/usb/id_ed25519_agenix.pub" 43 | check_file_exists "/mnt/usb/id_ed25519_agenix" 44 | cp /mnt/usb/id_ed25519_agenix.pub $SSH_DIR 45 | cp /mnt/usb/id_ed25519_agenix $SSH_DIR 46 | chmod 600 $SSH_DIR/id_ed25519_{agenix,agenix.pub} 47 | echo -e "\e[0;32mKeys copied successfully.\e[0m" 48 | } 49 | 50 | set_keys() { 51 | check_file_exists "/mnt/usb/id_ed25519_github.pub" 52 | check_file_exists "/mnt/usb/id_ed25519_github" 53 | cp /mnt/usb/id_ed25519_github.pub $SSH_DIR/id_ed25519.pub 54 | cp /mnt/usb/id_ed25519_github $SSH_DIR/id_ed25519 55 | chmod 600 $SSH_DIR/id_ed25519 56 | chmod 644 $SSH_DIR/id_ed25519.pub 57 | } 58 | 59 | change_ownership() { 60 | chown nixos:wheel $SSH_DIR/id_ed25519{,.pub} 61 | chown nixos:wheel $SSH_DIR/id_ed25519_{agenix,agenix.pub} 62 | } 63 | 64 | trap unmount_usb EXIT 65 | 66 | setup_ssh_directory 67 | mount_usb 68 | copy_keys 69 | set_keys 70 | change_ownership 71 | unmount_usb 72 | -------------------------------------------------------------------------------- /apps/x86_64-linux/create-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | # We're assuming this is being run as root in the NixOS installer 9 | export SSH_DIR=/root/.ssh 10 | 11 | setup_ssh_directory() { 12 | mkdir -p ${SSH_DIR} 13 | } 14 | 15 | generate_keys() { 16 | ssh-keygen -t ed25519 -f "${SSH_DIR}/id_ed25519" -N "" 17 | ssh-keygen -t ed25519 -f "${SSH_DIR}/id_ed25519_agenix" -N "" 18 | chmod 600 ${SSH_DIR}/id_ed25519{,_agenix}{,.pub} 19 | } 20 | 21 | setup_ssh_directory 22 | generate_keys 23 | 24 | echo -e "${GREEN}New SSH keys have been generated.${NC}" 25 | echo -e "${GREEN}1) Add the id_ed25519 key to Github.${NC}" 26 | cat "${SSH_DIR}/id_ed25519.pub" 27 | echo -e "${GREEN}2) Create a private nix-secrets repo in Github, even if it's empty.${NC}" 28 | -------------------------------------------------------------------------------- /apps/x86_64-linux/install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exu 3 | 4 | check_installer() { 5 | if [ -e /etc/NIXOS ]; then 6 | echo -e "\e[1;32mRunning in the NixOS installer environment.\e[0m" 7 | else 8 | echo -e "\e[1;31mNot running in the NixOS installer environment.\e[0m" 9 | exit 1 10 | fi 11 | } 12 | 13 | cleanup() { 14 | rm -rf nixos-config-main.zip nixos-config-main nixos-config 15 | } 16 | 17 | download_config() { 18 | curl -LJ0 https://github.com/dustinlyons/nixos-config/archive/main.zip -o nixos-config-main.zip 19 | unzip nixos-config-main.zip 20 | mv nixos-config-main/templates/starter nixos-config 21 | cd nixos-config 22 | } 23 | 24 | run_apply() { 25 | ./apps/x86_64-linux/apply 26 | if [ ! -f /tmp/username.txt ]; then 27 | echo -e "\e[1;31mError: /tmp/username.txt does not exist.\e[0m" 28 | exit 1 29 | fi 30 | export USERNAME=$(cat /tmp/username.txt) 31 | } 32 | 33 | run_disko() { 34 | sudo nix run --extra-experimental-features nix-command --extra-experimental-features flakes \ 35 | github:nix-community/disko -- --mode zap_create_mount ./modules/nixos/disk-config.nix 36 | } 37 | 38 | setup_files() { 39 | sudo mkdir -p /mnt/etc/nixos 40 | sudo cp -r * /mnt/etc/nixos 41 | cd /mnt/etc/nixos 42 | } 43 | 44 | install_nixos() { 45 | ARCH=$(uname -m) 46 | 47 | case "$ARCH" in 48 | x86_64) 49 | FLAKE_TARGET="x86_64-linux" 50 | ;; 51 | aarch64) 52 | FLAKE_TARGET="aarch64-linux" 53 | ;; 54 | *) 55 | echo -e "${RED}Unsupported architecture: $ARCH${CLEAR}" 56 | exit 1 57 | ;; 58 | esac 59 | 60 | sudo nixos-install --flake .#$FLAKE_TARGET $@ 61 | sudo chmod -R 775 /mnt/etc/nixos 62 | } 63 | 64 | prompt_reboot() { 65 | read -p "Do you want to reboot now? (y/yes) " choice 66 | case "$choice" in 67 | y|Y|yes|YES ) echo -e "\e[1;32mRebooting...\e[0m" && sudo reboot;; 68 | * ) echo -e "\e[1;33mReboot skipped.\e[0m";; 69 | esac 70 | } 71 | 72 | cleanup 73 | check_installer 74 | download_config 75 | run_apply 76 | run_disko 77 | setup_files 78 | install_nixos 79 | cleanup 80 | prompt_reboot 81 | -------------------------------------------------------------------------------- /apps/x86_64-linux/install-with-secrets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exu 3 | 4 | check_installer() { 5 | if [ -e /etc/NIXOS ]; then 6 | echo -e "\e[1;32mRunning in the NixOS installer environment.\e[0m" 7 | else 8 | echo -e "\e[1;31mNot running in the NixOS installer environment.\e[0m" 9 | exit 1 10 | fi 11 | } 12 | 13 | cleanup() { 14 | rm -rf nixos-config-main.zip nixos-config-main nixos-config 15 | } 16 | 17 | download_config() { 18 | curl -LJ0 https://github.com/dustinlyons/nixos-config/archive/main.zip -o nixos-config-main.zip 19 | unzip nixos-config-main.zip 20 | mv nixos-config-main/templates/starter-with-secrets nixos-config 21 | cd nixos-config 22 | } 23 | 24 | run_apply() { 25 | ./apps/x86_64-linux/apply 26 | if [ ! -f /tmp/username.txt ]; then 27 | echo -e "\e[1;31mError: /tmp/username.txt does not exist.\e[0m" 28 | exit 1 29 | fi 30 | export USERNAME=$(cat /tmp/username.txt) 31 | } 32 | 33 | run_disko() { 34 | sudo nix run --extra-experimental-features nix-command --extra-experimental-features flakes \ 35 | github:nix-community/disko -- --mode zap_create_mount ./modules/nixos/disk-config.nix 36 | } 37 | 38 | setup_files() { 39 | sudo mkdir -p /mnt/etc/nixos 40 | sudo cp -r * /mnt/etc/nixos 41 | cd /mnt/etc/nixos 42 | 43 | mkdir -p /root/.ssh 44 | touch /root/.ssh/known_hosts 45 | ssh-keyscan -t ed25519 github.com >> /root/.ssh/known_hosts 46 | } 47 | 48 | setup_ssh_keys() { 49 | mkdir -p /mnt/home/${USERNAME}/.ssh 50 | chown nixos /mnt/home/${USERNAME}/.ssh 51 | 52 | chown nixos /root/.ssh/id_ed25519_agenix{,.pub} 53 | cp --preserve=all /root/.ssh/id_ed25519_agenix /mnt/home/${USERNAME}/.ssh/id_ed25519 54 | cp --preserve=all /root/.ssh/id_ed25519_agenix.pub /mnt/home/${USERNAME}/.ssh/id_ed25519.pub 55 | cp --preserve=all /root/.ssh/id_ed25519 /mnt/home/${USERNAME}/.ssh/id_github 56 | cp --preserve=all /root/.ssh/id_ed25519.pub /mnt/home/${USERNAME}/.ssh/id_github.pub 57 | 58 | chmod 600 /mnt/home/${USERNAME}/.ssh/id_ed25519{,.pub} 59 | chmod 600 /mnt/home/${USERNAME}/.ssh/id_github{,.pub} 60 | } 61 | 62 | link_home_dir() { 63 | ln -s /mnt/home/${USERNAME} /home/${USERNAME} # Used to grab initial secrets 64 | } 65 | 66 | install_nixos() { 67 | ARCH=$(uname -m) 68 | 69 | case "$ARCH" in 70 | x86_64) 71 | FLAKE_TARGET="x86_64-linux" 72 | ;; 73 | aarch64) 74 | FLAKE_TARGET="aarch64-linux" 75 | ;; 76 | *) 77 | echo -e "${RED}Unsupported architecture: $ARCH${CLEAR}" 78 | exit 1 79 | ;; 80 | esac 81 | 82 | sudo nixos-install --flake .#$FLAKE_TARGET $@ 83 | sudo chmod -R 775 /mnt/etc/nixos 84 | } 85 | 86 | prompt_reboot() { 87 | read -p "Do you want to reboot now? (y/yes) " choice 88 | case "$choice" in 89 | y|Y|yes|YES ) echo -e "\e[1;32mRebooting...\e[0m" && sudo reboot;; 90 | * ) echo -e "\e[1;33mReboot skipped.\e[0m";; 91 | esac 92 | } 93 | 94 | cleanup 95 | check_installer 96 | download_config 97 | run_apply 98 | run_disko 99 | setup_files 100 | setup_ssh_keys 101 | link_home_dir 102 | install_nixos 103 | cleanup 104 | prompt_reboot 105 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "General Purpose Configuration for macOS and NixOS"; 3 | inputs = { 4 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 5 | agenix.url = "github:ryantm/agenix"; 6 | home-manager.url = "github:nix-community/home-manager"; 7 | darwin = { 8 | url = "github:LnL7/nix-darwin/master"; 9 | inputs.nixpkgs.follows = "nixpkgs"; 10 | }; 11 | nix-homebrew = { 12 | url = "github:zhaofengli-wip/nix-homebrew"; 13 | }; 14 | homebrew-bundle = { 15 | url = "github:homebrew/homebrew-bundle"; 16 | flake = false; 17 | }; 18 | homebrew-core = { 19 | url = "github:homebrew/homebrew-core"; 20 | flake = false; 21 | }; 22 | homebrew-cask = { 23 | url = "github:homebrew/homebrew-cask"; 24 | flake = false; 25 | }; 26 | disko = { 27 | url = "github:nix-community/disko"; 28 | inputs.nixpkgs.follows = "nixpkgs"; 29 | }; 30 | secrets = { 31 | url = "git+ssh://git@github.com/dustinlyons/nix-secrets.git"; 32 | flake = false; 33 | }; 34 | }; 35 | outputs = { self, darwin, nix-homebrew, homebrew-bundle, homebrew-core, homebrew-cask, home-manager, nixpkgs, disko, agenix, secrets } @inputs: 36 | let 37 | user = "dustin"; 38 | linuxSystems = [ "x86_64-linux" "aarch64-linux" ]; 39 | darwinSystems = [ "aarch64-darwin" "x86_64-darwin" ]; 40 | forAllSystems = f: nixpkgs.lib.genAttrs (linuxSystems ++ darwinSystems) f; 41 | devShell = system: let pkgs = nixpkgs.legacyPackages.${system}; in { 42 | default = with pkgs; mkShell { 43 | nativeBuildInputs = with pkgs; [ bashInteractive git age age-plugin-yubikey ]; 44 | shellHook = with pkgs; '' 45 | export EDITOR=vim 46 | ''; 47 | }; 48 | }; 49 | mkApp = scriptName: system: { 50 | type = "app"; 51 | program = "${(nixpkgs.legacyPackages.${system}.writeScriptBin scriptName '' 52 | #!/usr/bin/env bash 53 | PATH=${nixpkgs.legacyPackages.${system}.git}/bin:$PATH 54 | echo "Running ${scriptName} for ${system}" 55 | exec ${self}/apps/${system}/${scriptName} 56 | '')}/bin/${scriptName}"; 57 | }; 58 | mkLinuxApps = system: { 59 | "apply" = mkApp "apply" system; 60 | "build-switch" = mkApp "build-switch" system; 61 | "copy-keys" = mkApp "copy-keys" system; 62 | "create-keys" = mkApp "create-keys" system; 63 | "check-keys" = mkApp "check-keys" system; 64 | "install" = mkApp "install" system; 65 | "install-with-secrets" = mkApp "install-with-secrets" system; 66 | }; 67 | mkDarwinApps = system: { 68 | "apply" = mkApp "apply" system; 69 | "build" = mkApp "build" system; 70 | "build-switch" = mkApp "build-switch" system; 71 | "copy-keys" = mkApp "copy-keys" system; 72 | "create-keys" = mkApp "create-keys" system; 73 | "check-keys" = mkApp "check-keys" system; 74 | "rollback" = mkApp "rollback" system; 75 | }; 76 | in 77 | { 78 | templates = { 79 | starter = { 80 | path = ./templates/starter; 81 | description = "Starter configuration"; 82 | }; 83 | starter-with-secrets = { 84 | path = ./templates/starter-with-secrets; 85 | description = "Starter configuration with secrets"; 86 | }; 87 | }; 88 | devShells = forAllSystems devShell; 89 | apps = nixpkgs.lib.genAttrs linuxSystems mkLinuxApps // nixpkgs.lib.genAttrs darwinSystems mkDarwinApps; 90 | darwinConfigurations = nixpkgs.lib.genAttrs darwinSystems (system: 91 | darwin.lib.darwinSystem { 92 | inherit system; 93 | specialArgs = inputs; 94 | modules = [ 95 | home-manager.darwinModules.home-manager 96 | nix-homebrew.darwinModules.nix-homebrew 97 | { 98 | nix-homebrew = { 99 | inherit user; 100 | enable = true; 101 | taps = { 102 | "homebrew/homebrew-core" = homebrew-core; 103 | "homebrew/homebrew-cask" = homebrew-cask; 104 | "homebrew/homebrew-bundle" = homebrew-bundle; 105 | }; 106 | mutableTaps = false; 107 | autoMigrate = true; 108 | }; 109 | } 110 | ./hosts/darwin 111 | ]; 112 | } 113 | ); 114 | nixosConfigurations = { 115 | # Main NixOS configuration 116 | nixos = nixpkgs.lib.nixosSystem { 117 | system = "x86_64-linux"; 118 | specialArgs = inputs // { inherit user; }; 119 | modules = [ 120 | # Temporarily disable home-manager to isolate issues 121 | home-manager.nixosModules.home-manager 122 | { 123 | home-manager = { 124 | useGlobalPkgs = true; 125 | useUserPackages = true; 126 | users.${user} = import ./modules/shared/home-manager.nix; 127 | }; 128 | } 129 | ./hosts/nixos 130 | ]; 131 | }; 132 | 133 | # Alternative: generate for all systems (if you want both) 134 | # Uncomment the line below if you want to support multiple architectures 135 | # } // nixpkgs.lib.genAttrs linuxSystems (system: 136 | # nixpkgs.lib.nixosSystem { 137 | # inherit system; 138 | # specialArgs = inputs // { inherit user; }; 139 | # modules = [ 140 | # disko.nixosModules.disko 141 | # ./hosts/nixos 142 | # ]; 143 | # } 144 | # ); 145 | }; 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /hosts/darwin/default.nix: -------------------------------------------------------------------------------- 1 | { agenix, config, pkgs, ... }: 2 | let user = "dustin"; in 3 | { 4 | imports = [ 5 | ../../modules/darwin/secrets.nix 6 | ../../modules/darwin/home-manager.nix 7 | ../../modules/shared 8 | agenix.darwinModules.default 9 | ]; 10 | # Setup user, packages, programs 11 | nix = { 12 | package = pkgs.nix; 13 | settings = { 14 | trusted-users = [ "@admin" "${user}" ]; 15 | substituters = [ "https://nix-community.cachix.org" "https://cache.nixos.org" ]; 16 | trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ]; 17 | }; 18 | gc = { 19 | automatic = true; 20 | interval = { Weekday = 0; Hour = 2; Minute = 0; }; 21 | options = "--delete-older-than 30d"; 22 | }; 23 | # Turn this on to make command line easier 24 | extraOptions = '' 25 | experimental-features = nix-command flakes 26 | ''; 27 | }; 28 | # Load configuration that is shared across systems 29 | environment.systemPackages = with pkgs; [ 30 | emacs 31 | agenix.packages."${pkgs.system}".default 32 | ] ++ (import ../../modules/shared/packages.nix { inherit pkgs; }); 33 | 34 | #launchd.user.agents = { 35 | # emacs = { 36 | # path = [ config.environment.systemPath ]; 37 | # serviceConfig = { 38 | # KeepAlive = true; 39 | # ProgramArguments = [ 40 | # "/bin/sh" 41 | # "-c" 42 | # "{ osascript -e 'display notification \"Attempting to start Emacs...\" with title \"Emacs Launch\"'; /bin/wait4path ${pkgs.emacs}/bin/emacs && { ${pkgs.emacs}/bin/emacs --fg-daemon; if [ $? -eq 0 ]; then osascript -e 'display notification \"Emacs has started.\" with title \"Emacs Launch\"'; else osascript -e 'display notification \"Failed to start Emacs.\" with title \"Emacs Launch\"' >&2; fi; } } &> /tmp/emacs_launch.log" 43 | # ]; 44 | # StandardErrorPath = "/tmp/emacs.err.log"; 45 | # StandardOutPath = "/tmp/emacs.out.log"; 46 | # }; 47 | # }; 48 | #}; 49 | 50 | system = { 51 | # Turn off NIX_PATH warnings now that we're using flakes 52 | checks.verifyNixPath = false; 53 | primaryUser = user; 54 | stateVersion = 4; 55 | defaults = { 56 | LaunchServices = { 57 | LSQuarantine = false; 58 | }; 59 | NSGlobalDomain = { 60 | AppleShowAllExtensions = true; 61 | ApplePressAndHoldEnabled = false; 62 | 63 | # 120, 90, 60, 30, 12, 6, 2 64 | KeyRepeat = 2; 65 | 66 | # 120, 94, 68, 35, 25, 15 67 | InitialKeyRepeat = 15; 68 | "com.apple.mouse.tapBehavior" = 1; 69 | "com.apple.sound.beep.volume" = 0.0; 70 | "com.apple.sound.beep.feedback" = 0; 71 | }; 72 | dock = { 73 | autohide = false; 74 | show-recents = false; 75 | launchanim = true; 76 | mouse-over-hilite-stack = true; 77 | orientation = "bottom"; 78 | tilesize = 48; 79 | }; 80 | finder = { 81 | _FXShowPosixPathInTitle = false; 82 | }; 83 | trackpad = { 84 | Clicking = true; 85 | TrackpadThreeFingerDrag = true; 86 | }; 87 | }; 88 | keyboard = { 89 | enableKeyMapping = true; 90 | remapCapsLockToControl = true; 91 | }; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /modules/darwin/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Layout 3 | ``` 4 | . 5 | ├── dock # MacOS dock configuration 6 | ├── casks.nix # List of homebrew casks 7 | ├── default.nix # Defines module, system-level config 8 | ├── files.nix # Non-Nix, static configuration files (now immutable!) 9 | ├── home-manager.nix # Defines user programs 10 | ├── packages.nix # List of packages to install for MacOS 11 | ├── secrets.nix # Age-encrypted secrets with agenix 12 | ``` 13 | -------------------------------------------------------------------------------- /modules/darwin/casks.nix: -------------------------------------------------------------------------------- 1 | _: 2 | 3 | [ 4 | # Development Tools 5 | "homebrew/cask/docker" 6 | "claude" 7 | "insomnia" 8 | "tableplus" 9 | "ngrok" 10 | "postico" 11 | "visual-studio-code" 12 | "wireshark" 13 | 14 | # Communication Tools 15 | "discord" 16 | "loom" 17 | "slack" 18 | "telegram" 19 | "zoom" 20 | 21 | # Utility Tools 22 | "appcleaner" 23 | "syncthing" 24 | 25 | # Entertainment Tools 26 | "steam" 27 | "vlc" 28 | 29 | # Productivity Tools 30 | "raycast" 31 | "asana" 32 | 33 | # Browsers 34 | "google-chrome" 35 | 36 | # AI 37 | "diffusionbee" 38 | ] 39 | -------------------------------------------------------------------------------- /modules/darwin/dock/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | # Original source: https://gist.github.com/antifuchs/10138c4d838a63c0a05e725ccd7bccdd 3 | 4 | with lib; 5 | let 6 | cfg = config.local.dock; 7 | inherit (pkgs) stdenv dockutil; 8 | in 9 | { 10 | options = { 11 | local.dock = { 12 | enable = mkOption { 13 | description = "Enable dock"; 14 | default = stdenv.isDarwin; 15 | }; 16 | 17 | entries = mkOption { 18 | description = "Entries on the Dock"; 19 | type = 20 | with types; 21 | listOf (submodule { 22 | options = { 23 | path = lib.mkOption { type = str; }; 24 | section = lib.mkOption { 25 | type = str; 26 | default = "apps"; 27 | }; 28 | options = lib.mkOption { 29 | type = str; 30 | default = ""; 31 | }; 32 | }; 33 | }); 34 | readOnly = true; 35 | }; 36 | 37 | username = mkOption { 38 | description = "Username to apply the dock settings to"; 39 | type = types.str; 40 | }; 41 | }; 42 | }; 43 | 44 | config = mkIf cfg.enable ( 45 | let 46 | normalize = path: if hasSuffix ".app" path then path + "/" else path; 47 | entryURI = 48 | path: 49 | "file://" 50 | + (builtins.replaceStrings 51 | [ " " "!" "\"" "#" "$" "%" "&" "'" "(" ")" ] 52 | [ "%20" "%21" "%22" "%23" "%24" "%25" "%26" "%27" "%28" "%29" ] 53 | (normalize path) 54 | ); 55 | wantURIs = concatMapStrings (entry: "${entryURI entry.path}\n") cfg.entries; 56 | createEntries = 57 | concatMapStrings 58 | (entry: 59 | "${dockutil}/bin/dockutil --no-restart --add '${entry.path}' --section ${entry.section} ${entry.options}\n" 60 | ) 61 | cfg.entries; 62 | in 63 | { 64 | system.activationScripts.postActivation.text = '' 65 | echo >&2 "Setting up the Dock for ${cfg.username}..." 66 | su ${cfg.username} -s /bin/sh <<'USERBLOCK' 67 | haveURIs="$(${dockutil}/bin/dockutil --list | ${pkgs.coreutils}/bin/cut -f2)" 68 | if ! diff -wu <(echo -n "$haveURIs") <(echo -n '${wantURIs}') >&2 ; then 69 | echo >&2 "Resetting Dock." 70 | ${dockutil}/bin/dockutil --no-restart --remove all 71 | ${createEntries} 72 | killall Dock 73 | else 74 | echo >&2 "Dock setup complete." 75 | fi 76 | USERBLOCK 77 | ''; 78 | } 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /modules/darwin/files.nix: -------------------------------------------------------------------------------- 1 | { user, config, pkgs, ... }: 2 | 3 | let 4 | xdg_configHome = "${config.users.users.${user}.home}/.config"; 5 | xdg_dataHome = "${config.users.users.${user}.home}/.local/share"; 6 | xdg_stateHome = "${config.users.users.${user}.home}/.local/state"; in 7 | { 8 | 9 | # Raycast script so that "Run Emacs" is available and uses Emacs daemon 10 | "${xdg_dataHome}/bin/emacsclient" = { 11 | executable = true; 12 | text = '' 13 | #!/bin/zsh 14 | # 15 | # Required parameters: 16 | # @raycast.schemaVersion 1 17 | # @raycast.title Run Emacs 18 | # @raycast.mode silent 19 | # 20 | # Optional parameters: 21 | # @raycast.packageName Emacs 22 | # @raycast.icon ${xdg_dataHome}/img/icons/Emacs.icns 23 | # @raycast.iconDark ${xdg_dataHome}/img/icons/Emacs.icns 24 | 25 | if [[ $1 = "-t" ]]; then 26 | # Terminal mode 27 | ${pkgs.emacs}/bin/emacsclient -t $@ 28 | else 29 | # GUI mode 30 | ${pkgs.emacs}/bin/emacsclient -c -n $@ 31 | fi 32 | ''; 33 | }; 34 | 35 | # Script to import Drafts into Emacs org-roam 36 | "${xdg_dataHome}/bin/import-drafts" = { 37 | executable = true; 38 | text = '' 39 | #!/bin/sh 40 | 41 | for f in ${xdg_stateHome}/drafts/* 42 | do 43 | if [[ ! "$f" =~ "done" ]]; then 44 | echo "Importing $f" 45 | filename="$(head -c 10 $f)" 46 | output="${xdg_dataHome}/org-roam/daily/$filename.org" 47 | echo '\n' >> "$output" 48 | tail -n +3 $f >> "$output" 49 | mv $f done 50 | fi 51 | done 52 | ''; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /modules/darwin/home-manager.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, home-manager, ... }: 2 | 3 | let 4 | user = "dustin"; 5 | myEmacsLauncher = pkgs.writeScript "emacs-launcher.command" '' 6 | #!/bin/sh 7 | emacsclient -c -n & 8 | ''; 9 | sharedFiles = import ../shared/files.nix { inherit config pkgs; }; 10 | additionalFiles = import ./files.nix { inherit user config pkgs; }; 11 | in 12 | { 13 | imports = [ 14 | ./dock 15 | ]; 16 | 17 | users.users.${user} = { 18 | name = "${user}"; 19 | home = "/Users/${user}"; 20 | isHidden = false; 21 | shell = pkgs.zsh; 22 | }; 23 | 24 | homebrew = { 25 | # This is a module from nix-darwin 26 | # Homebrew is *installed* via the flake input nix-homebrew 27 | 28 | # These app IDs are from using the mas CLI app 29 | # mas = mac app store 30 | # https://github.com/mas-cli/mas 31 | # 32 | # $ nix shell nixpkgs#mas 33 | # $ mas search 34 | # 35 | enable = true; 36 | casks = pkgs.callPackage ./casks.nix {}; 37 | masApps = { 38 | "hidden-bar" = 1452453066; 39 | "wireguard" = 1451685025; 40 | }; 41 | }; 42 | 43 | home-manager = { 44 | useGlobalPkgs = true; 45 | users.${user} = { pkgs, config, lib, ... }: 46 | { 47 | home = { 48 | enableNixpkgsReleaseCheck = false; 49 | packages = pkgs.callPackage ./packages.nix {}; 50 | file = lib.mkMerge [ 51 | sharedFiles 52 | additionalFiles 53 | { "emacs-launcher.command".source = myEmacsLauncher; } 54 | ]; 55 | stateVersion = "23.11"; 56 | }; 57 | programs = {} // import ../shared/home-manager.nix { inherit config pkgs lib; }; 58 | manual.manpages.enable = false; 59 | }; 60 | }; 61 | 62 | # Fully declarative dock using the latest from Nix Stor 63 | local.dock = { 64 | enable = true; 65 | username = user; 66 | entries = [ 67 | { path = "/Applications/Slack.app/"; } 68 | { path = "/System/Applications/Messages.app/"; } 69 | { path = "${pkgs.alacritty}/Applications/Alacritty.app/"; } 70 | { path = "/System/Applications/Music.app/"; } 71 | { path = "/System/Applications/Photos.app/"; } 72 | { path = "/System/Applications/Photo Booth.app/"; } 73 | { path = "/System/Applications/TV.app/"; } 74 | { path = "${pkgs.jetbrains.phpstorm}/Applications/PhpStorm.app/"; } 75 | { path = "/Applications/TablePlus.app/"; } 76 | { path = "/Applications/Claude.app/"; } 77 | { path = "/Applications/Discord.app/"; } 78 | { path = "/Applications/TickTick.app/"; } 79 | { path = "/System/Applications/Home.app/"; } 80 | { 81 | path = toString myEmacsLauncher; 82 | section = "others"; 83 | } 84 | { 85 | path = "${config.users.users.${user}.home}/.local/share/"; 86 | section = "others"; 87 | options = "--sort name --view grid --display folder"; 88 | } 89 | { 90 | path = "${config.users.users.${user}.home}/.local/share/downloads"; 91 | section = "others"; 92 | options = "--sort name --view grid --display stack"; 93 | } 94 | ]; 95 | }; 96 | } 97 | -------------------------------------------------------------------------------- /modules/darwin/packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | with pkgs; 4 | let shared-packages = import ../shared/packages.nix { inherit pkgs; }; in 5 | shared-packages ++ [ 6 | fswatch 7 | dockutil 8 | ] 9 | -------------------------------------------------------------------------------- /modules/darwin/secrets.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, agenix, secrets, ... }: 2 | 3 | let user = "dustin"; in 4 | { 5 | age = { 6 | identityPaths = [ 7 | "/Users/${user}/.ssh/id_ed25519" 8 | ]; 9 | 10 | secrets = { 11 | "syncthing-cert" = { 12 | symlink = true; 13 | path = "/Users/${user}/Library/Application Support/Syncthing/cert.pem"; 14 | file = "${secrets}/darwin-syncthing-cert.age"; 15 | mode = "644"; 16 | owner = "${user}"; 17 | group = "staff"; 18 | }; 19 | 20 | "syncthing-key" = { 21 | symlink = true; 22 | path = "/Users/${user}/Library/Application Support/Syncthing/key.pem"; 23 | file = "${secrets}/darwin-syncthing-key.age"; 24 | mode = "600"; 25 | owner = "${user}"; 26 | group = "staff"; 27 | }; 28 | 29 | "github-ssh-key" = { 30 | symlink = true; 31 | path = "/Users/${user}/.ssh/id_github"; 32 | file = "${secrets}/github-ssh-key.age"; 33 | mode = "600"; 34 | owner = "${user}"; 35 | group = "staff"; 36 | }; 37 | 38 | "github-signing-key" = { 39 | symlink = false; 40 | path = "/Users/${user}/.ssh/pgp_github.key"; 41 | file = "${secrets}/github-signing-key.age"; 42 | mode = "600"; 43 | owner = "${user}"; 44 | }; 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /modules/nixos/README.md: -------------------------------------------------------------------------------- 1 | ## Layout 2 | ``` 3 | . 4 | ├── config # Config files not written in Nix 5 | ├── default.nix # Defines module, system-level config, 6 | ├── disk-config.nix # Disks, partitions, and filesystems 7 | ├── files.nix # Non-Nix, static configuration files (now immutable!) 8 | ├── home-manager.nix # Defines user programs 9 | ├── packages.nix # List of packages to install for NixOS 10 | ├── secrets.nix # Age-encrypted secrets with agenix 11 | ``` 12 | -------------------------------------------------------------------------------- /modules/nixos/files.nix: -------------------------------------------------------------------------------- 1 | { user, ... }: 2 | 3 | let 4 | home = builtins.getEnv "HOME"; 5 | xdg_configHome = "${home}/.config"; 6 | xdg_dataHome = "${home}/.local/share"; 7 | xdg_stateHome = "${home}/.local/state"; in 8 | { 9 | 10 | "${xdg_dataHome}/bin/movesinks" = { 11 | executable = true; 12 | text = '' 13 | #!/usr/bin/env bash 14 | pacmd set-default-sink $1 15 | pacmd list-sink-inputs | grep index | while read line 16 | do 17 | pacmd move-sink-input `echo $line | cut -f2 -d' '` $1 18 | done 19 | ''; 20 | }; 21 | 22 | "${xdg_dataHome}/bin/speakers" = { 23 | executable = true; 24 | text = '' 25 | #!/usr/bin/env bash 26 | # Script to change audio format to headphones and check if the sink exists 27 | 28 | # Define the sink name 29 | SINK_NAME="alsa_output.usb-Audioengine_Audioengine_2_-00.analog-stereo" 30 | 31 | # Check if the sink exists 32 | if pactl list short sinks | grep -q "$SINK_NAME"; then 33 | # Sink exists, set it as the default 34 | pacmd set-default-sink "$SINK_NAME" 35 | movesinks "$SINK_NAME" 36 | else 37 | # Sink does not exist, print message 38 | echo "Turn on your speakers, stupid." 39 | fi 40 | ''; 41 | }; 42 | 43 | "${xdg_dataHome}/bin/headphones" = { 44 | executable = true; 45 | text = '' 46 | #!/usr/bin/env bash 47 | # Changes audio format to headphones 48 | pacmd set-default-sink alsa_output.pci-0000_00_1f.3.analog-stereo 49 | movesinks alsa_output.pci-0000_00_1f.3.analog-stereo 50 | ''; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /modules/nixos/home-manager.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | user = "dustin"; 5 | xdg_configHome = "/home/${user}/.config"; 6 | shared-programs = import ../shared/home-manager.nix { inherit config pkgs lib; }; 7 | shared-files = import ../shared/files.nix { inherit config pkgs; }; 8 | 9 | # These files are generated when secrets are decrypted at build time 10 | gpgKeys = [ 11 | "/home/${user}/.ssh/pgp_github.key" 12 | "/home/${user}/.ssh/pgp_github.pub" 13 | ]; 14 | { 15 | home = { 16 | enableNixpkgsReleaseCheck = false; 17 | username = "${user}"; 18 | homeDirectory = "/home/${user}"; 19 | packages = pkgs.callPackage ./packages.nix {}; 20 | file = shared-files // import ./files.nix { inherit user pkgs; }; 21 | stateVersion = "21.05"; 22 | }; 23 | 24 | programs = shared-programs // { gpg.enable = true; }; 25 | 26 | # This installs my GPG signing keys for Github 27 | systemd.user.services.gpg-import-keys = { 28 | Unit = { 29 | Description = "Import gpg keys"; 30 | After = [ "gpg-agent.socket" ]; 31 | }; 32 | 33 | Service = { 34 | Type = "oneshot"; 35 | ExecStart = toString (pkgs.writeScript "gpg-import-keys" '' 36 | #! ${pkgs.runtimeShell} -el 37 | ${lib.optionalString (gpgKeys!= []) '' 38 | ${pkgs.gnupg}/bin/gpg --import ${lib.concatStringsSep " " gpgKeys} 39 | ''} 40 | ''); 41 | }; 42 | 43 | Install = { WantedBy = [ "default.target" ]; }; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /modules/nixos/packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | with pkgs; 4 | let shared-packages = import ../shared/packages.nix { inherit pkgs; }; in 5 | shared-packages ++ [ 6 | 7 | # Security and authentication 8 | _1password-gui 9 | yubikey-agent 10 | keepassxc 11 | 12 | # App and package management 13 | gnumake 14 | cmake 15 | home-manager 16 | 17 | # Media and design tools 18 | gimp 19 | vlc 20 | 21 | # Printers and drivers 22 | brlaser # printer driver 23 | 24 | # Calculators 25 | bc # old school calculator 26 | 27 | # Audio tools 28 | pavucontrol # Pulse audio controls 29 | 30 | # Messaging and chat applications 31 | cider # Apple Music on Linux 32 | discord 33 | 34 | # Testing and development tools 35 | chromedriver 36 | direnv 37 | qmk 38 | 39 | # Screenshot and recording tools 40 | simplescreenrecorder 41 | 42 | # Text and terminal utilities 43 | emote # Emoji picker 44 | screenkey 45 | tree 46 | unixtools.ifconfig 47 | unixtools.netstat 48 | xclip # For the org-download package in Emacs 49 | 50 | # File and system utilities 51 | inotify-tools # inotifywait, inotifywatch - For file system events 52 | libnotify 53 | playerctl # Control media players from command line 54 | 55 | # Other utilities 56 | google-chrome 57 | 58 | # PDF viewer 59 | zathura 60 | ] 61 | -------------------------------------------------------------------------------- /modules/nixos/secrets.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, agenix, secrets, ... }: 2 | 3 | let user = "dustin"; in 4 | { 5 | age = { 6 | identityPaths = [ 7 | "/home/${user}/.ssh/id_ed25519" 8 | ]; 9 | 10 | secrets = { 11 | "syncthing-cert" = { 12 | symlink = true; 13 | path = "/home/${user}/.config/syncthing/cert.pem"; 14 | file = "${secrets}/felix-syncthing-cert.age"; 15 | mode = "600"; 16 | owner = "${user}"; 17 | group = "users"; 18 | }; 19 | 20 | "syncthing-key" = { 21 | symlink = true; 22 | path = "/home/{$user}/.config/syncthing/key.pem"; 23 | file = "${secrets}/felix-syncthing-key.age"; 24 | mode = "600"; 25 | owner = "${user}"; 26 | group = "users"; 27 | }; 28 | 29 | "github-ssh-key" = { 30 | symlink = false; 31 | path = "/home/${user}/.ssh/id_github"; 32 | file = "${secrets}/github-ssh-key.age"; 33 | mode = "600"; 34 | owner = "${user}"; 35 | group = "wheel"; 36 | }; 37 | 38 | "github-signing-key" = { 39 | symlink = false; 40 | path = "/home/${user}/.ssh/pgp_github.key"; 41 | file = "${secrets}/github-signing-key.age"; 42 | mode = "600"; 43 | owner = "${user}"; 44 | group = "wheel"; 45 | }; 46 | }; 47 | }; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /modules/shared/README.md: -------------------------------------------------------------------------------- 1 | ## Shared 2 | Much of the code running on MacOS or NixOS is actually found here. 3 | 4 | This configuration gets imported by both modules. Some configuration examples include `git`, `zsh`, `vim`, and `tmux`. 5 | 6 | ## Layout 7 | ``` 8 | . 9 | ├── config # Config files not written in Nix 10 | ├── cachix # Defines cachix, a global cache for builds 11 | ├── default.nix # Defines how we import overlays 12 | ├── files.nix # Non-Nix, static configuration files (now immutable!) 13 | ├── home-manager.nix # The goods; most all shared config lives here 14 | ├── packages.nix # List of packages to share 15 | 16 | ``` 17 | -------------------------------------------------------------------------------- /modules/shared/cachix/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, ... }: 2 | { 3 | nix.settings = { 4 | substituters = [ 5 | "https://nix-community.cachix.org" 6 | "https://cache.nixos.org/" 7 | ]; 8 | trusted-public-keys = [ 9 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 10 | ]; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/shared/config/emacs/init.el: -------------------------------------------------------------------------------- 1 | ;; ------------------------- 2 | ;; Variable Declarations 3 | ;; ------------------------- 4 | (defvar org-config-file "~/.local/share/src/nixos-config/modules/shared/config/emacs/config.org") 5 | (defvar default-config-file "~/.emacs.d/default-config.org") 6 | (defvar default-config-url "https://raw.githubusercontent.com/dustinlyons/nixos-config/9ad810c818b895c1f67f4daf21bbef31d8b5e8cd/shared/config/emacs/config.org") 7 | 8 | ;; ------------------------- 9 | ;; Package Manager Setup 10 | ;; ------------------------- 11 | (require 'package) 12 | (setq package-archives '(("melpa" . "https://melpa.org/packages/") 13 | ("gnu" . "http://elpa.gnu.org/packages/"))) 14 | 15 | (unless (assoc-default "melpa" package-archives) 16 | (message "Warning: MELPA source not found. Adding MELPA to package-archives.") 17 | (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)) 18 | (unless (assoc-default "org" package-archives) 19 | (message "Warning: Org source not found. Adding Org to package-archives.") 20 | (add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)) 21 | 22 | (setq package-enable-at-startup nil) 23 | 24 | ;; ------------------------- 25 | ;; Use-Package Setup 26 | ;; ------------------------- 27 | (unless (package-installed-p 'use-package) 28 | (package-initialize) 29 | (if (package-install 'use-package) 30 | (message "use-package installed successfully.") 31 | (error "Error: Failed to install use-package.")) 32 | (setq use-package-verbose t) 33 | (setq use-package-always-ensure t) 34 | (require 'use-package)) 35 | 36 | ;; ------------------------- 37 | ;; Environment Variables Setup 38 | ;; ------------------------- 39 | (use-package exec-path-from-shell 40 | :if (memq window-system '(mac ns x)) 41 | :config 42 | (setq exec-path-from-shell-variables '("PATH" "GOPATH" "PNPM_HOME")) 43 | (if (exec-path-from-shell-initialize) 44 | (message "Environment variables initialized successfully.") 45 | (error "Error: Failed to initialize environment variables."))) 46 | 47 | (when (daemonp) 48 | (exec-path-from-shell-initialize)) 49 | 50 | ;; ------------------------- 51 | ;; Straight.el Setup 52 | ;; ------------------------- 53 | (setq straight-repository-branch "develop") 54 | (defvar bootstrap-version) 55 | (let ((bootstrap-file 56 | (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) 57 | (bootstrap-version 6)) 58 | (unless (file-exists-p bootstrap-file) 59 | (with-current-buffer 60 | (url-retrieve-synchronously 61 | "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 62 | 'silent 'inhibit-cookies) 63 | (goto-char (point-max)) 64 | (eval-print-last-sexp))) 65 | (if (load bootstrap-file nil 'nomessage) 66 | (message "Straight.el loaded successfully.") 67 | (error "Error: Failed to load Straight.el."))) 68 | 69 | (setq straight-use-package-by-default t) 70 | (package-initialize) 71 | 72 | ;; ------------------------- 73 | ;; Window and UI Setup 74 | ;; ------------------------- 75 | (defun dl/window-setup () 76 | (condition-case nil 77 | (progn 78 | (column-number-mode) 79 | (scroll-bar-mode 0) 80 | (menu-bar-mode -1) 81 | (tool-bar-mode 0) 82 | (winner-mode 1) 83 | (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) 84 | (add-to-list 'default-frame-alist '(ns-appearance . dark)) 85 | (setq ns-use-proxy-icon nil) 86 | (setq frame-title-format nil) 87 | (message "Window and UI setup completed successfully.")) 88 | (error (message "Error occurred in Window and UI setup.")))) 89 | (dl/window-setup) 90 | 91 | ;; ------------------------- 92 | ;; Org Mode Setup 93 | ;; ------------------------- 94 | (defun dl/org-mode-setup () 95 | (condition-case nil 96 | (progn 97 | (org-indent-mode) 98 | (variable-pitch-mode 1) 99 | (auto-fill-mode 0) 100 | (visual-line-mode 1) 101 | (setq evil-auto-indent nil) 102 | (message "Org mode setup completed successfully.")) 103 | (error (message "Error occurred in Org mode setup.")))) 104 | 105 | (use-package org 106 | :defer t 107 | :hook (org-mode . dl/org-mode-setup) 108 | :config 109 | (setq org-edit-src-content-indentation 2 110 | org-ellipsis " ▾" 111 | org-hide-emphasis-markers t 112 | org-hide-block-startup nil) 113 | :bind (("C-c a" . org-agenda))) 114 | 115 | ;; ------------------------- 116 | ;; Default Config Download 117 | ;; ------------------------- 118 | (defun dl/download-default-config () 119 | (condition-case nil 120 | (progn 121 | (unless (file-exists-p default-config-file) 122 | (url-retrieve default-config-url 123 | (lambda (_status) 124 | ;; delete-region removes the HTTP headers from the downloaded content. 125 | (delete-region (point-min) (1+ url-http-end-of-headers)) 126 | ;; save the contents of the buffer to the file. 127 | (write-file default-config-file))) 128 | (message "Default configuration downloaded successfully."))) 129 | (error (message "Error occurred while downloading the default configuration.")))) 130 | 131 | ;; ------------------------- 132 | ;; Load Org Config or Default 133 | ;; ------------------------- 134 | (condition-case nil 135 | (progn 136 | (unless (file-exists-p org-config-file) 137 | (dl/download-default-config)) 138 | (if (file-exists-p org-config-file) 139 | (org-babel-load-file org-config-file) 140 | (org-babel-load-file default-config-file)) 141 | (message "Configuration loaded successfully.")) 142 | (error (message "Error occurred while loading the configuration."))) 143 | -------------------------------------------------------------------------------- /modules/shared/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let 4 | emacsOverlaySha256 = "06413w510jmld20i4lik9b36cfafm501864yq8k4vxl5r4hn0j0h"; 5 | in 6 | { 7 | 8 | nixpkgs = { 9 | config = { 10 | allowUnfree = true; 11 | #cudaSupport = true; 12 | #cudaCapabilities = ["8.0"]; 13 | allowBroken = true; 14 | allowInsecure = false; 15 | allowUnsupportedSystem = true; 16 | }; 17 | 18 | overlays = 19 | # Apply each overlay found in the /overlays directory 20 | let path = ../../overlays; in with builtins; 21 | map (n: import (path + ("/" + n))) 22 | (filter (n: match ".*\\.nix" n != null || 23 | pathExists (path + ("/" + n + "/default.nix"))) 24 | (attrNames (readDir path))) 25 | 26 | ++ [(import (builtins.fetchTarball { 27 | url = "https://github.com/dustinlyons/emacs-overlay/archive/refs/heads/master.tar.gz"; 28 | sha256 = emacsOverlaySha256; 29 | }))]; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /modules/shared/files.nix: -------------------------------------------------------------------------------- 1 | { pkgs, config, ... }: 2 | 3 | let 4 | githubPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOk8iAnIaa1deoc7jw8YACPNVka1ZFJxhnU4G74TmS+p dustin@Dustins-MBP.localdomain"; 5 | githubPublicSigningKey = '' 6 | -----BEGIN PGP PUBLIC KEY BLOCK----- 7 | 8 | mQGNBGNHB2YBDADNAoEzFeTEn/84dnrZKL+yeOq0m07cMFwQLiiylstJj0OxOJI3 9 | 0frjNsijIOTDhtrrYNr+vkc7Bsf2P4aI+FmkrBfKfY4oA1GBjyb823ran99Fnfy9 10 | r7n8FM7X/6E7BG8cYawcLmFW5A8++h25tqoEoSw9y0ENTC/tP5TSZc7ypUJ2qKs5 11 | nfvnCYs7P2avLtJrElZiwnkjsMADyj6CtGjTOAGi5LypsDX/9oqzAMOJH6eD2829 12 | irhZ9zLg1HLkaFN4FApdmeHhCyM8e3d4yXMYAfjQ52RFFci4cf+cVp2ijgX+FZpp 13 | 7aBz9Fxqfb34kCzPktXh6dROmlFg9Of6jJmcGBxDr7vuo6FciFyQUjSe1BsMIjrb 14 | WC5N4wb/nWGUPaWKtN7BTUNcTGy5xAk4i03xWacamqaLbMiqKN9BHoGT8D7BmqQo 15 | toh1yhoVpuKkwOT66NM7vfCH5N3s0zEsAI8RHHSqNBWincx5yyQoqveeYPn9EOJs 16 | f7MnPR2mgvBuvN8AEQEAAbQgRHVzdGluIEx5b25zIDxkdXN0aW5AZGx5b25zLmRl 17 | dj6JAdEEEwEIADsWIQSRE59mup65UqK9X4TZWq5A0U5jswUCY0cHZgIbAwULCQgH 18 | AgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDZWq5A0U5js1kxDACQZAP6orX+4tWO 19 | dk+9gNtKlq+oDYwFg6ITl8NyurCzlLl3OhhKuCIhCd6FeBhcmCO2WhupKgkjB2ij 20 | HCUMlf4Qs6gLHgU+MvvtwIJYycil0q10FATRv2jH73txk4hCUcSgy4MNT6MsjOgB 21 | innZgFYte08a54SHxmRN5RbXCeddkcDM+kdeMsEu24kczxbNHjkJGV2IpyWYIH5m 22 | Y+VPySt6url4UQZhtF00weV21Nl3yao3+lqv+f/ML0EFJTyri6TzH9E9Owk/iszz 23 | hhFoofPRvvqE4VkvnwUmHidzWa9x3XyuzwBFRTBgE6ZfsDDclRUmhNsxRtjwSW0k 24 | FmjUDmCgWjlGY5iJneJ32n5ccwWc5MBLztHb8u52eg74f84iMr0wSYctaWDb++nl 25 | pB64jEJobZWXJf74zHkIb51TfhSAqGGX6gHxQ/bsZ3iv8zYXWkjTsq4dgtbylWVA 26 | suhaqxTG8/WjCzFLCQebME7x3ChEJFNXM40LMi3pBLPTge0UCUK5AY0EY0cHZgEM 27 | ANqEI67q5MRDcGnX0gKeKgRcqMFlJq0Lpm1YfqjVBiw4PEwQBJ8cW3nZaA+fTZTJ 28 | 1X31ti+0HkcYbnQzsXDAFNo+iaeJ3JDMgIK5+tayCpTFnjec47iniP2wIaPfdaGx 29 | zqMEp9JXAJuwpjT5qIqIyx9Qh6fvteittz2FKycla3mnrAeswyFLM0LsjkUi7g0O 30 | FLcmOiCEmcQQzL9cKLPm2p+tnwudId5FdeQtDXW9wYN+kEu+UMOGFVzrCCtWMoee 31 | NNna9ZPw/5Pjk2RbMSykvGvImcUQeKtheyV/xk8i9NUdTQk6hctK7dGm45QlvroQ 32 | 95cHdEKUdJRgzpN8TG+LWPR8+FUFATlSNFCTPNJiaVY1Jyn74Prfg/V7TkFNZbSP 33 | KRMYQy9BfUxC1uGsy/a5NlfPAJ+uU7up+NHD9GCl7QtmJGsqdkac8VCSpUt+dgCI 34 | ILlIHbeWsMBsMZUNggOHZt+G8xE13mo2yr6ylJ87sRA0iu9Yk2BgQ1zkiLBPwZ+y 35 | UQARAQABiQG2BBgBCAAgFiEEkROfZrqeuVKivV+E2VquQNFOY7MFAmNHB2YCGwwA 36 | CgkQ2VquQNFOY7NLjQwAuCZYL+I5QwJ4nTFRRtkJYi55BvLbEuyVnYwbkHpHksg6 37 | Nxh1gbykEdFAafJAVDCwU/ov+GA7RLVRS0TtnU7DBKUmzbO6MvFusjs8190PwLKP 38 | 9Eb2gWgTkECyd0WC3HMvfTBk96koidpxGLDal5P7B8DoanaqcuEf5QAWawT66lW/ 39 | sOYmrDOlEisV14/Mk/XgdOO/X/BKDXoGlTOtsiWFw50sBzjg9nKQUkaSzgU1HB5g 40 | TSZu6Wi4OtVdTMxT2ryOLj78YAQ3eBtfDak2in2J6bOY2i9d+vP5TKik4DeZypNQ 41 | iLgAKJ5+2NRlCbnci1bmay21Ke1PIZiUTe82lCoS4CoEJzKU89NtHSU64M7FEjBS 42 | 5yYtMrs+ko+INWYG9aEj7rs4grpQMP9NF5AxfDuq77+Ca7Vg9pTkI1DYj1D91mWR 43 | J/pMd3YqlIkZ4JBN489FZ1qqRV6RuKko/qyqvvQ5+ziqrh+QjluJU4qI60znX/LI 44 | 1USIqi8ymF08Ak+cIhyO 45 | =WFfO 46 | -----END PGP PUBLIC KEY BLOCK----- 47 | ''; 48 | in 49 | 50 | { 51 | # Initializes Emacs with org-mode so we can tangle the main config 52 | # 53 | # @todo: Get rid of this after we've upgraded to Emacs 29 on the Macbook 54 | # Emacs 29 includes org-mode now 55 | ".emacs.d/init.el" = { 56 | text = builtins.readFile ./config/emacs/init.el; 57 | }; 58 | 59 | ".ssh/id_github.pub" = { 60 | text = githubPublicKey; 61 | }; 62 | 63 | ".ssh/pgp_github.pub" = { 64 | text = githubPublicSigningKey; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /modules/shared/packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | 3 | let 4 | myPython = pkgs.python3.withPackages (ps: with ps; [ 5 | slpp 6 | pip 7 | rich 8 | virtualenv 9 | black 10 | ]); 11 | in 12 | 13 | with pkgs; [ 14 | # General packages for development and system management 15 | act 16 | alacritty 17 | aspell 18 | aspellDicts.en 19 | bash-completion 20 | bat 21 | btop 22 | coreutils 23 | difftastic 24 | du-dust 25 | gcc 26 | git-filter-repo 27 | killall 28 | neofetch 29 | openssh 30 | pandoc 31 | sqlite 32 | wget 33 | zip 34 | uv 35 | 36 | # Encryption and security tools 37 | _1password 38 | age 39 | age-plugin-yubikey 40 | gnupg 41 | libfido2 42 | 43 | # Cloud-related tools and SDKs 44 | gopls 45 | ngrok 46 | terraform 47 | terraform-ls 48 | tflint 49 | 50 | # Media-related packages 51 | emacs-all-the-icons-fonts 52 | imagemagick 53 | dejavu_fonts 54 | ffmpeg 55 | fd 56 | font-awesome 57 | glow 58 | hack-font 59 | jpegoptim 60 | meslo-lgs-nf 61 | noto-fonts 62 | noto-fonts-emoji 63 | pngquant 64 | 65 | # PHP 66 | php82 67 | php82Packages.composer 68 | php82Packages.php-cs-fixer 69 | php82Extensions.xdebug 70 | php82Packages.deployer 71 | phpunit 72 | 73 | # Node.js development tools 74 | fzf 75 | nodePackages.live-server 76 | nodePackages.nodemon 77 | nodePackages.prettier 78 | nodePackages.npm 79 | nodejs 80 | 81 | # Source code management, Git, GitHub tools 82 | gh 83 | 84 | # Text and terminal utilities 85 | htop 86 | hunspell 87 | iftop 88 | jetbrains-mono 89 | jetbrains.phpstorm 90 | jq 91 | ripgrep 92 | slack 93 | tree 94 | tmux 95 | unrar 96 | unzip 97 | zsh-powerlevel10k 98 | 99 | myPython 100 | ] 101 | -------------------------------------------------------------------------------- /overlays/README.md: -------------------------------------------------------------------------------- 1 | # Overlays 2 | 3 | Files in this directory run automatically as part of each build. Some common ways I've used overlays in the past: 4 | * Applying patches 5 | * Downloading different versions of files (locking to a version or trying a fork) 6 | * Workarounds and stuff I need to run temporarily 7 | 8 | Here are some previous examples. 9 | 10 | ### Overriding a package with a specific hash from Github 11 | To get the sha256, I just made something up and tried to build it; Nix will complain with the actual sha256. 12 | ```nix 13 | final: prev: { 14 | picom = prev.picom.overrideAttrs (old: { 15 | src = prev.fetchFromGitHub { 16 | owner = "pijulius"; 17 | repo = "picom"; 18 | rev = "982bb43e5d4116f1a37a0bde01c9bda0b88705b9"; 19 | sha256 = "YiuLScDV9UfgI1MiYRtjgRkJ0VuA1TExATA2nJSJMhM="; 20 | }; 21 | }); 22 | } 23 | ``` 24 | 25 | ### Override a file or attribute of a package 26 | In Nix, we get to just patch things willy nilly. This is an old patch I used to get the `cypress` package working; it tidied me over until a proper fix was in `nixpkgs`. 27 | 28 | ```nix 29 | # When Cypress starts, it copies some files locally from the Nix Store, but 30 | # fails to remove the read-only flag. 31 | # 32 | # Luckily, the code responsible is a plain text script that we can easily patch: 33 | # 34 | final: prev: { 35 | cypress = prev.cypress.overrideAttrs (oldAttrs: { 36 | installPhase = let 37 | matchForChrome = "yield utils_1.default.copyExtension(pathToExtension, extensionDest);"; 38 | appendForChrome = "yield fs_1.fs.chmodAsync(extensionBg, 0o0644);"; # We edit this line 39 | 40 | matchForFirefox = "copyExtension(pathToExtension, extensionDest)"; 41 | replaceForFirefox = "copyExtension(pathToExtension, extensionDest).then(() => fs.chmodAsync(extensionBg, 0o0644))"; # We edit this line 42 | in '' 43 | sed -i '/${matchForChrome}/a\${appendForChrome}' \ 44 | ./resources/app/packages/server/lib/browsers/chrome.js 45 | 46 | sed -i 's/${matchForFirefox}/${replaceForFirefox}/' \ 47 | ./resources/app/packages/server/lib/browsers/utils.js 48 | '' + oldAttrs.installPhase; 49 | }); 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="aarch64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Cleaning up...${NC}" 17 | unlink ./result 18 | 19 | echo "${GREEN}Switch to new generation complete!${NC}" 20 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="aarch64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Switching to new generation...${NC}" 17 | # See https://github.com/nix-darwin/nix-darwin/issues/1457 on why we need sudo 18 | sudo ./result/sw/bin/darwin-rebuild switch --flake .#${SYSTEM_TYPE} $@ 19 | 20 | echo "${YELLOW}Cleaning up...${NC}" 21 | unlink ./result 22 | 23 | echo "${GREEN}Switch to new generation complete!${NC}" 24 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/check-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | lint_keys() { 12 | if [[ -f "${SSH_DIR}/id_ed25519" && -f "${SSH_DIR}/id_ed25519.pub" && -f "${SSH_DIR}/id_ed25519_agenix" && -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 13 | echo -e "${GREEN}All SSH keys are present.${NC}" 14 | else 15 | echo -e "${RED}Some SSH keys are missing.${NC}" 16 | if [[ ! -f "${SSH_DIR}/id_ed25519" ]]; then 17 | echo -e "${RED}Missing: id_ed25519${NC}" 18 | fi 19 | if [[ ! -f "${SSH_DIR}/id_ed25519.pub" ]]; then 20 | echo -e "${RED}Missing: id_ed25519.pub${NC}" 21 | fi 22 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix" ]]; then 23 | echo -e "${RED}Missing: id_ed25519_agenix${NC}" 24 | fi 25 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 26 | echo -e "${RED}Missing: id_ed25519_agenix.pub${NC}" 27 | fi 28 | echo -e "${GREEN}Run the createKeys command to generate the missing keys.${NC}" 29 | exit 1 30 | fi 31 | } 32 | 33 | lint_keys 34 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/copy-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | handle_no_usb() { 12 | echo -e ${RED}No USB drive found or mounted.${NC}" 13 | echo -e ${GREEN}If you have not yet set up your keys, run the script to generate new SSH keys.${NC}" 14 | exit 1 15 | } 16 | 17 | mount_usb() { 18 | MOUNT_PATH="" 19 | for dev in $(diskutil list | grep -o 'disk[0-9]'); do 20 | MOUNT_PATH="$(diskutil info /dev/${dev} | grep \"Mount Point\" | awk -F: '{print $2}' | xargs)" 21 | if [ -n "${MOUNT_PATH}" ]; then 22 | echo -e "${GREEN}USB drive found at ${MOUNT_PATH}.${NC}" 23 | break 24 | fi 25 | done 26 | 27 | if [ -z "${MOUNT_PATH}" ]; then 28 | echo -e "${RED}No USB drive found.${NC}" 29 | fi 30 | } 31 | 32 | copy_keys() { 33 | if [ -n "${MOUNT_PATH}" ]; then 34 | cp "${MOUNT_PATH}/id_ed25519_agenix.pub" ${SSH_DIR} 35 | cp "${MOUNT_PATH}/id_ed25519_agenix" ${SSH_DIR} 36 | chmod 600 ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 37 | else 38 | echo -e "${RED}No USB drive found. Aborting.${NC}" 39 | exit 1 40 | fi 41 | } 42 | 43 | setup_ssh_directory() { 44 | mkdir -p ${SSH_DIR} 45 | } 46 | 47 | set_keys() { 48 | cp ${MOUNT_PATH}/id_ed25519_github.pub ${SSH_DIR}/id_ed25519.pub 49 | cp ${MOUNT_PATH}/id_ed25519_github ${SSH_DIR}/id_ed25519 50 | chmod 600 ${SSH_DIR}/id_ed25519 51 | chmod 644 ${SSH_DIR}/id_ed25519.pub 52 | } 53 | 54 | change_ownership() { 55 | chown ${username}:staff ${SSH_DIR}/id_ed25519{,.pub} 56 | chown ${username}:staff ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 57 | } 58 | 59 | setup_ssh_directory 60 | mount_usb 61 | 62 | if [ -z "${MOUNT_PATH}" ]; then 63 | handle_no_usb 64 | else 65 | copy_keys 66 | set_keys 67 | change_ownership 68 | fi 69 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/create-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | setup_ssh_directory() { 12 | mkdir -p ${SSH_DIR} 13 | } 14 | 15 | prompt_for_key_generation() { 16 | local key_name=$1 17 | if [[ -f "${SSH_DIR}/${key_name}" ]]; then 18 | echo -e "${RED}Existing SSH key found for ${key_name}.${NC}" 19 | cat "${SSH_DIR}/${key_name}.pub" 20 | read -p "Do you want to replace it? (y/n) " -n 1 -r 21 | echo 22 | if [[ $REPLY =~ ^[Yy]$ ]]; then 23 | return 0 # Indicate key should be replaced 24 | else 25 | return 1 # Indicate key should be kept 26 | fi 27 | fi 28 | return 0 # Indicate no key exists, so it should be created 29 | } 30 | 31 | generate_key() { 32 | local key_name=$1 33 | if prompt_for_key_generation "$key_name"; then 34 | ssh-keygen -t ed25519 -f "${SSH_DIR}/${key_name}" -N "" 35 | chown ${username}:staff "${SSH_DIR}/${key_name}"{,.pub} 36 | else 37 | echo -e "${GREEN}Kept existing ${key_name}.${NC}" 38 | fi 39 | } 40 | 41 | setup_ssh_directory 42 | generate_key "id_ed25519" 43 | generate_key "id_ed25519_agenix" 44 | 45 | echo -e "${GREEN}SSH key setup complete.${NC}" 46 | echo -e "${GREEN}Remember to add the necessary keys to Github or other services as required.${NC}" 47 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-darwin/rollback: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | FLAKE="macos" 9 | 10 | echo "${YELLOW}Available generations:${NC}" 11 | /run/current-system/sw/bin/darwin-rebuild --list-generations 12 | 13 | echo "${YELLOW}Enter the generation number for rollback:${NC}" 14 | read GEN_NUM 15 | 16 | if [ -z "$GEN_NUM" ]; then 17 | echo "${RED}No generation number entered. Aborting rollback.${NC}" 18 | exit 1 19 | fi 20 | 21 | echo "${YELLOW}Rolling back to generation $GEN_NUM...${NC}" 22 | /run/current-system/sw/bin/darwin-rebuild switch --flake .#$FLAKE --switch-generation $GEN_NUM 23 | 24 | echo "${GREEN}Rollback to generation $GEN_NUM complete!${NC}" 25 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/aarch64-linux: -------------------------------------------------------------------------------- 1 | x86_64-linux -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-darwin/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="x86_64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Cleaning up...${NC}" 17 | unlink ./result 18 | 19 | echo "${GREEN}Switch to new generation complete!${NC}" 20 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-darwin/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | GREEN='\033[1;32m' 4 | YELLOW='\033[1;33m' 5 | RED='\033[1;31m' 6 | NC='\033[0m' 7 | 8 | SYSTEM_TYPE="x86_64-darwin" 9 | FLAKE_SYSTEM="darwinConfigurations.${SYSTEM_TYPE}.system" 10 | 11 | export NIXPKGS_ALLOW_UNFREE=1 12 | 13 | echo "${YELLOW}Starting build...${NC}" 14 | nix --extra-experimental-features 'nix-command flakes' build .#$FLAKE_SYSTEM $@ 15 | 16 | echo "${YELLOW}Switching to new generation...${NC}" 17 | # See https://github.com/nix-darwin/nix-darwin/issues/1457 on why we need sudo 18 | sudo ./result/sw/bin/darwin-rebuild switch --flake .#${SYSTEM_TYPE} $@ 19 | 20 | echo "${YELLOW}Cleaning up...${NC}" 21 | unlink ./result 22 | 23 | echo "${GREEN}Switch to new generation complete!${NC}" 24 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-darwin/check-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | lint_keys() { 12 | if [[ -f "${SSH_DIR}/id_ed25519" && -f "${SSH_DIR}/id_ed25519.pub" && -f "${SSH_DIR}/id_ed25519_agenix" && -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 13 | echo -e "${GREEN}All SSH keys are present.${NC}" 14 | else 15 | echo -e "${RED}Some SSH keys are missing.${NC}" 16 | if [[ ! -f "${SSH_DIR}/id_ed25519" ]]; then 17 | echo -e "${RED}Missing: id_ed25519${NC}" 18 | fi 19 | if [[ ! -f "${SSH_DIR}/id_ed25519.pub" ]]; then 20 | echo -e "${RED}Missing: id_ed25519.pub${NC}" 21 | fi 22 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix" ]]; then 23 | echo -e "${RED}Missing: id_ed25519_agenix${NC}" 24 | fi 25 | if [[ ! -f "${SSH_DIR}/id_ed25519_agenix.pub" ]]; then 26 | echo -e "${RED}Missing: id_ed25519_agenix.pub${NC}" 27 | fi 28 | echo -e "${GREEN}Run the createKeys command to generate the missing keys.${NC}" 29 | exit 1 30 | fi 31 | } 32 | 33 | lint_keys 34 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-darwin/copy-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | handle_no_usb() { 12 | echo -e ${RED}No USB drive found or mounted.${NC}" 13 | echo -e ${GREEN}If you have not yet set up your keys, run the script to generate new SSH keys.${NC}" 14 | exit 1 15 | } 16 | 17 | mount_usb() { 18 | MOUNT_PATH="" 19 | for dev in $(diskutil list | grep -o 'disk[0-9]'); do 20 | MOUNT_PATH="$(diskutil info /dev/${dev} | grep \"Mount Point\" | awk -F: '{print $2}' | xargs)" 21 | if [ -n "${MOUNT_PATH}" ]; then 22 | echo -e "${GREEN}USB drive found at ${MOUNT_PATH}.${NC}" 23 | break 24 | fi 25 | done 26 | 27 | if [ -z "${MOUNT_PATH}" ]; then 28 | echo -e "${RED}No USB drive found.${NC}" 29 | fi 30 | } 31 | 32 | copy_keys() { 33 | if [ -n "${MOUNT_PATH}" ]; then 34 | cp "${MOUNT_PATH}/id_ed25519_agenix.pub" ${SSH_DIR} 35 | cp "${MOUNT_PATH}/id_ed25519_agenix" ${SSH_DIR} 36 | chmod 600 ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 37 | else 38 | echo -e "${RED}No USB drive found. Aborting.${NC}" 39 | exit 1 40 | fi 41 | } 42 | 43 | setup_ssh_directory() { 44 | mkdir -p ${SSH_DIR} 45 | } 46 | 47 | set_keys() { 48 | cp ${MOUNT_PATH}/id_ed25519_github.pub ${SSH_DIR}/id_ed25519.pub 49 | cp ${MOUNT_PATH}/id_ed25519_github ${SSH_DIR}/id_ed25519 50 | chmod 600 ${SSH_DIR}/id_ed25519 51 | chmod 644 ${SSH_DIR}/id_ed25519.pub 52 | } 53 | 54 | change_ownership() { 55 | chown ${username}:staff ${SSH_DIR}/id_ed25519{,.pub} 56 | chown ${username}:staff ${SSH_DIR}/id_ed25519_{agenix,agenix.pub} 57 | } 58 | 59 | setup_ssh_directory 60 | mount_usb 61 | 62 | if [ -z "${MOUNT_PATH}" ]; then 63 | handle_no_usb 64 | else 65 | copy_keys 66 | set_keys 67 | change_ownership 68 | fi 69 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-darwin/create-keys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' 7 | 8 | username=${USER} 9 | export SSH_DIR=/Users/${username}/.ssh 10 | 11 | setup_ssh_directory() { 12 | mkdir -p ${SSH_DIR} 13 | } 14 | 15 | prompt_for_key_generation() { 16 | local key_name=$1 17 | if [[ -f "${SSH_DIR}/${key_name}" ]]; then 18 | echo -e "${RED}Existing SSH key found for ${key_name}.${NC}" 19 | cat "${SSH_DIR}/${key_name}.pub" 20 | read -p "Do you want to replace it? (y/n) " -n 1 -r 21 | echo 22 | if [[ $REPLY =~ ^[Yy]$ ]]; then 23 | return 0 # Indicate key should be replaced 24 | else 25 | return 1 # Indicate key should be kept 26 | fi 27 | fi 28 | return 0 # Indicate no key exists, so it should be created 29 | } 30 | 31 | generate_key() { 32 | local key_name=$1 33 | if prompt_for_key_generation "$key_name"; then 34 | ssh-keygen -t ed25519 -f "${SSH_DIR}/${key_name}" -N "" 35 | chown ${username}:staff "${SSH_DIR}/${key_name}"{,.pub} 36 | else 37 | echo -e "${GREEN}Kept existing ${key_name}.${NC}" 38 | fi 39 | } 40 | 41 | setup_ssh_directory 42 | generate_key "id_ed25519" 43 | generate_key "id_ed25519_agenix" 44 | 45 | echo -e "${GREEN}SSH key setup complete.${NC}" 46 | echo -e "${GREEN}Remember to add the necessary keys to Github or other services as required.${NC}" 47 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/apps/x86_64-linux/build-switch: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | VERSION=1.0 4 | 5 | GREEN='\033[1;32m' 6 | RED='\033[1;31m' 7 | YELLOW='\033[1;33m' 8 | NC='\033[0m' 9 | 10 | SYSTEM=$(uname -m) 11 | 12 | case "$SYSTEM" in 13 | x86_64) 14 | FLAKE_TARGET="x86_64-linux" 15 | ;; 16 | aarch64) 17 | FLAKE_TARGET="aarch64-linux" 18 | ;; 19 | *) 20 | echo -e "${RED}Unsupported architecture: $SYSTEM${NC}" 21 | exit 1 22 | ;; 23 | esac 24 | 25 | echo -e "${YELLOW}Starting...${NC}" 26 | 27 | # We pass SSH from user to root so root can download secrets from our private Github 28 | sudo SSH_AUTH_SOCK=$SSH_AUTH_SOCK /run/current-system/sw/bin/nixos-rebuild switch --flake .#$FLAKE_TARGET $@ 29 | 30 | echo -e "${GREEN}Switch to new generation complete!${NC}" 31 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Starter Configuration with secrets for MacOS and NixOS"; 3 | inputs = { 4 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 5 | agenix.url = "github:ryantm/agenix"; 6 | home-manager.url = "github:nix-community/home-manager"; 7 | darwin = { 8 | url = "github:LnL7/nix-darwin/master"; 9 | inputs.nixpkgs.follows = "nixpkgs"; 10 | }; 11 | nix-homebrew = { 12 | url = "github:zhaofengli-wip/nix-homebrew"; 13 | }; 14 | homebrew-bundle = { 15 | url = "github:homebrew/homebrew-bundle"; 16 | flake = false; 17 | }; 18 | homebrew-core = { 19 | url = "github:homebrew/homebrew-core"; 20 | flake = false; 21 | }; 22 | homebrew-cask = { 23 | url = "github:homebrew/homebrew-cask"; 24 | flake = false; 25 | }; 26 | disko = { 27 | url = "github:nix-community/disko"; 28 | inputs.nixpkgs.follows = "nixpkgs"; 29 | }; 30 | }; 31 | outputs = { self, darwin, nix-homebrew, homebrew-bundle, homebrew-core, homebrew-cask, home-manager, nixpkgs, disko, agenix } @inputs: 32 | let 33 | user = "%USER%"; 34 | linuxSystems = [ "x86_64-linux" "aarch64-linux" ]; 35 | darwinSystems = [ "aarch64-darwin" "x86_64-darwin" ]; 36 | forAllSystems = f: nixpkgs.lib.genAttrs (linuxSystems ++ darwinSystems) f; 37 | devShell = system: let pkgs = nixpkgs.legacyPackages.${system}; in { 38 | default = with pkgs; mkShell { 39 | nativeBuildInputs = with pkgs; [ bashInteractive git age age-plugin-yubikey ]; 40 | shellHook = with pkgs; '' 41 | export EDITOR=vim 42 | ''; 43 | }; 44 | }; 45 | mkApp = scriptName: system: { 46 | type = "app"; 47 | program = "${(nixpkgs.legacyPackages.${system}.writeScriptBin scriptName '' 48 | #!/usr/bin/env bash 49 | PATH=${nixpkgs.legacyPackages.${system}.git}/bin:$PATH 50 | echo "Running ${scriptName} for ${system}" 51 | exec ${self}/apps/${system}/${scriptName} 52 | '')}/bin/${scriptName}"; 53 | }; 54 | mkLinuxApps = system: { 55 | "apply" = mkApp "apply" system; 56 | "build-switch" = mkApp "build-switch" system; 57 | "copy-keys" = mkApp "copy-keys" system; 58 | "create-keys" = mkApp "create-keys" system; 59 | "check-keys" = mkApp "check-keys" system; 60 | "install" = mkApp "install" system; 61 | "install-with-secrets" = mkApp "install-with-secrets" system; 62 | }; 63 | mkDarwinApps = system: { 64 | "apply" = mkApp "apply" system; 65 | "build" = mkApp "build" system; 66 | "build-switch" = mkApp "build-switch" system; 67 | "copy-keys" = mkApp "copy-keys" system; 68 | "create-keys" = mkApp "create-keys" system; 69 | "check-keys" = mkApp "check-keys" system; 70 | "rollback" = mkApp "rollback" system; 71 | }; 72 | in 73 | { 74 | devShells = forAllSystems devShell; 75 | apps = nixpkgs.lib.genAttrs linuxSystems mkLinuxApps // nixpkgs.lib.genAttrs darwinSystems mkDarwinApps; 76 | 77 | darwinConfigurations = nixpkgs.lib.genAttrs darwinSystems (system: 78 | darwin.lib.darwinSystem { 79 | inherit system; 80 | specialArgs = inputs; 81 | modules = [ 82 | home-manager.darwinModules.home-manager 83 | nix-homebrew.darwinModules.nix-homebrew 84 | { 85 | nix-homebrew = { 86 | inherit user; 87 | enable = true; 88 | taps = { 89 | "homebrew/homebrew-core" = homebrew-core; 90 | "homebrew/homebrew-cask" = homebrew-cask; 91 | "homebrew/homebrew-bundle" = homebrew-bundle; 92 | }; 93 | mutableTaps = false; 94 | autoMigrate = true; 95 | }; 96 | } 97 | ./hosts/darwin 98 | ]; 99 | } 100 | ); 101 | 102 | nixosConfigurations = nixpkgs.lib.genAttrs linuxSystems (system: nixpkgs.lib.nixosSystem { 103 | inherit system; 104 | specialArgs = inputs; 105 | modules = [ 106 | disko.nixosModules.disko 107 | home-manager.nixosModules.home-manager { 108 | home-manager = { 109 | useGlobalPkgs = true; 110 | useUserPackages = true; 111 | users.${user} = import ./modules/nixos/home-manager.nix; 112 | }; 113 | } 114 | ./hosts/nixos 115 | ]; 116 | }); 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/hosts/darwin/default.nix: -------------------------------------------------------------------------------- 1 | { agenix, config, pkgs, ... }: 2 | 3 | let user = "%USER%"; in 4 | 5 | { 6 | 7 | imports = [ 8 | ../../modules/darwin/secrets.nix 9 | ../../modules/darwin/home-manager.nix 10 | ../../modules/shared 11 | agenix.darwinModules.default 12 | ]; 13 | 14 | # Setup user, packages, programs 15 | nix = { 16 | package = pkgs.nix; 17 | 18 | settings = { 19 | trusted-users = [ "@admin" "${user}" ]; 20 | substituters = [ "https://nix-community.cachix.org" "https://cache.nixos.org" ]; 21 | trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ]; 22 | }; 23 | 24 | gc = { 25 | automatic = true; 26 | interval = { Weekday = 0; Hour = 2; Minute = 0; }; 27 | options = "--delete-older-than 30d"; 28 | }; 29 | 30 | extraOptions = '' 31 | experimental-features = nix-command flakes 32 | ''; 33 | }; 34 | 35 | # Turn off NIX_PATH warnings now that we're using flakes 36 | 37 | # Load configuration that is shared across systems 38 | environment.systemPackages = with pkgs; [ 39 | emacs-unstable 40 | agenix.packages."${pkgs.system}".default 41 | ] ++ (import ../../modules/shared/packages.nix { inherit pkgs; }); 42 | 43 | launchd.user.agents.emacs.path = [ config.environment.systemPath ]; 44 | launchd.user.agents.emacs.serviceConfig = { 45 | KeepAlive = true; 46 | ProgramArguments = [ 47 | "/bin/sh" 48 | "-c" 49 | "/bin/wait4path ${pkgs.emacs}/bin/emacs && exec ${pkgs.emacs}/bin/emacs --fg-daemon" 50 | ]; 51 | StandardErrorPath = "/tmp/emacs.err.log"; 52 | StandardOutPath = "/tmp/emacs.out.log"; 53 | }; 54 | 55 | system = { 56 | checks.verifyNixPath = false; 57 | primaryUser = user; 58 | stateVersion = 4; 59 | 60 | defaults = { 61 | NSGlobalDomain = { 62 | AppleShowAllExtensions = true; 63 | ApplePressAndHoldEnabled = false; 64 | 65 | # 120, 90, 60, 30, 12, 6, 2 66 | KeyRepeat = 2; 67 | 68 | # 120, 94, 68, 35, 25, 15 69 | InitialKeyRepeat = 15; 70 | 71 | "com.apple.mouse.tapBehavior" = 1; 72 | "com.apple.sound.beep.volume" = 0.0; 73 | "com.apple.sound.beep.feedback" = 0; 74 | }; 75 | 76 | dock = { 77 | autohide = false; 78 | show-recents = false; 79 | launchanim = true; 80 | orientation = "bottom"; 81 | tilesize = 48; 82 | }; 83 | 84 | finder = { 85 | _FXShowPosixPathInTitle = false; 86 | }; 87 | 88 | trackpad = { 89 | Clicking = true; 90 | TrackpadThreeFingerDrag = true; 91 | }; 92 | }; 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Layout 3 | ``` 4 | . 5 | ├── dock # MacOS dock configuration 6 | ├── casks.nix # List of homebrew casks 7 | ├── default.nix # Defines module, system-level config 8 | ├── files.nix # Non-Nix, static configuration files (now immutable!) 9 | ├── home-manager.nix # Defines user programs 10 | ├── packages.nix # List of packages to install for MacOS 11 | ``` 12 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/casks.nix: -------------------------------------------------------------------------------- 1 | _: 2 | 3 | [ 4 | # Development Tools 5 | "homebrew/cask/docker" 6 | "visual-studio-code" 7 | 8 | # Communication Tools 9 | "discord" 10 | "notion" 11 | "slack" 12 | "telegram" 13 | "zoom" 14 | 15 | # Utility Tools 16 | "syncthing" 17 | 18 | # Entertainment Tools 19 | "vlc" 20 | 21 | # Productivity Tools 22 | "raycast" 23 | 24 | # Browsers 25 | "google-chrome" 26 | ] 27 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/dock/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | ... 6 | }: 7 | 8 | # Original source: https://gist.github.com/antifuchs/10138c4d838a63c0a05e725ccd7bccdd 9 | 10 | with lib; 11 | let 12 | cfg = config.local.dock; 13 | inherit (pkgs) stdenv dockutil; 14 | in 15 | { 16 | options = { 17 | local.dock = { 18 | enable = mkOption { 19 | description = "Enable dock"; 20 | default = stdenv.isDarwin; 21 | example = false; 22 | }; 23 | 24 | entries = mkOption { 25 | description = "Entries on the Dock"; 26 | type = 27 | with types; 28 | listOf (submodule { 29 | options = { 30 | path = lib.mkOption { type = str; }; 31 | section = lib.mkOption { 32 | type = str; 33 | default = "apps"; 34 | }; 35 | options = lib.mkOption { 36 | type = str; 37 | default = ""; 38 | }; 39 | }; 40 | }); 41 | readOnly = true; 42 | }; 43 | 44 | username = mkOption { 45 | description = "Username to apply the dock settings to"; 46 | type = types.str; 47 | }; 48 | }; 49 | }; 50 | 51 | config = mkIf cfg.enable ( 52 | let 53 | normalize = path: if hasSuffix ".app" path then path + "/" else path; 54 | entryURI = 55 | path: 56 | "file://" 57 | + (builtins.replaceStrings 58 | [ 59 | " " 60 | "!" 61 | "\"" 62 | "#" 63 | "$" 64 | "%" 65 | "&" 66 | "'" 67 | "(" 68 | ")" 69 | ] 70 | [ 71 | "%20" 72 | "%21" 73 | "%22" 74 | "%23" 75 | "%24" 76 | "%25" 77 | "%26" 78 | "%27" 79 | "%28" 80 | "%29" 81 | ] 82 | (normalize path) 83 | ); 84 | wantURIs = concatMapStrings (entry: "${entryURI entry.path}\n") cfg.entries; 85 | createEntries = concatMapStrings ( 86 | entry: 87 | "${dockutil}/bin/dockutil --no-restart --add '${entry.path}' --section ${entry.section} ${entry.options}\n" 88 | ) cfg.entries; 89 | in 90 | { 91 | system.activationScripts.postActivation.text = '' 92 | echo >&2 "Setting up the Dock for ${cfg.username}..." 93 | su ${cfg.username} -s /bin/sh <<'USERBLOCK' 94 | haveURIs="$(${dockutil}/bin/dockutil --list | ${pkgs.coreutils}/bin/cut -f2)" 95 | if ! diff -wu <(echo -n "$haveURIs") <(echo -n '${wantURIs}') >&2 ; then 96 | echo >&2 "Resetting Dock." 97 | ${dockutil}/bin/dockutil --no-restart --remove all 98 | ${createEntries} 99 | killall Dock 100 | else 101 | echo >&2 "Dock setup complete." 102 | fi 103 | USERBLOCK 104 | ''; 105 | } 106 | ); 107 | } 108 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/files.nix: -------------------------------------------------------------------------------- 1 | { user, config, pkgs, ... }: 2 | 3 | let 4 | xdg_configHome = "${config.users.users.${user}.home}/.config"; 5 | xdg_dataHome = "${config.users.users.${user}.home}/.local/share"; 6 | xdg_stateHome = "${config.users.users.${user}.home}/.local/state"; in 7 | { 8 | 9 | # Raycast script so that "Run Emacs" is available and uses Emacs daemon 10 | "${xdg_dataHome}/bin/emacsclient" = { 11 | executable = true; 12 | text = '' 13 | #!/bin/zsh 14 | # 15 | # Required parameters: 16 | # @raycast.schemaVersion 1 17 | # @raycast.title Run Emacs 18 | # @raycast.mode silent 19 | # 20 | # Optional parameters: 21 | # @raycast.packageName Emacs 22 | # @raycast.icon ${xdg_dataHome}/img/icons/Emacs.icns 23 | # @raycast.iconDark ${xdg_dataHome}/img/icons/Emacs.icns 24 | 25 | if [[ $1 = "-t" ]]; then 26 | # Terminal mode 27 | ${pkgs.emacs}/bin/emacsclient -t $@ 28 | else 29 | # GUI mode 30 | ${pkgs.emacs}/bin/emacsclient -c -n $@ 31 | fi 32 | ''; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/home-manager.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, home-manager, ... }: 2 | 3 | let 4 | user = "%USER%"; 5 | # Define the content of your file as a derivation 6 | myEmacsLauncher = pkgs.writeScript "emacs-launcher.command" '' 7 | #!/bin/sh 8 | emacsclient -c -n & 9 | ''; 10 | sharedFiles = import ../shared/files.nix { inherit config pkgs; }; 11 | additionalFiles = import ./files.nix { inherit user config pkgs; }; 12 | in 13 | { 14 | imports = [ 15 | ./dock 16 | ]; 17 | 18 | # It me 19 | users.users.${user} = { 20 | name = "${user}"; 21 | home = "/Users/${user}"; 22 | isHidden = false; 23 | shell = pkgs.zsh; 24 | }; 25 | 26 | homebrew = { 27 | enable = true; 28 | casks = pkgs.callPackage ./casks.nix {}; 29 | # onActivation.cleanup = "uninstall"; 30 | 31 | # These app IDs are from using the mas CLI app 32 | # mas = mac app store 33 | # https://github.com/mas-cli/mas 34 | # 35 | # $ nix shell nixpkgs#mas 36 | # $ mas search 37 | # 38 | # If you have previously added these apps to your Mac App Store profile (but not installed them on this system), 39 | # you may receive an error message "Redownload Unavailable with This Apple ID". 40 | # This message is safe to ignore. (https://github.com/dustinlyons/nixos-config/issues/83) 41 | 42 | masApps = { 43 | "1password" = 1333542190; 44 | "wireguard" = 1451685025; 45 | }; 46 | }; 47 | 48 | # Enable home-manager 49 | home-manager = { 50 | useGlobalPkgs = true; 51 | users.${user} = { pkgs, config, lib, ... }:{ 52 | home = { 53 | enableNixpkgsReleaseCheck = false; 54 | packages = pkgs.callPackage ./packages.nix {}; 55 | file = lib.mkMerge [ 56 | sharedFiles 57 | additionalFiles 58 | { "emacs-launcher.command".source = myEmacsLauncher; } 59 | ]; 60 | 61 | stateVersion = "23.11"; 62 | }; 63 | programs = {} // import ../shared/home-manager.nix { inherit config pkgs lib; }; 64 | 65 | # Marked broken Oct 20, 2022 check later to remove this 66 | # https://github.com/nix-community/home-manager/issues/3344 67 | manual.manpages.enable = false; 68 | }; 69 | }; 70 | 71 | # Fully declarative dock using the latest from Nix Store 72 | local = { 73 | dock = { 74 | enable = true; 75 | username = user; 76 | entries = [ 77 | { path = "/Applications/Slack.app/"; } 78 | { path = "/System/Applications/Messages.app/"; } 79 | { path = "/System/Applications/Facetime.app/"; } 80 | { path = "${pkgs.alacritty}/Applications/Alacritty.app/"; } 81 | { path = "/System/Applications/Music.app/"; } 82 | { path = "/System/Applications/News.app/"; } 83 | { path = "/System/Applications/Photos.app/"; } 84 | { path = "/System/Applications/Photo Booth.app/"; } 85 | { path = "/System/Applications/TV.app/"; } 86 | { path = "/System/Applications/Home.app/"; } 87 | { 88 | path = toString myEmacsLauncher; 89 | section = "others"; 90 | } 91 | { 92 | path = "${config.users.users.${user}.home}/.local/share/"; 93 | section = "others"; 94 | options = "--sort name --view grid --display folder"; 95 | } 96 | { 97 | path = "${config.users.users.${user}.home}/.local/share/downloads"; 98 | section = "others"; 99 | options = "--sort name --view grid --display stack"; 100 | } 101 | ]; 102 | }; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/packages.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | with pkgs; 4 | let shared-packages = import ../shared/packages.nix { inherit pkgs; }; in 5 | shared-packages ++ [ 6 | dockutil 7 | ] 8 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/darwin/secrets.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, agenix, secrets, ... }: 2 | 3 | let user = "%USER%"; in 4 | { 5 | age.identityPaths = [ 6 | "/Users/${user}/.ssh/id_ed25519" 7 | ]; 8 | 9 | # Your secrets go here 10 | # 11 | # Note: the installWithSecrets command you ran to boostrap the machine actually copies over 12 | # a Github key pair. However, if you want to store the keypair in your nix-secrets repo 13 | # instead, you can reference the age files and specify the symlink path here. Then add your 14 | # public key in shared/files.nix. 15 | # 16 | # If you change the key name, you'll need to update the SSH configuration in shared/home-manager.nix 17 | # so Github reads it correctly. 18 | 19 | # 20 | # age.secrets."github-ssh-key" = { 21 | # symlink = true; 22 | # path = "/Users/${user}/.ssh/id_github"; 23 | # file = "${secrets}/github-ssh-key.age"; 24 | # mode = "600"; 25 | # owner = "${user}"; 26 | # group = "staff"; 27 | # }; 28 | 29 | # age.secrets."github-signing-key" = { 30 | # symlink = false; 31 | # path = "/Users/${user}/.ssh/pgp_github.key"; 32 | # file = "${secrets}/github-signing-key.age"; 33 | # mode = "600"; 34 | # owner = "${user}"; 35 | # }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/nixos/README.md: -------------------------------------------------------------------------------- 1 | ## Layout 2 | ``` 3 | . 4 | ├── config # Config files not written in Nix 5 | ├── default.nix # Defines module, system-level config, 6 | ├── disk-config.nix # Disks, partitions, and filesystems 7 | ├── files.nix # Non-Nix, static configuration files (now immutable!) 8 | ├── home-manager.nix # Defines user programs 9 | ├── packages.nix # List of packages to install for NixOS 10 | ├── secrets.nix # Age-encrypted secrets with agenix 11 | ``` 12 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/nixos/config/login-wallpaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinlyons/nixos-config/640b0a637aff0585195207cca0b104a679f771fb/templates/starter-with-secrets/modules/nixos/config/login-wallpaper.png -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/nixos/config/polybar/colors.ini: -------------------------------------------------------------------------------- 1 | [color] 2 | 3 | background = #1F1F1F 4 | foreground = #FFFFFF 5 | foreground-alt = #8F8F8F 6 | module-fg = #FFFFFF 7 | primary = #546e7a 8 | secondary = #E53935 9 | alternate = #7cb342 10 | -------------------------------------------------------------------------------- /templates/starter-with-secrets/modules/nixos/config/polybar/user_modules.ini: -------------------------------------------------------------------------------- 1 | ;; ┌──────────────────────────────────────────────────────────────────────────────-----┐ 2 | ;; │░█▀█░█▀█░█░░░█░█░█▀▄░█▀█░█▀▄░░░░░░░░░█░█░█▀▀░█▀▀░█▀▄░░░█▄█░█▀█░█▀▄░█░█░█░░░█▀▀░█▀▀ │ 3 | ;; │░█▀▀░█░█░█░░░░█░░█▀▄░█▀█░█▀▄░░░░▀░░░░█░█░▀▀█░█▀▀░█▀▄░░░█░█░█░█░█░█░█░█░█░░░█▀▀░▀▀█ │ 4 | ;; │░▀░░░▀▀▀░▀▀▀░░▀░░▀▀░░▀░▀░▀░▀░░░░▀░░░░▀▀▀░▀▀▀░▀▀▀░▀░▀░░░▀░▀░▀▀▀░▀▀░░▀▀▀░▀▀▀░▀▀▀░▀▀▀ │ 5 | ;; │░Created░By░Aditya░Shakya░@adi1090x░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ 6 | ;; └──────────────────────────────────────────────────────────────────────────────-----┘ 7 | 8 | ;; _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ 9 | 10 | [module/updates] 11 | type = custom/script 12 | 13 | ; Available tokens: 14 | ; %counter% 15 | ; Command to be executed (using "/usr/bin/env sh -c [command]") 16 | exec = @packages@ 17 | 18 | ; Conditional command that, if defined, needs to exit successfully 19 | ; before the main exec command is invoked. 20 | ; Default: "" 21 | ;;exec-if = "" 22 | 23 | ; Will the script output continous content? 24 | ; Default: false 25 | tail = true 26 | 27 | ; Seconds to sleep between updates 28 | ; Default: 2 (0 if `tail = true`) 29 | interval = 0 30 | 31 | ; Available tags: 32 | ; - deprecated 33 | ;