#!/bin/sh
set -eu


usage() {
	cat <<-'EOF'
		Usage:
		  gc [TYPE...]
		  gc -h
	EOF
}

help() {
	cat <<-'EOF'


		Options:
		  -h, --help    show this message

		  TYPE          what to do GC on (default: all):
		                - guix
		                - nix
		                - trash
		                - tmpdir
		                - coredump
		                - docker


		Free disk space system-wide.


		Examples:

		  Just run it, for all:

		    $ gc


		  Cleanup trash and tmpdir:

		    $ gc trash tmpdir
	EOF
}

for flag in "$@"; do
	case "$flag" in
		(--)
			break
			;;
		(--help)
			usage
			help
			exit
			;;
		(*)
			;;
	esac
done

while getopts 'h' flag; do
	case "$flag" in
		(h)
			usage
			help
			exit
			;;
		(*)
			usage >&2
			exit 2
			;;
	esac
done
shift $((OPTIND - 1))


disk() {
	df -h . |
		awk 'NR == 2 { printf "%s - %s/%s\n", $4, $3, $2 }'
}


gc_guix() {
	if [ ! -e /gnu/ ]; then
		return
	fi

	guix home delete-generations 1m ||:
	guix gc -d 1m

	if [ -e /var/guix/profiles/system ]; then
		pass show "$(hostname)"/andreh | head -n1 |
			sudo -iS guix system delete-generations 1m ||:
		pass show "$(hostname)"/andreh | head -n1 |
			sudo -iS guix gc -d 1m ||:
	fi
}

gc_nix() {
	if [ ! -e /nix/ ]; then
		return
	fi

	PROFILES='
	/nix/var/nix/profiles/per-user/root/channels
	/nix/var/nix/profiles/system
	'

	for p in $PROFILES; do
		pass show "$(hostname)"/andreh | head -n1 |
			sudo -iS nix-env --delete-generations old -p "$p"
	done
	nix-env --delete-generations old
	nix-store --gc
	nix-collect-garbage -d
}

gc_trash() {
	yes | trash-empty
}

gc_tmpdir() {
	find "${TMPDIR:-/tmp}" '(' -type f -or -type d ')' -atime +10 -exec rm -vrf {} \; ||:
}

gc_coredump() {
	find /var/crash/ -type f -user "$USER" -exec rm -vf {} \;
}

gc_docker() {
	if ! command -v docker; then
		return
	fi

	yes | docker system prune -a
	docker rmi  "$(docker images -a -q)"              ||:
	docker rm   "$(docker ps -a -f status=exited -q)" ||:
	docker stop "$(docker ps -a -q)"                  ||:
	docker rm   "$(docker ps -a -q)"                  ||:
	yes | docker volume prune
	yes | docker container prune
}


TYPES='
guix
nix
trash
tmpdir
docker
'

if [ $# -eq 0 ]; then
	# shellcheck disable=2086
	set -- $TYPES
fi

for type in "$@"; do
	CMD=gc_"$type"
	if ! command -v "$CMD" >/dev/null; then
		printf 'Invalid TYPE: "%s".\n\n' "$type" >&2
		usage >&2
		exit 2
	fi
done

BEFORE="$(disk)"
for type in "$@"; do
	CMD=gc_"$type"
	set -x
	"$CMD"
	{ set +x; } 2>/dev/null
done
AFTER="$(disk)"

cat <<-EOF
	Disk space:
	  before: $BEFORE
	  after:  $AFTER
EOF
