main dotfiles / bin / gen-deps-tags
Eric Bower  ·  2026-09-08
  1#!/usr/bin/env bash
  2set -euo pipefail
  3
  4if ! command -v ctags >/dev/null 2>&1; then
  5  echo "error: ctags not found in PATH" >&2
  6  exit 1
  7fi
  8
  9target=".tags_deps"
 10generated=0
 11
 12# 1. Go modules
 13if [[ -f "go.mod" ]] && command -v go >/dev/null 2>&1; then
 14  echo "Resolving Go dependencies..."
 15  go mod download 2>/dev/null || true
 16  dirs="$(go list -m -f '{{if not .Main}}{{.Dir}}{{end}}' all 2>/dev/null | grep -v '^$' || true)"
 17  if [[ -n "${dirs}" ]]; then
 18    echo "Indexing Go dependencies into ${target}..."
 19    flags=("-f" "${target}" "--languages=Go" "--exclude=testdata")
 20    [[ $generated -eq 1 ]] && flags+=("-a")
 21    echo "${dirs}" | ctags "${flags[@]}" -L -
 22    generated=1
 23  fi
 24fi
 25
 26# 2. Zig dependencies (build.zig.zon)
 27if [[ -f "build.zig.zon" ]]; then
 28  echo "Resolving Zig dependencies..."
 29  cache_p="${ZIG_GLOBAL_CACHE_DIR:-$HOME/.cache/zig}/p"
 30  zig_dirs=()
 31  if [[ -d "${cache_p}" ]]; then
 32    while IFS= read -r hash; do
 33      [[ -z "$hash" ]] && continue
 34      for d in "${cache_p}"/*"${hash}"*; do
 35        if [[ -d "$d" ]]; then
 36          zig_dirs+=("$d")
 37        fi
 38      done
 39    done < <(grep -oE '[0-9a-zA-Z_-]{40,}' build.zig.zon | sort -u)
 40  fi
 41
 42  if [[ -d ".zig-cache/p" ]]; then
 43    for d in .zig-cache/p/*; do
 44      [[ -d "$d" ]] && zig_dirs+=("$d")
 45    done
 46  fi
 47
 48  if [[ ${#zig_dirs[@]} -gt 0 ]]; then
 49    echo "Indexing ${#zig_dirs[@]} Zig dependencies into ${target}..."
 50    flags=("-f" "${target}" "--languages=+Zig")
 51    [[ $generated -eq 1 ]] && flags+=("-a")
 52    printf "%s\n" "${zig_dirs[@]}" | ctags "${flags[@]}" -L -
 53    generated=1
 54  fi
 55fi
 56
 57# 3. Python virtualenv
 58venv_dir=""
 59if [[ -n "${VIRTUAL_ENV:-}" && -d "${VIRTUAL_ENV}" ]]; then
 60  venv_dir="${VIRTUAL_ENV}"
 61elif [[ -d ".venv" ]]; then
 62  venv_dir=".venv"
 63elif [[ -d "venv" ]]; then
 64  venv_dir="venv"
 65fi
 66
 67if [[ -n "${venv_dir}" ]]; then
 68  echo "Resolving Python dependencies from ${venv_dir}..."
 69  sp_dirs=()
 70  for sp in "${venv_dir}"/lib/python*/site-packages; do
 71    [[ -d "$sp" ]] && sp_dirs+=("$sp")
 72  done
 73
 74  if [[ ${#sp_dirs[@]} -gt 0 ]]; then
 75    echo "Indexing Python site-packages into ${target}..."
 76    flags=("-f" "${target}" "--languages=Python" "--exclude=*.dist-info" "--exclude=*.egg-info" "--exclude=*/tests/*" "--exclude=*/test/*")
 77    [[ $generated -eq 1 ]] && flags+=("-a")
 78    ctags "${flags[@]}" "${sp_dirs[@]}"
 79    generated=1
 80  fi
 81fi
 82
 83# 4. TypeScript / Node.js
 84if [[ -f "package.json" && -d "node_modules" ]]; then
 85  echo "Resolving TypeScript / Node dependencies..."
 86  ts_targets=()
 87  if [[ -d "node_modules/@types" ]]; then
 88    ts_targets+=("node_modules/@types")
 89  fi
 90  while IFS= read -r dts; do
 91    [[ -f "$dts" ]] && ts_targets+=("$dts")
 92  done < <(find node_modules -maxdepth 4 -name "*.d.ts" ! -path "*/node_modules/@types/*" 2>/dev/null | head -n 500)
 93
 94  if [[ ${#ts_targets[@]} -gt 0 ]]; then
 95    echo "Indexing TypeScript types into ${target}..."
 96    flags=("-f" "${target}" "--languages=TypeScript,JavaScript" "--exclude=*/test/*" "--exclude=*/tests/*")
 97    [[ $generated -eq 1 ]] && flags+=("-a")
 98    printf "%s\n" "${ts_targets[@]}" | ctags "${flags[@]}" -L -
 99    generated=1
100  fi
101fi
102
103if [[ $generated -eq 1 ]]; then
104  echo "Saved dependency tags to ${target} ($(du -h "${target}" | cut -f1))"
105else
106  echo "No third-party dependencies detected in current directory."
107  exit 1
108fi