diff --git a/.github/workflows/nix-checks.yml b/.github/workflows/nix-checks.yml new file mode 100644 index 0000000..1719c8a --- /dev/null +++ b/.github/workflows/nix-checks.yml @@ -0,0 +1,35 @@ +name: Nix Checks + +on: + push: + paths: + - 'flake.nix' + - 'flake.lock' + - 'nix-cleanup.sh' + - '.github/workflows/nix-checks.yml' + +jobs: + nix_checks: + runs-on: ubuntu-latest + strategy: + fail-fast: false + permissions: + id-token: write + contents: read + pull-requests: read + + steps: + - name: Checkout repository + uses: actions/checkout@cd7d8d697e10461458bc61a30d094dc601a8b017 #v4 + + - uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c #v26 + with: + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + sandbox = true # force sandbox for all OS (normally disabled for macOS) + + - name: Run app + run: nix run --print-build-logs --show-trace '.#nix-cleanup' -- --help + + - name: Run app with --system + run: nix run --print-build-logs --show-trace '.#nix-cleanup' -- --system diff --git a/README.md b/README.md index 44d7036..d2706c3 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# nix-cleanup \ No newline at end of file +# nix-cleanup +nix-cleanup is a script that cleans up the nix environment + +## Run +`nix run 'github:willyrgf/nix-cleanup'` + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..2e946ee --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1718024670, + "narHash": "sha256-irORPELC7pDFiNjlWawhSpa9omeGsesnZk8UrtQBT3g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3369c121872617068a879fad42bf5ba25f16c645", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c1ac541 --- /dev/null +++ b/flake.nix @@ -0,0 +1,40 @@ +{ + description = "nix-cleanup is a script that cleans up the nix environment."; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + packages.nix-cleanup = pkgs.stdenv.mkDerivation rec { + pname = "nix-cleanup"; + version = "0.0.1"; + src = ./.; + + buildInputs = [ pkgs.bash pkgs.nix pkgs.sudo ]; + + installPhase = '' + mkdir -p $out/bin + substitute ${pname}.sh $out/bin/${pname} \ + --replace "/usr/bin/env bash" "${pkgs.bash}/bin/bash" + chmod +x $out/bin/${pname} + ''; + + shellHook = '' + export PATH=${pkgs.bash}/bin:${pkgs.nix}/bin:${pkgs.sudo}/bin:$PATH + ''; + }; + + defaultPackage = self.packages.${system}.nix-cleanup; + + defaultApp = { + type = "app"; + program = "${self.packages.${system}.nix-cleanup}/bin/nix-cleanup"; + }; + }); +} + diff --git a/nix-cleanup.sh b/nix-cleanup.sh new file mode 100755 index 0000000..f991865 --- /dev/null +++ b/nix-cleanup.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +_exit_error(){ + echo "ERROR: $@" + exit 1 +} + +_arg0(){ + echo -n $0 | grep -Eo '([a-z]+[-.]?){1,}$' +} + +_help(){ + printf " +Usage: $(_arg0) [--system] [flake-pkg-name] [nix-store-path] +\t--system\t\tcleans up the whole nix-store (nix state) +\tflake-pkg-name\t\tcleans up everything related to this package on the nix-store +\tnix-store-path\t\tcleans up everything related to a nix-store path +" +} + +_delete_from_store_path(){ + STORE_PATH=$1 + + # Get all referrers + REFERRERS=$(nix-store --query --referrers-closure "$STORE_PATH") + + # Combine the store path and its referrers + ALL_PATHS="$STORE_PATH $REFERRERS" + + echo "The following paths will be deleted (${#ALL_PATHS}):" + echo "$ALL_PATHS" + + # Confirm before deletion + if [ ${CLEANUP_SYSTEM} -ne 1 ]; then + read -p "Are you sure you want to delete these paths? (y/N): " -r + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Aborting." + exit 1 + fi + fi + + # Delete the store path and its referrers + sudo nix-store --delete $ALL_PATHS + + echo "Deleted the following paths:" + echo "$ALL_PATHS" +} + +_nix_cleanup_system() { + echo "Indexing and deleting all nix-store paths..." + ls -1 -f -q /nix/store/ | grep -v '^\.' | + xargs -I {} -P 4 $0 /nix/store/{} + + # Perform garbage collection to clean up everything + sudo nix-collect-garbage -d +} + +_cleanup_package() { + PACKAGE_NAME=$1 + + # Get the store path of the package + + STORE_PATH=$(nix path-info .#$PACKAGE_NAME 2> >(grep -Eo '/nix/store/([a-z0-9]+[_.-]?)+')) + if [ -z "$STORE_PATH" ]; then + echo "Package $PACKAGE_NAME not found." + exit 1 + fi + + echo "Found store path: ${STORE_PATH[@]}" + _delete_from_store_path ${STORE_PATH[@]} + + # Perform garbage collection to clean up everything + sudo nix-collect-garbage -d + + echo "Garbage collection complete. Nix store is cleaned up." +} + +export CLEANUP_SYSTEM=0 + +# Ensure required packages is available +required_packages=("nix" "nix-store" "nix-collect-garbage") +for req in "${required_packages[@]}"; do + if ! type ${req} > /dev/null 2>&1; then + _exit_error "package required: ${req}" + fi +done + +# Ensure a arg is provided +if [ -z "$1" ]; then + _help + exit 1 +fi + +if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then + _help + exit 0 +fi + +if [ "$1" == "--system" ]; then + CLEANUP_SYSTEM=1 + _nix_cleanup_system + exit $? +fi + + +if [[ "$1" =~ "/nix/store" ]]; then + CLEANUP_SYSTEM=1 + _delete_from_store_path $1 + exit $? +fi + + +_cleanup_package $@