|
| 1 | +SHELL := /usr/bin/env bash |
| 2 | +.DEFAULT_GOAL := help |
| 3 | + |
| 4 | +LINUX_ROOT := $(abspath .) |
| 5 | +REPO_ROOT := $(abspath ..) |
| 6 | +NIXOS_DIR := $(abspath NixOS) |
| 7 | +DOTS_DIR := $(abspath dots) |
| 8 | +INSTALLER_DIR := $(abspath installer) |
| 9 | + |
| 10 | +NIX_RUN := nix run --no-write-lock-file nixpkgs\# |
| 11 | + |
| 12 | +NIXFMT := $(NIX_RUN)nixfmt -- |
| 13 | +STATIX := $(NIX_RUN)statix -- |
| 14 | +DEADNIX := $(NIX_RUN)deadnix -- |
| 15 | +SHFMT := $(NIX_RUN)shfmt -- |
| 16 | +STYLUA := $(NIX_RUN)stylua -- |
| 17 | + |
| 18 | +# find -print0 chains keep paths with spaces intact (e.g. NixOS/home/noctalia/.../Catppuccin Lavender/). |
| 19 | +NIX_FIND := find $(NIXOS_DIR) -type f -name '*.nix' -print0 |
| 20 | +SHELL_FIND := find $(DOTS_DIR)/hypr/scripts -type f -name '*.sh' -print0 |
| 21 | +FISH_FIND := find $(DOTS_DIR)/hypr/scripts -type f -name '*.fish' -print0 |
| 22 | +LUA_FIND := find $(DOTS_DIR)/nvim -type f -name '*.lua' -print0 |
| 23 | +JSON_FIND := find $(NIXOS_DIR) $(DOTS_DIR) $(INSTALLER_DIR)/internal/shellruntime -type f -name '*.json' ! -name 'lazy-lock.json' -print0 |
| 24 | + |
| 25 | +##@ Aggregate |
| 26 | + |
| 27 | +.PHONY: lint |
| 28 | +lint: lint-go lint-nix lint-shell lint-json ## Run all linters across go/nix/shell/json |
| 29 | + |
| 30 | +.PHONY: fmt-check |
| 31 | +fmt-check: fmt-check-go fmt-check-nix fmt-check-shell ## Check formatting without writing |
| 32 | + |
| 33 | +.PHONY: fmt |
| 34 | +fmt: fmt-go fmt-nix fmt-shell ## Apply formatting in place across go/nix/shell |
| 35 | + |
| 36 | +.PHONY: test |
| 37 | +test: test-go ## Run all test suites |
| 38 | + |
| 39 | +.PHONY: vuln |
| 40 | +vuln: vuln-go ## Run all vulnerability scanners |
| 41 | + |
| 42 | +.PHONY: ci |
| 43 | +ci: lint fmt-check test vuln ## Full CI pipeline: lint + fmt-check + test + vuln |
| 44 | + |
| 45 | +.PHONY: all |
| 46 | +all: lint test ## Lint + test (fast feedback loop) |
| 47 | + |
| 48 | +##@ Go (installer) |
| 49 | + |
| 50 | +.PHONY: lint-go |
| 51 | +lint-go: ## golangci-lint on Linux/installer |
| 52 | + $(MAKE) -C $(INSTALLER_DIR) lint |
| 53 | + |
| 54 | +.PHONY: lint-go-fix |
| 55 | +lint-go-fix: ## golangci-lint --fix on Linux/installer |
| 56 | + $(MAKE) -C $(INSTALLER_DIR) lint-fix |
| 57 | + |
| 58 | +.PHONY: fmt-go |
| 59 | +fmt-go: ## golangci-lint fmt on Linux/installer |
| 60 | + $(MAKE) -C $(INSTALLER_DIR) fmt |
| 61 | + |
| 62 | +.PHONY: fmt-check-go |
| 63 | +fmt-check-go: ## Check Go formatting without writing |
| 64 | + $(MAKE) -C $(INSTALLER_DIR) fmt-check |
| 65 | + |
| 66 | +.PHONY: vet-go |
| 67 | +vet-go: ## go vet ./... in installer |
| 68 | + $(MAKE) -C $(INSTALLER_DIR) vet |
| 69 | + |
| 70 | +.PHONY: test-go |
| 71 | +test-go: ## Run installer test suite (race detector) |
| 72 | + $(MAKE) -C $(INSTALLER_DIR) test |
| 73 | + |
| 74 | +.PHONY: vuln-go |
| 75 | +vuln-go: ## govulncheck on installer module |
| 76 | + cd $(INSTALLER_DIR) && govulncheck ./... |
| 77 | + |
| 78 | +##@ Nix (NixOS/) |
| 79 | + |
| 80 | +.PHONY: lint-nix |
| 81 | +lint-nix: lint-nix-statix lint-nix-deadnix ## statix + deadnix |
| 82 | + |
| 83 | +.PHONY: lint-nix-statix |
| 84 | +lint-nix-statix: ## statix anti-pattern check |
| 85 | + $(STATIX) check $(NIXOS_DIR) |
| 86 | + |
| 87 | +.PHONY: lint-nix-deadnix |
| 88 | +lint-nix-deadnix: ## deadnix dead-code check (fails on findings) |
| 89 | + $(DEADNIX) --fail $(NIXOS_DIR) |
| 90 | + |
| 91 | +.PHONY: fmt-nix |
| 92 | +fmt-nix: ## nixfmt across NixOS/ |
| 93 | + @$(NIX_FIND) | xargs -0 -r $(NIXFMT) |
| 94 | + |
| 95 | +.PHONY: fmt-check-nix |
| 96 | +fmt-check-nix: ## nixfmt --check across NixOS/ |
| 97 | + @$(NIX_FIND) | xargs -0 -r $(NIXFMT) --check |
| 98 | + |
| 99 | +.PHONY: nix-syntax |
| 100 | +nix-syntax: ## Parse all .nix files for syntax errors |
| 101 | + @count=0; while IFS= read -r -d '' f; do \ |
| 102 | + nix-instantiate --parse "$$f" >/dev/null || { echo "FAIL: $$f"; exit 1; }; \ |
| 103 | + count=$$((count+1)); \ |
| 104 | + done < <($(NIX_FIND)); \ |
| 105 | + echo "nix-syntax: $$count .nix files parsed cleanly" |
| 106 | + |
| 107 | +.PHONY: nix-flake-check |
| 108 | +nix-flake-check: ## Run nix flake check (full eval) |
| 109 | + cd $(NIXOS_DIR) && nix flake check --no-write-lock-file |
| 110 | + |
| 111 | +.PHONY: nix-build |
| 112 | +nix-build: ## Delegate to installer Makefile nix-build target |
| 113 | + $(MAKE) -C $(INSTALLER_DIR) nix-build |
| 114 | + |
| 115 | +##@ Dotfiles (shell, fish, lua, json) |
| 116 | + |
| 117 | +.PHONY: lint-shell |
| 118 | +lint-shell: lint-shell-bash lint-shell-fish ## shellcheck + fish -n |
| 119 | + |
| 120 | +.PHONY: lint-shell-bash |
| 121 | +lint-shell-bash: ## bash -n syntax + shellcheck -x (CWD=repo root for source= follow) |
| 122 | + @$(SHELL_FIND) | xargs -0 -r -n1 bash -n |
| 123 | + @cd $(REPO_ROOT) && find Linux/dots/hypr/scripts -type f -name '*.sh' -print0 | xargs -0 -r shellcheck -x |
| 124 | + |
| 125 | +.PHONY: lint-shell-fish |
| 126 | +lint-shell-fish: ## fish -n on dots/hypr/scripts/*.fish |
| 127 | + @$(FISH_FIND) | xargs -0 -r -n1 fish -n |
| 128 | + |
| 129 | +.PHONY: fmt-shell |
| 130 | +fmt-shell: ## shfmt -w on dots/hypr/scripts/*.sh |
| 131 | + @$(SHELL_FIND) | xargs -0 -r $(SHFMT) -w -i 2 -ci |
| 132 | + |
| 133 | +.PHONY: fmt-check-shell |
| 134 | +fmt-check-shell: ## shfmt -d (diff) on dots/hypr/scripts/*.sh |
| 135 | + @$(SHELL_FIND) | xargs -0 -r $(SHFMT) -d -i 2 -ci |
| 136 | + |
| 137 | +.PHONY: lint-lua |
| 138 | +lint-lua: ## stylua --check on Neovim config (optional) |
| 139 | + @if $(LUA_FIND) | grep -qz .; then $(STYLUA) --check $(DOTS_DIR)/nvim; fi |
| 140 | + |
| 141 | +.PHONY: fmt-lua |
| 142 | +fmt-lua: ## stylua write on Neovim config |
| 143 | + @if $(LUA_FIND) | grep -qz .; then $(STYLUA) $(DOTS_DIR)/nvim; fi |
| 144 | + |
| 145 | +.PHONY: lint-json |
| 146 | +lint-json: ## jq empty on every JSON in NixOS/, dots/, installer manifests |
| 147 | + @count=0; while IFS= read -r -d '' f; do \ |
| 148 | + jq empty "$$f" >/dev/null || { echo "FAIL: $$f"; exit 1; }; \ |
| 149 | + count=$$((count+1)); \ |
| 150 | + done < <($(JSON_FIND)); \ |
| 151 | + echo "lint-json: $$count .json files parse cleanly" |
| 152 | + |
| 153 | +.PHONY: lint-python |
| 154 | +lint-python: ## python ast.parse on tracked patch sources |
| 155 | + @python3 -c 'import ast, pathlib; ast.parse(pathlib.Path("$(NIXOS_DIR)/home/end4/patches/quickshell.py").read_text())' |
| 156 | + |
| 157 | +##@ Project-wide checks |
| 158 | + |
| 159 | +.PHONY: shell-contracts |
| 160 | +shell-contracts: ## Hypr keybind/profile contract tests |
| 161 | + $(MAKE) -C $(INSTALLER_DIR) hypr-bind-check |
| 162 | + |
| 163 | +.PHONY: full-check |
| 164 | +full-check: ## Mirror installer/Makefile check target (full local CI) |
| 165 | + $(MAKE) -C $(INSTALLER_DIR) check |
| 166 | + |
| 167 | +##@ Help |
| 168 | + |
| 169 | +.PHONY: help |
| 170 | +help: ## Show this help |
| 171 | + @awk 'BEGIN{FS=":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} \ |
| 172 | + /^[a-zA-Z0-9_-]+:.*?##/ {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2} \ |
| 173 | + /^##@/ {printf "\n\033[1m%s\033[0m\n", substr($$0, 5)}' $(MAKEFILE_LIST) |
0 commit comments