feat: improve scripts setup (lint, format, refactor)

This commit is contained in:
2026-03-21 17:38:19 +01:00
parent 7fcd8b2ec8
commit d8ab6207d5
7 changed files with 310 additions and 202 deletions

View File

@@ -12,3 +12,13 @@ repos:
language: system
files: \.nix$
pass_filenames: false
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.11.0
hooks:
- id: shellcheck
args: [-x, -P, scripts]
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
hooks:
- id: shfmt
args: [-d]

View File

@@ -147,6 +147,8 @@
packages = [
pkgs.pre-commit
pkgs.statix
pkgs.shellcheck
pkgs.shfmt
pkgs.qemu
];
};

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-prefetch
# shellcheck shell=bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -9,54 +10,62 @@ PKG_FILE="$SCRIPT_DIR/package.nix"
cd "$ROOT_DIR"
extract_hash() {
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
}
echo "fetching latest version..."
LATEST=$(curl -sf "https://git.janezic.dev/api/v1/repos/janezicmatej/ahab/tags?limit=1" | jq -r '.[0].name')
CURRENT=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
main() {
echo "fetching latest version..."
local latest current
latest=$(curl -sf "https://git.janezic.dev/api/v1/repos/janezicmatej/ahab/tags?limit=1" | jq -r '.[0].name')
current=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [[ "$CURRENT" == "$LATEST" ]]; then
echo "ahab already at $LATEST"
exit 0
fi
if [[ "$current" == "$latest" ]]; then
echo "ahab already at $latest"
return 0
fi
echo "updating ahab: $CURRENT -> $LATEST"
echo "updating ahab: $current -> $latest"
echo " prefetching source..."
BASE32=$(nix-prefetch-url --unpack "https://git.janezic.dev/janezicmatej/ahab/archive/${LATEST}.tar.gz" 2>/dev/null)
SRC_HASH=$(nix hash convert --to sri "sha256:$BASE32")
echo " source: $SRC_HASH"
echo " prefetching source..."
local base32 src_hash
base32=$(nix-prefetch-url --unpack "https://git.janezic.dev/janezicmatej/ahab/archive/${latest}.tar.gz" 2>/dev/null)
src_hash=$(nix hash convert --to sri "sha256:$base32")
echo " source: $src_hash"
echo " computing cargo hash..."
BUILD_OUTPUT=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
in pkgs.rustPlatform.fetchCargoVendor {
src = pkgs.fetchFromGitea {
domain = \"git.janezic.dev\";
owner = \"janezicmatej\";
repo = \"ahab\";
rev = \"$LATEST\";
hash = \"$SRC_HASH\";
};
hash = \"\";
}
" 2>&1) || true
CARGO_HASH=$(echo "$BUILD_OUTPUT" | extract_hash) || true
echo " computing cargo hash..."
local build_output cargo_hash
build_output=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
in pkgs.rustPlatform.fetchCargoVendor {
src = pkgs.fetchFromGitea {
domain = \"git.janezic.dev\";
owner = \"janezicmatej\";
repo = \"ahab\";
rev = \"$latest\";
hash = \"$src_hash\";
};
hash = \"\";
}
" 2>&1) || true
cargo_hash=$(echo "$build_output" | extract_hash) || true
if [[ -z "$CARGO_HASH" ]]; then
echo " error: failed to compute cargo hash"
echo "$BUILD_OUTPUT"
exit 1
fi
echo " cargo: $CARGO_HASH"
if [[ -z "$cargo_hash" ]]; then
echo "error: failed to compute cargo hash" >&2
echo "$build_output" >&2
exit 1
fi
echo " cargo: $cargo_hash"
OLD_SRC=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
OLD_CARGO=$(grep 'cargoHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
local old_src old_cargo
old_src=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
old_cargo=$(grep 'cargoHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
sed -i "s|version = \"$CURRENT\"|version = \"$LATEST\"|" "$PKG_FILE"
sed -i "s|$OLD_SRC|$SRC_HASH|" "$PKG_FILE"
sed -i "s|$OLD_CARGO|$CARGO_HASH|" "$PKG_FILE"
sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE"
sed -i "s|$old_src|$src_hash|" "$PKG_FILE"
sed -i "s|$old_cargo|$cargo_hash|" "$PKG_FILE"
echo "ahab updated to $LATEST"
echo "ahab updated to $latest"
}
main "$@"

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-prefetch
# shellcheck shell=bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -9,55 +10,63 @@ PKG_FILE="$SCRIPT_DIR/package.nix"
cd "$ROOT_DIR"
extract_hash() {
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
}
echo "fetching latest tag..."
LATEST=$(curl -sf "https://api.github.com/repos/tkw1536/ggman/tags?per_page=1" | jq -r '.[0].name')
CURRENT=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
main() {
echo "fetching latest tag..."
local latest current
latest=$(curl -sf "https://api.github.com/repos/tkw1536/ggman/tags?per_page=1" | jq -r '.[0].name')
current=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [[ "$CURRENT" == "$LATEST" ]]; then
echo "ggman already at $LATEST"
exit 0
fi
if [[ "$current" == "$latest" ]]; then
echo "ggman already at $latest"
return 0
fi
echo "updating ggman: $CURRENT -> $LATEST"
echo "updating ggman: $current -> $latest"
echo " prefetching source..."
BASE32=$(nix-prefetch-url --unpack "https://github.com/tkw1536/ggman/archive/${LATEST}.tar.gz" 2>/dev/null)
SRC_HASH=$(nix hash convert --to sri "sha256:$BASE32")
echo " source: $SRC_HASH"
echo " prefetching source..."
local base32 src_hash
base32=$(nix-prefetch-url --unpack "https://github.com/tkw1536/ggman/archive/${latest}.tar.gz" 2>/dev/null)
src_hash=$(nix hash convert --to sri "sha256:$base32")
echo " source: $src_hash"
echo " computing vendor hash..."
BUILD_OUTPUT=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs-master.legacyPackages.\${builtins.currentSystem};
in (pkgs.buildGoModule.override { go = pkgs.go_1_26; } {
pname = \"ggman\";
version = \"$LATEST\";
src = pkgs.fetchFromGitHub {
owner = \"tkw1536\";
repo = \"ggman\";
rev = \"$LATEST\";
hash = \"$SRC_HASH\";
};
vendorHash = \"\";
}).goModules
" 2>&1) || true
VENDOR_HASH=$(echo "$BUILD_OUTPUT" | extract_hash) || true
echo " computing vendor hash..."
local build_output vendor_hash
build_output=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs-master.legacyPackages.\${builtins.currentSystem};
in (pkgs.buildGoModule.override { go = pkgs.go_1_26; } {
pname = \"ggman\";
version = \"$latest\";
src = pkgs.fetchFromGitHub {
owner = \"tkw1536\";
repo = \"ggman\";
rev = \"$latest\";
hash = \"$src_hash\";
};
vendorHash = \"\";
}).goModules
" 2>&1) || true
vendor_hash=$(echo "$build_output" | extract_hash) || true
if [[ -z "$VENDOR_HASH" ]]; then
echo " error: failed to compute vendor hash"
echo "$BUILD_OUTPUT"
exit 1
fi
echo " vendor: $VENDOR_HASH"
if [[ -z "$vendor_hash" ]]; then
echo "error: failed to compute vendor hash" >&2
echo "$build_output" >&2
exit 1
fi
echo " vendor: $vendor_hash"
OLD_SRC=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
OLD_VENDOR=$(grep 'vendorHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
local old_src old_vendor
old_src=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
old_vendor=$(grep 'vendorHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
sed -i "s|version = \"$CURRENT\"|version = \"$LATEST\"|" "$PKG_FILE"
sed -i "s|$OLD_SRC|$SRC_HASH|" "$PKG_FILE"
sed -i "s|$OLD_VENDOR|$VENDOR_HASH|" "$PKG_FILE"
sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE"
sed -i "s|$old_src|$src_hash|" "$PKG_FILE"
sed -i "s|$old_vendor|$vendor_hash|" "$PKG_FILE"
echo "ggman updated to $LATEST"
echo "ggman updated to $latest"
}
main "$@"

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-prefetch
# shellcheck shell=bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -9,54 +10,62 @@ PKG_FILE="$SCRIPT_DIR/package.nix"
cd "$ROOT_DIR"
extract_hash() {
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+='
}
echo "fetching latest version..."
LATEST=$(curl -sf "https://git.janezic.dev/api/v1/repos/janezicmatej/todo-mcp/tags?limit=1" | jq -r '.[0].name')
CURRENT=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
main() {
echo "fetching latest version..."
local latest current
latest=$(curl -sf "https://git.janezic.dev/api/v1/repos/janezicmatej/todo-mcp/tags?limit=1" | jq -r '.[0].name')
current=$(grep 'version = ' "$PKG_FILE" | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [[ "$CURRENT" == "$LATEST" ]]; then
echo "todo-mcp already at $LATEST"
exit 0
fi
if [[ "$current" == "$latest" ]]; then
echo "todo-mcp already at $latest"
return 0
fi
echo "updating todo-mcp: $CURRENT -> $LATEST"
echo "updating todo-mcp: $current -> $latest"
echo " prefetching source..."
BASE32=$(nix-prefetch-url --unpack "https://git.janezic.dev/janezicmatej/todo-mcp/archive/${LATEST}.tar.gz" 2>/dev/null)
SRC_HASH=$(nix hash convert --to sri "sha256:$BASE32")
echo " source: $SRC_HASH"
echo " prefetching source..."
local base32 src_hash
base32=$(nix-prefetch-url --unpack "https://git.janezic.dev/janezicmatej/todo-mcp/archive/${latest}.tar.gz" 2>/dev/null)
src_hash=$(nix hash convert --to sri "sha256:$base32")
echo " source: $src_hash"
echo " computing cargo hash..."
BUILD_OUTPUT=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
in pkgs.rustPlatform.fetchCargoVendor {
src = pkgs.fetchFromGitea {
domain = \"git.janezic.dev\";
owner = \"janezicmatej\";
repo = \"todo-mcp\";
rev = \"$LATEST\";
hash = \"$SRC_HASH\";
};
hash = \"\";
}
" 2>&1) || true
CARGO_HASH=$(echo "$BUILD_OUTPUT" | extract_hash) || true
echo " computing cargo hash..."
local build_output cargo_hash
build_output=$(nix build --no-link --impure --expr "
let
pkgs = (builtins.getFlake \"path:$ROOT_DIR\").inputs.nixpkgs.legacyPackages.\${builtins.currentSystem};
in pkgs.rustPlatform.fetchCargoVendor {
src = pkgs.fetchFromGitea {
domain = \"git.janezic.dev\";
owner = \"janezicmatej\";
repo = \"todo-mcp\";
rev = \"$latest\";
hash = \"$src_hash\";
};
hash = \"\";
}
" 2>&1) || true
cargo_hash=$(echo "$build_output" | extract_hash) || true
if [[ -z "$CARGO_HASH" ]]; then
echo " error: failed to compute cargo hash"
echo "$BUILD_OUTPUT"
exit 1
fi
echo " cargo: $CARGO_HASH"
if [[ -z "$cargo_hash" ]]; then
echo "error: failed to compute cargo hash" >&2
echo "$build_output" >&2
exit 1
fi
echo " cargo: $cargo_hash"
OLD_SRC=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
OLD_CARGO=$(grep 'cargoHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
local old_src old_cargo
old_src=$(grep 'sha256 = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
old_cargo=$(grep 'cargoHash = ' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=')
sed -i "s|version = \"$CURRENT\"|version = \"$LATEST\"|" "$PKG_FILE"
sed -i "s|$OLD_SRC|$SRC_HASH|" "$PKG_FILE"
sed -i "s|$OLD_CARGO|$CARGO_HASH|" "$PKG_FILE"
sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE"
sed -i "s|$old_src|$src_hash|" "$PKG_FILE"
sed -i "s|$old_cargo|$cargo_hash|" "$PKG_FILE"
echo "todo-mcp updated to $LATEST"
echo "todo-mcp updated to $latest"
}
main "$@"

View File

@@ -1,87 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
SSH_PORT=2222
MEMORY=8G
CPUS=4
MOUNTS=()
CLAUDE=false
setup_colors() {
if [ -t 2 ]; then
red=$'\033[31m'
yellow=$'\033[33m'
cyan=$'\033[36m'
reset=$'\033[0m'
else
red="" yellow="" cyan="" reset=""
fi
}
die() {
echo "${red}error:${reset} $*" >&2
exit 1
}
warn() {
echo "${yellow}warning:${reset} $*" >&2
}
info() {
echo "${cyan}$*${reset}" >&2
}
# globals for cleanup trap
CLEANUP_OVERLAY=""
cleanup() {
[ -n "$CLEANUP_OVERLAY" ] && rm -rf "$CLEANUP_OVERLAY"
return 0
}
trap cleanup EXIT
usage() {
cat <<EOF
cat <<EOF
Usage: ephvm-run.sh [options]
Options:
--mount <path> Mount host directory into VM (repeatable)
--claude Mount claude config dir (requires CLAUDE_CONFIG_DIR)
--disk-size <size> Resize guest disk (e.g. 50G)
--memory <size> VM memory (default: 8G)
--cpus <n> VM CPUs (default: 4)
--ssh-port <port> SSH port forward (default: 2222)
-h, --help Show usage
EOF
exit 1
exit "${1:-0}"
}
while [ $# -gt 0 ]; do
case "$1" in
--mount) MOUNTS+=("$2"); shift 2 ;;
--claude) CLAUDE=true; shift ;;
--memory) MEMORY="$2"; shift 2 ;;
--cpus) CPUS="$2"; shift 2 ;;
--ssh-port) SSH_PORT="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "unknown option: $1"; usage ;;
esac
done
main() {
setup_colors
echo "building ephvm image..."
IMAGE_DIR=$(nix build --no-link --print-out-paths .#nixosConfigurations.ephvm.config.system.build.images.qemu)
IMAGE=$(find "$IMAGE_DIR" -name '*.qcow2' -print -quit)
local ssh_port=2222 memory=8G cpus=4 claude=false disk_size=""
local -a mounts=()
if [ -z "$IMAGE" ]; then
echo "error: no qcow2 image found in $IMAGE_DIR"
exit 1
fi
while [ $# -gt 0 ]; do
case "$1" in
--mount)
mounts+=("$2")
shift 2
;;
--claude)
claude=true
shift
;;
--disk-size)
disk_size="$2"
shift 2
;;
--memory)
memory="$2"
shift 2
;;
--cpus)
cpus="$2"
shift 2
;;
--ssh-port)
ssh_port="$2"
shift 2
;;
-h | --help) usage ;;
*)
echo "${red}error:${reset} unknown option: $1" >&2
usage 1
;;
esac
done
ACCEL="tcg"
[ -r /dev/kvm ] && ACCEL="kvm"
info "building ephvm image..."
local image_dir image
image_dir=$(nix build --no-link --print-out-paths .#nixosConfigurations.ephvm.config.system.build.images.qemu)
image=$(find "$image_dir" -name '*.qcow2' -print -quit)
[ -n "$image" ] || die "no qcow2 image found in $image_dir"
QEMU_ARGS=(
qemu-system-x86_64
-accel "$ACCEL"
-m "$MEMORY"
-smp "$CPUS"
-drive "file=$IMAGE,format=qcow2,snapshot=on"
-nic "user,hostfwd=tcp::${SSH_PORT}-:22"
-nographic
)
# create resized overlay when --disk-size is given
local drive_arg
if [ -n "$disk_size" ]; then
CLEANUP_OVERLAY=$(mktemp -d)
local overlay="$CLEANUP_OVERLAY/overlay.qcow2"
qemu-img create -f qcow2 -b "$(realpath "$image")" -F qcow2 "$overlay" "$disk_size"
drive_arg="file=$overlay,format=qcow2"
else
drive_arg="file=$image,format=qcow2,snapshot=on"
fi
if [ "$ACCEL" != "tcg" ]; then
QEMU_ARGS+=(-cpu host)
fi
local accel="tcg"
[ -r /dev/kvm ] && accel="kvm"
FS_ID=0
for mount_path in "${MOUNTS[@]}"; do
mount_path=$(realpath "$mount_path")
name=$(basename "$mount_path")
tag="m_${name:0:29}"
QEMU_ARGS+=(
-virtfs "local,path=$mount_path,mount_tag=$tag,security_model=none,id=fs${FS_ID}"
)
FS_ID=$((FS_ID + 1))
done
local -a qemu_args=(
qemu-system-x86_64
-accel "$accel"
-m "$memory"
-smp "$cpus"
-drive "$drive_arg"
-nic "user,hostfwd=tcp::${ssh_port}-:22"
-nographic
)
if [ "$CLAUDE" = true ]; then
if [ -z "${CLAUDE_CONFIG_DIR:-}" ]; then
echo "error: --claude requires CLAUDE_CONFIG_DIR to be set"
exit 1
fi
mkdir -p "$CLAUDE_CONFIG_DIR"
claude_dir=$(realpath "$CLAUDE_CONFIG_DIR")
if [ "$accel" != "tcg" ]; then
qemu_args+=(-cpu host)
fi
QEMU_ARGS+=(
-virtfs "local,path=$claude_dir,mount_tag=claude,security_model=none,id=fs${FS_ID}"
)
FS_ID=$((FS_ID + 1))
fi
local fs_id=0 mount_path name tag
for mount_path in "${mounts[@]}"; do
mount_path=$(realpath "$mount_path")
name=$(basename "$mount_path")
tag="m_${name:0:29}"
qemu_args+=(
-virtfs "local,path=$mount_path,mount_tag=$tag,security_model=none,id=fs${fs_id}"
)
fs_id=$((fs_id + 1))
done
exec "${QEMU_ARGS[@]}"
if [ "$claude" = true ]; then
[ -n "${CLAUDE_CONFIG_DIR:-}" ] || die "--claude requires CLAUDE_CONFIG_DIR to be set"
mkdir -p "$CLAUDE_CONFIG_DIR"
local claude_dir
claude_dir=$(realpath "$CLAUDE_CONFIG_DIR")
qemu_args+=(
-virtfs "local,path=$claude_dir,mount_tag=claude,security_model=none,id=fs${fs_id}"
)
fs_id=$((fs_id + 1))
fi
info "---"
info "Accel: $accel | SSH: ssh -p $ssh_port matej@localhost"
info "---"
exec "${qemu_args[@]}"
}
main "$@"

View File

@@ -3,22 +3,22 @@ set -euo pipefail
KEY_DIR="/etc/secrets/initrd"
echo "Generating initrd SSH host keys in $KEY_DIR"
main() {
echo "generating initrd SSH host keys in $KEY_DIR"
sudo mkdir -p "$KEY_DIR"
sudo mkdir -p "$KEY_DIR"
local key_type
for key_type in rsa ed25519; do
local key_file="$KEY_DIR/ssh_host_${key_type}_key"
if [[ ! -f "$key_file" ]]; then
sudo ssh-keygen -t "$key_type" -N "" -f "$key_file"
echo "generated: $key_file"
else
echo "exists: $key_file"
fi
done
if [[ ! -f "$KEY_DIR/ssh_host_rsa_key" ]]; then
sudo ssh-keygen -t rsa -N "" -f "$KEY_DIR/ssh_host_rsa_key"
echo "Generated: $KEY_DIR/ssh_host_rsa_key"
else
echo "Exists: $KEY_DIR/ssh_host_rsa_key"
fi
echo "done. now run nixos-rebuild."
}
if [[ ! -f "$KEY_DIR/ssh_host_ed25519_key" ]]; then
sudo ssh-keygen -t ed25519 -N "" -f "$KEY_DIR/ssh_host_ed25519_key"
echo "Generated: $KEY_DIR/ssh_host_ed25519_key"
else
echo "Exists: $KEY_DIR/ssh_host_ed25519_key"
fi
echo "Done. Now run nixos-rebuild."
main "$@"