#!/usr/bin/env bash #ddev-generated # Keep the add-on's own artifacts out of git, in every project it is installed in. # # Rewrites a marker-delimited block in the project's .git/info/exclude. That file is # per-clone and never committed, and every git process honours it -- unlike # core.excludesfile, which is set on the container's git config only and so does # nothing for git run from the host. Called by install.sh, which runs on "ddev start" # and on every "ddev claude", so the list refreshes itself as the add-on changes. # # Personal patterns (.DS_Store, .idea, CLAUDE.md, ...) are deliberately NOT here: # they belong in ~/.gitignore_global, not to this add-on. set -uo pipefail BEGIN='# >>> ddev-claude-cli >>>' END='# <<< ddev-claude-cli <<<' # Block written by this add-on before it was renamed from ddev-codex-claude-cli; removed on sight. LEGACY_BEGIN='# >>> ddev-codex-claude-cli >>>' LEGACY_END='# <<< ddev-codex-claude-cli <<<' PATTERNS=( '.ddev/addon-metadata/ddev-claude-cli/' '.ddev/config.claude-cli.yaml' '.ddev/commands/web/claude' '.ddev/commands/web/claude-swap' '.ddev/commands/web/claude-refs' '.ddev/commands/host/claude-browser' '.ddev/docker-compose.claude-browser.yaml' '.ddev/claude-code/' '.ddev/claude-refs.txt' '.ddev/plans/' '.ddev/codex-cli/' # legacy: left behind by add-on versions that shipped Codex CLI ) approot="${DDEV_APPROOT:-$(pwd)}" # --git-common-dir resolves a worktree's .git file to the real directory. Anything # that is not a git checkout is not an error: ddev start must never fail over this. gitdir="$(git -C "${approot}" rev-parse --git-common-dir 2>/dev/null)" || exit 0 [ -n "${gitdir}" ] || exit 0 case "${gitdir}" in /*) ;; *) gitdir="${approot}/${gitdir}" ;; esac [ -d "${gitdir}" ] || exit 0 info="${gitdir}/info" exclude="${info}/exclude" mkdir -p "${info}" 2>/dev/null || exit 0 [ -e "${exclude}" ] || : >"${exclude}" 2>/dev/null || exit 0 [ -w "${exclude}" ] || exit 0 block="$( printf '%s\n' "${BEGIN}" printf '%s\n' "# Managed by .ddev/claude-code/git-exclude.sh. Edits inside this block are lost." printf '%s\n' "${PATTERNS[@]}" printf '%s\n' "${END}" )" # Drop the pre-rename block first, then replace the current block in place or # append it after a blank line. current="$(awk -v begin="${LEGACY_BEGIN}" -v end="${LEGACY_END}" ' index($0, begin) == 1 { skip = 1; next } skip && index($0, end) == 1 { skip = 0; eat = 1; next } eat && $0 == "" { eat = 0; next } { eat = 0 } !skip { print } ' "${exclude}")" if grep -qF "${BEGIN}" <<<"${current}" && grep -qF "${END}" <<<"${current}"; then updated="$(awk -v begin="${BEGIN}" -v end="${END}" -v block="${block}" ' index($0, begin) == 1 { print block; skip = 1; next } skip && index($0, end) == 1 { skip = 0; next } !skip { print } ' <<<"${current}")" else updated="$(printf '%s' "${current}"; [ -n "${current}" ] && printf '\n\n'; printf '%s\n' "${block}")" fi # Only write on a real change, so "ddev start" does not touch the mtime every time. # cat > rather than mv: the file may be bind-mounted. if [ "${updated}" != "$(cat "${exclude}")" ]; then printf '%s\n' "${updated}" >"${exclude}" || exit 0 fi