Skip to main content

SHIM

Constant SHIM 

Source
pub const SHIM: &str = "#!/bin/sh\n# git-templates hook shim \u{2192} the amont binary.\n#\n# One shim serves every hook: it passes its own filename through, so the binary\n# knows which hook to run. Dispatchers (pre-commit, pre-push) and ported leaf\n# hooks use the identical file.\n# Author: https://github.com/fredericrous\n#\n# POSIX sh, not zsh: this must run wherever git does, including Git for Windows\n# (which ships sh but not zsh).\n#\n# Resolution order matters more than it looks. Git hooks do NOT inherit an\n# interactive shell\'s PATH: GUI clients (VS Code, Tower, JetBrains) launch git\n# with an environment that often lacks ~/.local/bin or ~/.cargo/bin. A shim that\n# only did `exec amont` would work in the terminal and fail in the GUI. So:\n#   1. $GIT_HOOKS_BIN   \u{2014} escape hatch; also how `make test` points at target/debug\n#   2. the baked path   \u{2014} an absolute path written into this shim by\n#                         `amont install`. The placeholder token is NOT\n#                         spelled out in this comment: substitution is a plain\n#                         global replace, so a comment containing the token gets\n#                         rewritten too, and the explanation turns into a machine\n#                         path. It did, for as long as this said otherwise.\n#                         ABSOLUTE, and checked for it below before it is used.\n#                         Git runs a hook with the working tree as the current\n#                         directory, so testing an UNSUBSTITUTED token with\n#                         `[ -x ]` asks the REPOSITORY whether it has a file by\n#                         that name \u{2014} and a clone shipping an executable so\n#                         named would then be run here, on the first commit,\n#                         before any check and before any trust decision. The\n#                         unbaked shim is a supported state (3 below), so the\n#                         value has to be rejected outright rather than asked\n#                         about on disk.\n#   3. $HOME/.local/bin \u{2014} the default install location, resolved at RUNTIME so\n#                         this template stays machine-agnostic. Without it, a\n#                         repo created by `git init` from a template dir that is\n#                         the git checkout itself (the usual setup here \u{2014} the\n#                         XDG path symlinks to the repo) never gets that token\n#                         substituted and would depend on PATH after all.\n#                         Both names are tried: Windows builds amont.exe, and\n#                         `[ -x .../amont ]` is false for it \u{2014} which left\n#                         Windows with PATH as its ONLY fallback, in exactly the\n#                         GUI-client case this list exists to survive. Windows\n#                         needs no symlink for any of this: point\n#                         init.templateDir straight at the checkout.\n#   4. PATH             \u{2014} last resort\n# and if none resolve, FAIL LOUDLY. Never skip a check silently: a hook that\n# quietly does nothing is worse than one that is missing.\nset -e\nHOOKS_DIR=$(CDPATH= cd -- \"$(dirname -- \"$0\")\" && pwd)\nHOOK_NAME=$(basename -- \"$0\")\n\n# The baked path, and nothing relative \u{2014} see 2 above. Absolute means POSIX `/\u{2026}`\n# or a Windows drive path: `amont install` bakes `C:\\Users\\\u{2026}\\amont.exe` on\n# Git for Windows. An unbaked shim fails this and falls through to 3, which is\n# exactly what it should do.\nBAKED=\"__AMONT_BIN__\"\ncase \"$BAKED\" in\n    /*|?:/*|?:\\\\*) ;;\n    *) BAKED= ;;\nesac\n\nif [ -n \"$GIT_HOOKS_BIN\" ] && [ -x \"$GIT_HOOKS_BIN\" ]; then\n    BIN=\"$GIT_HOOKS_BIN\"\nelif [ -n \"$BAKED\" ] && [ -x \"$BAKED\" ]; then\n    BIN=\"$BAKED\"\nelif [ -x \"$HOME/.local/bin/amont\" ]; then\n    BIN=\"$HOME/.local/bin/amont\"\nelif [ -x \"$HOME/.local/bin/amont.exe\" ]; then\n    BIN=\"$HOME/.local/bin/amont.exe\"\nelif command -v amont > /dev/null 2>&1; then\n    BIN=amont\nelse\n    printf \'  \\033[38;5;160m\u{2717}\\033[0m amont binary not found \u{2014} hooks cannot run.\\n\' >&2\n    printf \'    Looked at: $GIT_HOOKS_BIN, the baked path, ~/.local/bin, then PATH.\\n\' >&2\n    printf \'    Reinstall with \\033[38;5;208mmake install\\033[0m in git-templates.\\n\' >&2\n    exit 1\nfi\n\nexec \"$BIN\" --hooks-dir \"$HOOKS_DIR\" \"$HOOK_NAME\" \"$@\"\n";
Expand description

The one shim. All four git-invoked hooks are the same file — it passes its own filename through — and shims_on_disk_match_the_embedded_one keeps the repository’s templates/hooks/ honest against this copy.

The canonical text lives INSIDE this crate, and that is a packaging constraint rather than a preference. It used to be include_str!("../../../templates/hooks/pre-commit"), reaching up to the repository root — which works in a checkout and cannot work in a published crate, because cargo package tars up this directory and nothing above it. The tarball compiled nowhere: couldn't read src/../../../templates/hooks/ pre-commit. crates.io is immutable, so that would have been a broken release that could only be yanked, never fixed in place.

The repository’s templates/hooks/ still holds the four installable copies — that directory IS the product for anyone pointing init.templateDir at a clone, and it has to be real files rather than symlinks because Git for Windows materialises those as text files containing a path.