#!/bin/sh # `cf` on PATH, backed by whichever labs checkout you are standing in. # # Shell completion is why this exists: the function `cf completion bash|zsh` # installs calls `cf completion complete` by name on every Tab, so completion # is silently dead for anyone without a `cf` on PATH — including for # `deno task cf `, since the same function services the `deno` binding. # # Pick it up with `deno task install-cf`, which copies this file to a directory # on PATH: that needs no binary built, and one copy serves every checkout. # # Runs from source, so it never goes stale against the checkout. `dist/cf` is # deliberately not used here — see "Why not dist/cf" in packages/cli/README.md. set -e # Which labs checkout to run, in precedence order: # # 1. $CF_LABS_ROOT, if set — an explicit override for when the cwd cannot # say what you mean (working on a pattern in /tmp, say). A value that is # not a checkout is an error, not a quiet fall-through to something else. # 2. The nearest checkout walking up from $PWD, so a symlinked install does # not pin `cf` to the checkout it was installed from. Several checkouts # coexisting is normal here — a vendored labs inside another repo is a # supported, tested layout (see packages/cli/test/launcher.test.ts). # 3. A default chosen when this file was installed, then the checkout this # file physically lives in — for when you are not standing in one at all. # An installed copy carries the default; the in-repo file and any symlink # to it fall through to their own checkout. Neither applies while you are # inside a checkout, which is the overwhelmingly common case. # # Route 2 is what lets one installed copy serve every checkout: the copy has no # checkout of its own, and the directory you stand in decides. # Rewritten by scripts/install-cf.sh when it installs a copy. Empty here: the # in-repo file is reached through a checkout by definition. DEFAULT_LABS_ROOT="" is_labs_checkout() { [ -f "${1}/packages/cli/launcher.ts" ] } # First match walking up wins. A directory is checked as a checkout before it # is checked as a vendoring host, so standing inside `/vendor/labs` # selects that labs rather than walking up and re-deriving it from the host. resolve_from_cwd() { dir=$PWD while :; do if is_labs_checkout "${dir}"; then printf '%s\n' "${dir}" return 0 fi if is_labs_checkout "${dir}/vendor/labs"; then printf '%s\n' "${dir}/vendor/labs" return 0 fi parent=$(dirname "${dir}") # dirname("/") is "/" — stop rather than spin. [ "${parent}" = "${dir}" ] && return 1 dir=$parent done } # Resolve through symlinks so a linked install reports the checkout rather than # the link. `readlink -f` is GNU and newer-macOS only, so the links are walked # by hand to keep this working on a stock macOS shell. An installed copy is not # a link and lands on its own directory, which is not a checkout — that is what # DEFAULT_LABS_ROOT is for. script_checkout() { target=$0 while [ -L "${target}" ]; do link=$(readlink "${target}") case ${link} in /*) target=$link ;; *) target=$(dirname "${target}")/$link ;; esac done (CDPATH= cd -- "$(dirname -- "${target}")/.." && pwd -P) } # Last resort, in order: the root chosen at install time, then this file's own # checkout. Both are skipped unless they really are checkouts, so a stale # install-time default cannot silently send you somewhere that no longer exists. fallback_root() { if [ -n "${DEFAULT_LABS_ROOT}" ] && is_labs_checkout "${DEFAULT_LABS_ROOT}"; then printf '%s\n' "${DEFAULT_LABS_ROOT}" return 0 fi own=$(script_checkout) if is_labs_checkout "${own}"; then printf '%s\n' "${own}" return 0 fi return 1 } if [ -n "${CF_LABS_ROOT:-}" ]; then root=$CF_LABS_ROOT reason="CF_LABS_ROOT" if ! is_labs_checkout "${root}"; then echo "cf: CF_LABS_ROOT is not a labs checkout: ${root}" >&2 echo " (expected ${root}/packages/cli/launcher.ts to exist)" >&2 exit 2 fi elif root=$(resolve_from_cwd); then reason="nearest checkout above the current directory" elif root=$(fallback_root); then reason="fallback (not inside a checkout)" else echo "cf: no labs checkout found." >&2 echo " Not inside one, and this install has no usable default." >&2 echo " cd into a checkout, set CF_LABS_ROOT, or re-run 'deno task install-cf'." >&2 exit 2 fi # Answered by the wrapper, never forwarded: the question is which CLI would run, # so handing it to that CLI would beg it. Only as the first argument, so it # cannot swallow a `which` meant as a value for some other command. # # stdout is the checkout, because that is the part that varies and what the # question is really about — the entry inside it is always the same file. The # entry and the reason go to stderr, matching the CLI's output conventions, so # stdout stays a bare path a script can consume. if [ "${1:-}" = "which" ]; then entry="${root}/packages/cli/mod.ts" printf '%s\n' "${root}" # The checkout test above only proves launcher.ts is there. The entry the # launcher then runs is a separate file, and reporting a path without # checking it would make `which` assert something it has not verified — # the one thing a diagnostic command must not do. if [ ! -f "${entry}" ]; then echo "cf: entry ${entry} does not exist — this checkout is incomplete" >&2 echo "cf: selected by ${reason}" >&2 exit 1 fi echo "cf: entry ${entry}" >&2 echo "cf: selected by ${reason}" >&2 exit 0 fi if ! command -v deno >/dev/null 2>&1; then echo "cf: deno not found on PATH." >&2 echo " Install it with mise (\`mise install\` in ${root}) or directly:" >&2 echo " https://docs.deno.com/runtime/getting_started/installation/" >&2 exit 127 fi # `--cwd "$PWD"` because the launcher otherwise prefers an inherited INIT_CWD, # which is stale whenever `cf` is called from inside a `deno task`. `--` keeps # launcher option parsing off the user's own arguments (`cf --config …`). exec deno run --allow-run --allow-env --allow-read \ "${root}/packages/cli/launcher.ts" --cwd "$PWD" -- "$@"