Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions cli/test/installer/installer.bats
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,57 @@ FAKEID
# SANDCAT_HOME dir removed since it was empty after cli/ deletion
[ ! -d "$sandcat_home" ]
}

# Runs a shell command under a pseudo-terminal and types $1 on it.
# Stdin is held open briefly because macOS `script` forwards EOF to the
# terminal at once, and it could arrive before the typed answer.
_run_with_tty() {
local answer=$1 cmd=$2
if [ "$(uname)" = "Darwin" ]; then
(printf '%s\n' "$answer"; sleep 2) | script -q /dev/null sh -c "$cmd"
else
(printf '%s\n' "$answer"; sleep 2) | script -q -e -c "$cmd" /dev/null
fi
}

_install_fixture() {
SANDCAT_HOME="$1" \
SANDCAT_BIN_DIR="$2" \
SANDCAT_NON_INTERACTIVE=true \
PATH="$FAKE_BIN:$PATH" bash "$INSTALL_SH"
}

@test "install.sh piped into a shell reads the overwrite answer from the terminal" {
_stub_curl_with_fixture master

local sandcat_home="$BATS_TEST_TMPDIR/home/.local/share/sandcat"
local sandcat_bin="$BATS_TEST_TMPDIR/home/.local/bin"
_install_fixture "$sandcat_home" "$sandcat_bin"
touch "$sandcat_home/cli/stale"

SANDCAT_HOME="$sandcat_home" \
SANDCAT_BIN_DIR="$sandcat_bin" \
PATH="$FAKE_BIN:$PATH" \
run _run_with_tty y "cat '$INSTALL_SH' | sh"
assert_success
assert_output --partial "Overwrite?"
assert_output --partial "Installed sandcat"
[ ! -e "$sandcat_home/cli/stale" ]
}

@test "install.sh piped into a shell keeps the existing install on an empty answer" {
_stub_curl_with_fixture master

local sandcat_home="$BATS_TEST_TMPDIR/home/.local/share/sandcat"
local sandcat_bin="$BATS_TEST_TMPDIR/home/.local/bin"
_install_fixture "$sandcat_home" "$sandcat_bin"
touch "$sandcat_home/cli/stale"

SANDCAT_HOME="$sandcat_home" \
SANDCAT_BIN_DIR="$sandcat_bin" \
PATH="$FAKE_BIN:$PATH" \
run _run_with_tty "" "cat '$INSTALL_SH' | sh"
assert_success
assert_output --partial "Aborted"
[ -e "$sandcat_home/cli/stale" ]
}
8 changes: 5 additions & 3 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ curl -fsSL https://raw.githubusercontent.com/VirtusLab/sandcat/master/install.sh
Ensure `~/.local/bin` is on your `PATH` (the installer prints a hint if it
isn't), then jump to [Initialize the sandbox](getting-started/quickstart.md#2-initialize-the-sandbox-for-your-project).

**Upgrade:** re-run the same command. The installer atomically swaps the
existing install; `~/.config/sandcat/` (user settings) is never touched.
Combine with `SANDCAT_REF` to jump to a different branch/tag/commit:
**Upgrade:** re-run the same command and answer `y` when asked to overwrite
the existing install (set `SANDCAT_NON_INTERACTIVE=true` to skip the
question). The installer atomically swaps the existing install;
`~/.config/sandcat/` (user settings) is never touched. Combine with
`SANDCAT_REF` to jump to a different branch/tag/commit:

```bash
curl -fsSL https://raw.githubusercontent.com/VirtusLab/sandcat/master/install.sh | SANDCAT_REF=v1.0.0 sh
Expand Down
16 changes: 13 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
# SANDCAT_REF branch/tag/commit to install (default: master)
# SANDCAT_NON_INTERACTIVE skip prompts when set to "true" (default: false)

set -euo pipefail
# No pipefail: dash (sh on Debian/Ubuntu) lacks it, and no pipeline here
# relies on it.
set -eu

# --- Logging helpers ---------------------------------------------------------

Expand All @@ -36,8 +38,9 @@ cleanup() {
fi
}

# With set -e, a failing command exits with its status, and the EXIT trap
# then runs cleanup. (An ERR trap would not be portable to dash.)
trap 'cleanup' EXIT
trap 'cleanup; exit 1' ERR

# --- Argument parsing --------------------------------------------------------

Expand Down Expand Up @@ -214,7 +217,14 @@ prompt_yes_no() {
fi
printf '%s [y/N]: ' "$msg" >&2
local reply
IFS= read -r reply || reply=""
# When piped (curl ... | sh), stdin is the script itself, so ask the
# terminal directly. Without one (CI without SANDCAT_NON_INTERACTIVE),
# the answer stays empty and defaults to "no".
if [ -t 0 ]; then
IFS= read -r reply || reply=""
else
{ IFS= read -r reply < /dev/tty; } 2>/dev/null || reply=""
fi
case "$reply" in
y|Y|yes|YES) return 0 ;;
*) return 1 ;;
Expand Down
Loading