├── .github
├── FUNDING.yml
└── workflows
│ ├── debug.yaml
│ └── test.yaml
├── LICENSE
├── README.md
└── action.yml
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: flexiondotorg
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Martin Wimpress
4 | Copyright (c) 2024 Lucas Eduardo
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/debug.yaml:
--------------------------------------------------------------------------------
1 | name: Debug 🐛
2 | on:
3 | workflow_dispatch:
4 |
5 | concurrency:
6 | group: ${{ github.workflow }}
7 | cancel-in-progress: true
8 |
9 | jobs:
10 | test-ubuntu:
11 | name: Debug ${{ matrix.os }}
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | matrix:
15 | os: [ubuntu-22.04, ubuntu-24.04]
16 | fail-fast: false
17 | permissions:
18 | contents: read
19 | id-token: write
20 | steps:
21 | - name: Checkout
22 | uses: actions/checkout@v4
23 | with:
24 | path: ./.github/actions/this
25 | - name: Purge
26 | uses: ./.github/actions/this
27 | with:
28 | hatchet-protocol: rampage
29 | witness-carnage: true
30 | mnt-safe-haven: 10240
31 | root-safe-haven: 10240
32 | - name: Debug
33 | run: |
34 | sudo du -csh /opt/* | grep -v "Z 0"
35 | sudo du -csh /usr/bin/* | grep -v "Z 0"
36 | sudo du -csh /usr/lib/* | grep -v "Z 0"
37 | sudo du -csh /usr/share/* | grep -v "Z 0"
38 | sudo du -csh /var/lib/* | grep -v "Z 0"
39 | dpkg-query -W -f='${Installed-Size;8}\t${Status;1}\t${Package}\n' | grep -v "\sd\s" | sort -n | cut -f1,3-
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Test 🧪
2 | on:
3 | workflow_dispatch:
4 |
5 | concurrency:
6 | group: ${{ github.workflow }}
7 | cancel-in-progress: true
8 |
9 | jobs:
10 | determinate-nix-action:
11 | name: determinate-nix-action (${{ matrix.hatchet-protocol }}) on ${{ matrix.os }}
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | matrix:
15 | os: [ubuntu-22.04, ubuntu-24.04]
16 | hatchet-protocol: [holster, carve, cleave, rampage]
17 | fail-fast: false
18 | permissions:
19 | contents: read
20 | id-token: write
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v4
24 | with:
25 | path: ./.github/actions/this
26 | - name: Purge
27 | uses: ./.github/actions/this
28 | with:
29 | hatchet-protocol: ${{ matrix.hatchet-protocol }}
30 | witness-carnage: true
31 | - uses: DeterminateSystems/determinate-nix-action@main
32 | - name: Nix
33 | run: |
34 | nix --version
35 | echo "Hello Nix" | nix run "https://flakehub.com/f/NixOS/nixpkgs/*#neo-cowsay"
36 | # Build a package to ensure the Nix store is functional
37 | nix build "https://flakehub.com/f/NixOS/nixpkgs/*#hello"
38 | nix-quick-install:
39 | name: nix-quick-action (${{ matrix.hatchet-protocol }}) on ${{ matrix.os }}
40 | runs-on: ${{ matrix.os }}
41 | strategy:
42 | matrix:
43 | os: [ubuntu-22.04, ubuntu-24.04]
44 | hatchet-protocol: [holster, carve, cleave, rampage]
45 | fail-fast: false
46 | permissions:
47 | contents: read
48 | id-token: write
49 | steps:
50 | - name: Checkout
51 | uses: actions/checkout@v4
52 | with:
53 | path: ./.github/actions/this
54 | - name: Purge
55 | uses: ./.github/actions/this
56 | with:
57 | hatchet-protocol: ${{ matrix.hatchet-protocol }}
58 | witness-carnage: true
59 | nix-permission-edict: true
60 | - uses: nixbuild/nix-quick-install-action@v30
61 | - name: Nix
62 | run: |
63 | nix --version
64 | echo "Hello Nix" | nix run "nixpkgs#neo-cowsay"
65 | # Build a package to ensure the Nix store is functional
66 | nix build "nixpkgs#hello"
67 | cachix-nix-action:
68 | name: cachix-nix-action (${{ matrix.hatchet-protocol }}) on ${{ matrix.os }}
69 | runs-on: ${{ matrix.os }}
70 | strategy:
71 | matrix:
72 | os: [ubuntu-22.04, ubuntu-24.04]
73 | hatchet-protocol: [holster, carve, cleave, rampage]
74 | fail-fast: false
75 | permissions:
76 | contents: read
77 | id-token: write
78 | steps:
79 | - name: Checkout
80 | uses: actions/checkout@v4
81 | with:
82 | path: ./.github/actions/this
83 | - name: Purge
84 | uses: ./.github/actions/this
85 | with:
86 | hatchet-protocol: ${{ matrix.hatchet-protocol }}
87 | witness-carnage: true
88 | nix-permission-edict: true
89 | - uses: cachix/install-nix-action@v31
90 | - name: Nix
91 | run: |
92 | nix --version
93 | echo "Hello Nix" | nix run "nixpkgs#neo-cowsay"
94 | # Build a package to ensure the Nix store is functional
95 | nix build "nixpkgs#hello"
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 🌐 Language
5 |
29 |
30 |
31 |
32 | # Nothing but Nix
33 |
34 | **Transform your GitHub Actions runner into a [Nix](https://zero-to-nix.com/concepts/nix/) ❄️ powerhouse by ruthlessly slashing pre-installed bloat.**
35 |
36 | GitHub Actions runners come with meager disk space for Nix - a mere ~20GB.
37 | *Nothing but Nix* **brutally purges** unnecessary software, giving you **65GB to 130GB** for your Nix store! 💪
38 |
39 | ## Usage 🔧
40 |
41 | Add this action **before** installing Nix in your workflow:
42 |
43 | ```yaml
44 | jobs:
45 | build:
46 | runs-on: ubuntu-latest
47 | permissions:
48 | contents: read
49 | id-token: write
50 | steps:
51 | - uses: actions/checkout@v4
52 | - uses: wimpysworld/nothing-but-nix@main
53 | - name: Install Nix
54 | uses: DeterminateSystems/nix-installer-action@main
55 | - name: Run Nix
56 | run: |
57 | nix --version
58 | # Your Nix-powered steps here...
59 | ```
60 |
61 | ### Requirements ️✔️
62 |
63 | - Only supports official **Ubuntu** GitHub Actions runners
64 | - Must run **before** Nix is installed
65 |
66 | ## The Problem: Making Room for Nix to Thrive 🌱
67 |
68 | Standard GitHub Actions runners are stuffed with *"bloatware"* you'll never use in a Nix workflow:
69 |
70 | - 🌍 Web browsers. Lots of them. Gotta have 'em all!
71 | - 🐳 Docker images consuming gigabytes of precious disk space
72 | - 💻 Unnecessary language runtimes (.NET, Ruby, PHP, Java...)
73 | - 📦 Package managers gathering digital dust
74 | - 📚 Documentation no one will ever read
75 |
76 | This bloat leaves only ~20GB for your Nix store - barely enough for serious Nix builds! 😞
77 |
78 | ## The Solution: Nothing but Nix ️❄️
79 |
80 | **Nothing but Nix** takes a scorched-earth approach to GitHub Actions runners and mercilessly reclaims disk space using a two-phase attack:
81 |
82 | 1. **Initial Slash:** Instantly creates a large `/nix` volume (~65GB) by claiming free space from `/mnt`
83 | 2. **Background Rampage:** While your workflow continues, we ruthlessly eliminate unnecessary software to expand your `/nix` volume up to ~130GB
84 | - Web browsers? Nope ⛔
85 | - Docker images? Gone 🗑️
86 | - Language runtimes? Obliterated 💥
87 | - Package managers? Annihilated 💣
88 | - Documentation? Vaporized ️👻
89 |
90 | The file system purge is powered by `rmz` (from the [Fast Unix Commands (FUC)](https://github.com/SUPERCILEX/fuc) project) - a high-performance alternative to `rm` that makes space reclamation blazing fast! ⚡
91 | - Outperforms standard `rm` by an order of magnitude
92 | - Parallel-processes deletions for maximum efficiency
93 | - **Reclaims disk space in seconds rather than minutes!** ️⏱️
94 |
95 | The end result? A GitHub Actions runner with **65GB to 130GB** of Nix-ready space! 😁
96 |
97 | ### Dynamic Volume Growth
98 |
99 | Unlike other solutions, **Nothing but Nix** grows your `/nix` volume dynamically:
100 |
101 | 1. **Initial Volume Creation (1-10 seconds):** (*depending on Hatchet Protocol*)
102 | - Creates a loop device from free space on `/mnt`
103 | - Sets up a BTRFS filesystem in RAID0 configuration
104 | - Mounts with compression and performance tuning
105 | - Provides a 65GB `/nix` immediately, even before the purge begins
106 |
107 | 2. **Background Expansion (30-180 seconds):** (*depending on Hatchet Protocol*)
108 | - Executes purging operations
109 | - Monitors for newly freed space as bloat is eliminated
110 | - Dynamically adds an expansion disk to the `/nix` volume
111 | - Rebalances the filesystem to incorporate new space
112 |
113 | The `/nix` volume automatically **grows during workflow execution** 🎩🪄
114 |
115 | ### Choose Your Weapon: The Hatchet Protocol 🪓
116 |
117 | Control the level of annihilation 💥 with the `hatchet-protocol` input:
118 |
119 | ```yaml
120 | - uses: wimpysworld/nothing-but-nix@main
121 | with:
122 | hatchet-protocol: 'cleave' # Options: holster, carve, cleave (default), rampage
123 | ```
124 |
125 | #### Protocol Comparison ⚖️
126 |
127 | | Protocol | `/nix` | Description | Purge apt | Purge docker | Purge snap | Purged file systems |
128 | |----------|--------|--------------------------------------------------|------------|--------------|------------|-------------------------|
129 | | Holster | ~65GB | Keep the hatchet sheathed, use space from `/mnt` | No | No | No | None |
130 | | Carve | ~85GB | Craft and combine free space from `/` and `/mnt` | No | No | No | None |
131 | | Cleave | ~115GB | Make powerful, decisive cuts to large packages | Minimal | Yes | Yes | `/opt` and `/usr/local` |
132 | | Rampage | ~130GB | Relentless, brutal elimination of all bloat | Aggressive | Yes | Yes | Muahahaha! 🔥🌎 |
133 |
134 | Choose wisely:
135 | - **Holster** when you need the runner's tools to remain fully functional
136 | - **Carve** to preserve functional runner tooling but claim all free space for Nix
137 | - **Cleave** (*default*) for a good balance of space and functionality
138 | - **Rampage** when you need maximum Nix space and don't care what breaks `#nix-is-life`
139 |
140 | ### Witness The Carnage 🩸
141 |
142 | By default, the purging process executes silently in the background while your workflow continues. But if you want to watch the slaughter in real-time:
143 |
144 | ```yaml
145 | - uses: wimpysworld/nothing-but-nix@main
146 | with:
147 | ️hatchet-protocol: 'cleave'
148 | witness-carnage: true # Default: false
149 | ```
150 |
151 | ### Customize Safe Havens 🛡️
152 |
153 | Control how much space to spare from the Nix store land grab with custom safe haven sizes:
154 |
155 | ```yaml
156 | - uses: wimpysworld/nothing-but-nix@main
157 | with:
158 | ️hatchet-protocol: 'cleave'
159 | root-safe-haven: '3072' # Reserve 3GB on the / filesystem
160 | mnt-safe-haven: '2048' # Reserve 2GB on the /mnt filesystem
161 | ```
162 |
163 | These safe havens define how much space (in MB) will be mercifully spared during space reclamation:
164 | - Default `root-safe-haven` is 2048MB (2GB)
165 | - Default `mnt-safe-haven` is 1024MB (1GB)
166 |
167 | Increase these values if you need more breathing room on your filesystems, or decrease them to show no mercy! 😈
168 |
169 | ### Grant User Ownership of /nix (Nix Permission Edict) 🧑⚖️
170 |
171 | Some Nix installers or configurations expect the `/nix` directory to be writable by the current user. By default, `/nix` is owned by root. If you need user ownership (e.g., for certain Nix installer scripts that don't use `sudo` for all operations within `/nix`), you can enable the `nix-permission-edict`:
172 |
173 | ```yaml
174 | - uses: wimpysworld/nothing-but-nix@main
175 | with:
176 | nix-permission-edict: true # Default: false
177 | ```
178 |
179 | When `nix-permission-edict` is set to `true`, the action will run `sudo chown -R "$(id --user)":"$(id --group)" /nix` after mounting `/nix`.
180 |
181 | Now go and build something amazing with all that glorious Nix store space! ❄️
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Nothing but Nix'
2 | description: 'Removes all the cruft 🪓 from a GitHub Actions runner to make the most space possible for Nix ️❄️'
3 | branding:
4 | icon: 'trash-2'
5 | color: 'red'
6 | inputs:
7 | hatchet-protocol:
8 | description: 'Level of file purging (Holster: none, Cleave: standard, Rampage: aggressive)'
9 | required: false
10 | default: 'cleave'
11 | witness-carnage:
12 | description: 'Display purge progress in real-time instead of running in background'
13 | required: false
14 | default: 'false'
15 | root-safe-haven:
16 | description: 'Space in MB to mercifully spare on the / filesystem (default: 2048)'
17 | required: false
18 | default: '2048'
19 | mnt-safe-haven:
20 | description: 'Space in MB to mercifully spare on the /mnt filesystem (default: 1024)'
21 | required: false
22 | default: '1024'
23 | nix-permission-edict:
24 | description: 'Grant user ownership of /nix directory (default: false). Useful for Nix installers that require user-writable /nix.'
25 | required: false
26 | default: 'false'
27 | runs:
28 | using: composite
29 | steps:
30 | - name: The Checks
31 | id: environment-check
32 | shell: bash
33 | run: |
34 | if [[ "${{ runner.os }}" == "Linux" ]]; then
35 | if [ "$(lsb_release -is)" != "Ubuntu" ]; then
36 | echo "is_supported=false" >> $GITHUB_OUTPUT
37 | echo "This action only works on Ubuntu runners"
38 | exit 1
39 | else
40 | echo "is_supported=true" >> $GITHUB_OUTPUT
41 | fi
42 | fi
43 |
44 | if [ -z "$GITHUB_ACTIONS" ]; then
45 | echo "is_supported=false" >> $GITHUB_OUTPUT
46 | echo "This action only works on GitHub Actions runner"
47 | exit 1
48 | fi
49 |
50 | if [ -d /nix ]; then
51 | echo "is_supported=false" >> $GITHUB_OUTPUT
52 | echo "This action must be run before Nix is installed"
53 | exit 1
54 | else
55 | echo "is_supported=true" >> $GITHUB_OUTPUT
56 | fi
57 | - name: The Hatchet Protocol
58 | id: set-hatchet-protocol
59 | if: steps.environment-check.outputs.is_supported == 'true'
60 | shell: bash
61 | run: |
62 | input_protocol="${{ inputs.hatchet-protocol }}"
63 | # Convert to lowercase for case-insensitive comparison
64 | input_protocol="$(tr '[:upper:]' '[:lower:]' <<< "$input_protocol")"
65 |
66 | case "$input_protocol" in
67 | "holster")
68 | echo "🪓 Hatchet Protocol: Holster - Keep the hatchet sheathed, use space from /mnt (Level 0)"
69 | protocol_level=0;;
70 | "carve")
71 | echo "🪓 Hatchet Protocol: Carve - Craft and combine free space from / and /mnt (Level 1)"
72 | protocol_level=1;;
73 | "cleave")
74 | echo "🪓 Hatchet Protocol: Cleave - Make powerful, decisive cuts to large packages (Level 2)"
75 | protocol_level=2;;
76 | "rampage")
77 | echo "🪓 Hatchet Protocol: Rampage - Relentless, brutal elimination of all bloat (Level 3)"
78 | protocol_level=3;;
79 | *)
80 | echo "🪓 Hatchet Protocol: Cleave - Make powerful, decisive cuts to large packages (Level 2)"
81 | protocol_level=2;;
82 | esac
83 |
84 | echo "level=${protocol_level}" >> $GITHUB_OUTPUT
85 | - name: The Setup
86 | if: steps.environment-check.outputs.is_supported == 'true' && steps.set-hatchet-protocol.outputs.level > 1
87 | shell: bash
88 | run: |
89 | ARCH=$(uname -m)
90 | if [[ "$ARCH" == "x86_64" ]]; then
91 | URL_ARCH="x86_64"
92 | elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
93 | URL_ARCH="aarch64"
94 | else
95 | echo "Unsupported architecture: $ARCH"
96 | exit 1
97 | fi
98 |
99 | OS=$(uname -s)
100 | if [[ "$OS" == "Linux" ]]; then
101 | URL_OS="unknown-linux-gnu"
102 | elif [[ "$OS" == "Darwin" ]]; then
103 | URL_OS="apple-darwin"
104 | else
105 | echo "Unsupported OS: $OS"
106 | exit 1
107 | fi
108 |
109 | DOWNLOAD_URL="https://github.com/SUPERCILEX/fuc/releases/download/3.0.1/${URL_ARCH}-${URL_OS}-rmz"
110 | curl -L -o rmz "$DOWNLOAD_URL"
111 | chmod +x rmz
112 | sudo mv rmz /usr/bin/rmz
113 | rmz --version
114 | - name: The Volume
115 | if: steps.environment-check.outputs.is_supported == 'true'
116 | shell: bash
117 | run: |
118 | free_space=$(df -m --output=avail /mnt | tail -n 1 | tr -d ' ')
119 | echo "Initial free space of /mnt: ${free_space}MB"
120 | loop_dev=$(sudo losetup --find)
121 | loop_num=${loop_dev##*/loop}
122 |
123 | if sudo fallocate -l $((free_space - ${{ inputs.mnt-safe-haven }}))M "/mnt/disk${loop_num}.img"; then
124 | sudo losetup ${loop_dev} "/mnt/disk${loop_num}.img"
125 | fi
126 |
127 | # Create filesystem
128 | sudo mkfs.btrfs -L nix -d raid0 -m raid0 --nodiscard "${loop_dev}"
129 | sudo btrfs device scan
130 | sudo btrfs filesystem show
131 |
132 | # Mount filesystem
133 | sudo mkdir -p /nix
134 | sudo mount LABEL=nix /nix -o noatime,nobarrier,nodiscard,compress=zstd:1,space_cache=v2,commit=120
135 | sudo df -h
136 |
137 | if [[ "${{ inputs.nix-permission-edict }}" == "true" ]]; then
138 | echo "Applying Nix Permission Edict: Granting user ownership of /nix"
139 | sudo chown -R "$(id --user)":"$(id --group)" /nix
140 | fi
141 |
142 | # Create a tmp directory within /mnt for Nix builds and set TMPDIR
143 | TMPNIX="$(sudo mktemp --directory --tmpdir=/mnt)"
144 | sudo chmod 1777 "${TMPNIX}"
145 | echo "TMPDIR=${TMPNIX}" >> $GITHUB_ENV
146 | echo "TMPDIR set to ${TMPNIX} to use space on the /mnt volume for builds."
147 |
148 | # Create a directory to store expansion state
149 | mkdir -p "${HOME}/.expansion"
150 | echo "Initial volume created" | tee "${HOME}/.expansion/holster_done"
151 | - name: The Local
152 | if: steps.environment-check.outputs.is_supported == 'true' && steps.set-hatchet-protocol.outputs.level >= 2
153 | shell: bash
154 | run: |
155 | # Nix is often installed in /usr/local, so we need to ensure that it is purged early
156 | sudo rmz -f /usr/local
157 | sudo mkdir -p /usr/local/{bin,doc,include,lib,man,sbin,share,src} || true
158 | - name: The Purge
159 | if: steps.environment-check.outputs.is_supported == 'true'
160 | shell: bash
161 | run: |
162 | cat > /tmp/expand_nix_volume.sh << 'EOF'
163 | #!/usr/bin/env bash
164 | set -e
165 |
166 | protocol_level="${{ steps.set-hatchet-protocol.outputs.level }}"
167 | expansion_dir="${HOME}/.expansion"
168 | root_safe_haven="${{ inputs.root-safe-haven }}"
169 |
170 | function add_expansion_disk() {
171 | # Check for additional free space after purging
172 | free_space=$(df -m --output=avail / | tail -n 1 | tr -d ' ')
173 | echo "Free space of / after purge: ${free_space}MB"
174 |
175 | # Create additional disk if suitable free space exists
176 | if [ $free_space -gt $((root_safe_haven + 2048)) ]; then
177 | # Calculate the size of the expansion disk, reserving the safe haven
178 | disk_size=$((free_space - root_safe_haven))
179 | echo "Creating expansion disk of ${disk_size}MB in /"
180 | # Create expansion disk image
181 | loop_dev=$(sudo losetup --find)
182 | loop_num=${loop_dev##*/loop}
183 | if sudo fallocate -l ${disk_size}M "/disk${loop_num}.img"; then
184 | sudo losetup ${loop_dev} "/disk${loop_num}.img"
185 |
186 | # Add the new device to the pool
187 | sudo btrfs device add --nodiscard ${loop_dev} /nix
188 | echo "Added expansion disk "/disk${loop_num}.img" (${loop_dev}, ${disk_size}MB) to /nix pool" > $expansion_dir/expansion_done
189 |
190 | # Balance the filesystem to use the new space
191 | sudo btrfs balance start -dusage=50 /nix
192 | sudo btrfs filesystem show
193 | fi
194 | fi
195 | }
196 |
197 | # If carve is selected, claim space from / now
198 | if [[ "$protocol_level" -eq 1 ]]; then
199 | echo "Disk space has been carved out" > $expansion_dir/carve_done
200 | add_expansion_disk
201 | fi
202 |
203 | # Cleanse docker
204 | if [[ "$protocol_level" -ge 2 ]]; then
205 | for CRUFT in $(docker image ls --format '{{.ID}}'); do
206 | docker rmi --force "${CRUFT}" || true
207 | done
208 | docker system prune --all --force
209 | sudo apt-get -y remove --purge '^docker.*'
210 | sudo rmz -f /usr/bin/docker* /var/lib/docker
211 | echo "Cleanse docker complete" > $expansion_dir/docker_done
212 | fi
213 |
214 | # Cleanse snap
215 | if [[ "$protocol_level" -ge 2 ]]; then
216 | sudo apt-get -y remove --purge snapd
217 | sudo rmz -f \
218 | /snap \
219 | /usr/lib/snapd \
220 | /var/snap \
221 | /var/lib/snapd \
222 | "${HOME}/snap"
223 | echo "Cleanse snap complete" > $expansion_dir/snap_done
224 | fi
225 |
226 | # Cleanse apt
227 | if [[ "$protocol_level" -ge 2 ]]; then
228 | sudo tee /etc/dpkg/dpkg.cfg.d/01_nocruft > /dev/null << 'APTCFG'
229 | path-exclude /usr/share/doc/*
230 | path-exclude /usr/share/fonts/*
231 | path-exclude /usr/share/icons/*
232 | path-exclude /usr/share/info/*
233 | path-exclude /usr/share/man/*
234 | APTCFG
235 |
236 | if [[ "$protocol_level" -ge 3 ]]; then
237 | sudo apt-get -y remove --purge \
238 | '^apache2.*' \
239 | '^aspnetcore-.*' \
240 | azure-cli \
241 | buildah \
242 | '^byobu.*' \
243 | '^clang-.*' \
244 | containerd.io \
245 | containernetworking-plugins \
246 | '^dotnet-.*' \
247 | firefox \
248 | '^fonts-.*' \
249 | fwupd \
250 | '^gfortran-.*' \
251 | '^google-.*' \
252 | '^gradle.*' \
253 | '^java.*' \
254 | '^kotlin.*' \
255 | kubectl \
256 | '^libclang-.*' \
257 | libgl1-mesa-dri \
258 | '^libgirepository-.*' \
259 | '^libgtk-.*' \
260 | '^libllvm-.*' \
261 | '^libx265-.*' \
262 | '^llvm-.*' \
263 | man-db \
264 | '^mecab.*' \
265 | mediainfo \
266 | '^mercurial.*' \
267 | microsoft-edge-stable \
268 | '^mongodb-.*' \
269 | '^mono-.*' \
270 | '^mssql-.*' \
271 | '^mysql-.*' \
272 | '^nginx-.*' \
273 | '^php.*' \
274 | '^podman.*' \
275 | '^powershell.*' \
276 | '^postgres.*' \
277 | python-babel-localedata \
278 | '^python3-babel.*' \
279 | '^python3-boto.*' \
280 | '^ruby.*' \
281 | '^r-base.*' \
282 | skopeo \
283 | tcl \
284 | tk \
285 | '^tex-.*' \
286 | '^vim.*'
287 | fi
288 |
289 | sudo apt-get -y autoremove --purge
290 | sudo apt-get -y clean
291 | echo "Cleanse apt complete" > $expansion_dir/apt_done
292 | fi
293 |
294 | # Cleave
295 | if [[ "$protocol_level" -ge 2 ]]; then
296 | sudo rmz -f \
297 | "${HOME}/.rustup" \
298 | "${HOME}/.cargo" \
299 | "${HOME}/.dotnet" \
300 | /opt/containerd \
301 | /opt/hostedtoolcache \
302 | /opt/microsoft \
303 | /opt/az \
304 | /opt/pipx* \
305 | /opt/google \
306 | /opt/mssql-tools
307 | echo "Cleave complete" > $expansion_dir/cleave_done
308 | fi
309 |
310 | # Rampage
311 | if [[ "$protocol_level" -ge 3 ]]; then
312 | sudo rmz -f \
313 | /usr/bin/kotlin* \
314 | /usr/lib/heroku \
315 | /usr/share/apache-* \
316 | /usr/share/az_* \
317 | /usr/share/doc/* \
318 | /usr/share/fonts/* \
319 | /usr/share/gradle-* \
320 | /usr/share/icons/* \
321 | /usr/share/info/* \
322 | /usr/share/kotlinc \
323 | /usr/share/java \
324 | /usr/share/man/* \
325 | /usr/share/miniconda \
326 | /usr/share/sbt \
327 | /usr/share/swift \
328 | /usr/share/tcltk \
329 | /usr/share/texinfo \
330 | /var/lib/containerd \
331 | /var/lib/gems \
332 | /var/lib/mysql \
333 | /var/lib/ubuntu-advantage
334 | echo "Rampage complete" > $expansion_dir/rampage_done
335 | fi
336 |
337 | # Claim the space from / for purging
338 | if [[ "$protocol_level" -ge 2 ]]; then
339 | echo "The Purge Is Complete!" > $expansion_dir/purge_done
340 | add_expansion_disk
341 | fi
342 |
343 | echo "Everything completed" > $expansion_dir/all_done
344 | EOF
345 |
346 | # Make script executable
347 | chmod +x /tmp/expand_nix_volume.sh
348 | # Execute based on witness-carnage setting
349 | if [ "${{ inputs.witness-carnage }}" == "true" ]; then
350 | echo "😮 Displaying the carnage in real-time. This will block until completion."
351 | /tmp/expand_nix_volume.sh | tee ${HOME}/.expansion/expansion.log
352 | else
353 | /tmp/expand_nix_volume.sh > ${HOME}/.expansion/expansion.log 2>&1 &
354 | echo "📈 Background space expansion started. /nix will grow as space becomes available."
355 | fi
356 | - name: The Post
357 | if: ${{ runner.os }} == 'Linux'
358 | uses: srz-zumix/post-run-action@v2
359 | with:
360 | shell: bash -e {0}
361 | post-run: |
362 | ls -ltr ${HOME}/.expansion/*_done || true
363 | all_disks=()
364 |
365 | # Check for disks in /mnt directory
366 | mnt_disks=(/mnt/disk*.img)
367 | if [[ -e "${mnt_disks[0]}" ]]; then
368 | all_disks+=("${mnt_disks[@]}")
369 | fi
370 |
371 | # Check for disks in / directory
372 | root_disks=(/disk*.img)
373 | if [[ -e "${root_disks[0]}" ]]; then
374 | all_disks+=("${root_disks[@]}")
375 | fi
376 |
377 | echo "Found ${#all_disks[@]} disk image(s):"
378 | for disk in "${all_disks[@]}"; do
379 | echo "- $disk ($(du -h "$disk" | cut -f1))"
380 | done
381 | echo "Space used by TMPDIR:"
382 | sudo du -csh "$TMPDIR" || true
383 | echo "Space used by disk images:"
384 | sudo df -h
385 | echo "Check which device(s) btrfs is using:"
386 | sudo btrfs filesystem show /nix
387 | echo "See actual allocation per device:"
388 | sudo btrfs device stats /nix
389 |
390 |
--------------------------------------------------------------------------------