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
42 changes: 22 additions & 20 deletions mole
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ resolve_mole_source_path() {
[[ -n "$mole_path" ]] && printf '%s\n' "$mole_path"
}

resolve_current_mole_path() {
local mole_path
mole_path=$(resolve_mole_source_path || true)
[[ -n "$mole_path" ]] || return 1
printf '%s\n' "$mole_path"
}

is_homebrew_mole_path() {
local mole_path="$1"
local has_brew="$2"
Expand Down Expand Up @@ -164,31 +171,19 @@ is_homebrew_mole_path() {
return 1
}

# Install detection (Homebrew vs manual).
# Default path checks only the active script, keeping source-tree commands fast.
# Pass --include-path when update/remove flows intentionally need to inspect
# an installed `mole` found through PATH.
# Install detection follows the invoked Mole script, not PATH.
is_homebrew_install() {
local include_path_lookup="${1:-}"
local has_brew=false
if command -v brew > /dev/null 2>&1; then
has_brew=true
fi

local mole_path
mole_path=$(resolve_mole_source_path || true)
mole_path=$(resolve_current_mole_path || true)
if is_homebrew_mole_path "$mole_path" "$has_brew"; then
return 0
fi

if [[ "$include_path_lookup" == "--include-path" ]]; then
local path_mole
path_mole=$(command -v mole 2> /dev/null || true)
if [[ -n "$path_mole" && "$path_mole" != "$mole_path" ]] && is_homebrew_mole_path "$path_mole" "$has_brew"; then
return 0
fi
fi

return 1
}

Expand Down Expand Up @@ -391,7 +386,7 @@ update_mole() {
}
trap '_update_cleanup; update_interrupted=true; echo ""; exit 130' INT TERM

if is_homebrew_install --include-path; then
if is_homebrew_install; then
if [[ "$nightly_update" == "true" ]]; then
local review_icon="${ICON_REVIEW:-☞}"
log_error "Nightly update is only available for script installations. Homebrew installs follow stable releases."
Expand All @@ -402,6 +397,18 @@ update_mole() {
exit 0
fi

local mole_path
if ! mole_path=$(resolve_current_mole_path); then
log_error "Unable to resolve current Mole path"
exit 1
fi

local install_dir
if ! install_dir="$(cd "$(dirname "$mole_path")" && pwd)"; then
log_error "Unable to resolve current Mole install directory"
exit 1
fi

local latest=""
local download_label="Downloading latest version..."
local install_label="Installing update..."
Expand Down Expand Up @@ -500,11 +507,6 @@ update_mole() {
if [[ -t 1 ]]; then stop_inline_spinner; fi
chmod +x "$tmp_installer"

local mole_path
mole_path="$(command -v mole 2> /dev/null || echo "$0")"
local install_dir
install_dir="$(cd "$(dirname "$mole_path")" && pwd)"

local requires_sudo="false"
if [[ ! -w "$install_dir" ]]; then
requires_sudo="true"
Expand Down
169 changes: 169 additions & 0 deletions tests/update.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#!/usr/bin/env bats

setup_file() {
PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)"
export PROJECT_ROOT
}

setup() {
HOME="$(mktemp -d "${BATS_TEST_DIRNAME}/tmp-update-home.XXXXXX")"
TEST_ROOT="$(mktemp -d "${BATS_TEST_DIRNAME}/tmp-update-case.XXXXXX")"
export HOME TEST_ROOT
}

teardown() {
case "${HOME:-}" in
"${BATS_TEST_DIRNAME}/tmp-update-home."*) rm -rf "$HOME" ;;
esac
case "${TEST_ROOT:-}" in
"${BATS_TEST_DIRNAME}/tmp-update-case."*) rm -rf "$TEST_ROOT" ;;
esac
}

make_manual_mole_install() {
local install_dir="$1"
local config_dir="$2"
local version="$3"
mkdir -p "$install_dir" "$config_dir"
sed \
-e "s|^SCRIPT_DIR=.*|SCRIPT_DIR=\"$config_dir\"|" \
-e "s/^VERSION=\".*\"$/VERSION=\"$version\"/" \
"$PROJECT_ROOT/mole" > "$install_dir/mole"
cp "$PROJECT_ROOT/mo" "$install_dir/mo"
cp -R "$PROJECT_ROOT/lib" "$config_dir/lib"
chmod +x "$install_dir/mole" "$install_dir/mo"
}

make_homebrew_shadow() {
local bin_dir="$1"
local cellar_mole="$2"
mkdir -p "$bin_dir" "$(dirname "$cellar_mole")"
cp "$PROJECT_ROOT/mole" "$cellar_mole"
cp -R "$PROJECT_ROOT/lib" "$bin_dir/lib"
chmod +x "$cellar_mole"
ln -sf "$cellar_mole" "$bin_dir/mole"
ln -sf "$cellar_mole" "$bin_dir/mo"

cat > "$bin_dir/brew" <<'SCRIPT'
#!/usr/bin/env bash
printf '%s\n' "$*" >> "$BREW_LOG"
case "${1:-}" in
list)
if [[ "${2:-}" == "--versions" ]]; then
printf 'mole 9.9.9\n'
fi
exit 0
;;
update | upgrade)
exit 0
;;
esac
exit 0
SCRIPT
chmod +x "$bin_dir/brew"
}

make_update_curl_stub() {
local bin_dir="$1"
local latest_version="$2"
cat > "$bin_dir/curl" <<SCRIPT
#!/usr/bin/env bash
out=""
url=""
while [[ \$# -gt 0 ]]; do
case "\$1" in
-o)
out="\$2"
shift 2
;;
http*://*)
url="\$1"
shift
;;
*)
shift
;;
esac
done
[[ -n "\$url" ]] && printf '%s\n' "\$url" >> "\$CURL_URL_LOG"

if [[ -n "\$out" ]]; then
cat > "\$out" <<'INSTALLER'
#!/usr/bin/env bash
printf '%s\n' "\$*" > "\$INSTALLER_ARGS_LOG"
printf '%s\n' "\${MOLE_VERSION:-}" > "\$INSTALLER_VERSION_LOG"
echo "Updated to latest version, \${MOLE_VERSION#V}"
INSTALLER
exit 0
fi

if [[ "\$url" == *"api.github.com"* ]]; then
printf '{"tag_name":"%s"}\n' "$latest_version"
exit 0
fi

printf 'VERSION="%s"\n' "$latest_version"
SCRIPT
chmod +x "$bin_dir/curl"
}

@test "mo update targets the invoked manual install, not another Homebrew mole in PATH" {
local manual_bin="$TEST_ROOT/manual/bin"
local manual_config="$TEST_ROOT/manual/config"
local fake_brew_bin="$TEST_ROOT/homebrew/bin"
local fake_brew_mole="$TEST_ROOT/homebrew/Cellar/mole/9.9.9/bin/mole"
local brew_log="$TEST_ROOT/brew.log"
local installer_args_log="$TEST_ROOT/installer.args"
local installer_version_log="$TEST_ROOT/installer.version"
local curl_url_log="$TEST_ROOT/curl.urls"
local current_version
local stale_version="0.0.1"

current_version="$(sed -n 's/^VERSION="\([^"]*\)"$/\1/p' "$PROJECT_ROOT/mole" | head -1)"
make_manual_mole_install "$manual_bin" "$manual_config" "$stale_version"
make_homebrew_shadow "$fake_brew_bin" "$fake_brew_mole"
make_update_curl_stub "$fake_brew_bin" "$current_version"
: > "$brew_log"
: > "$curl_url_log"

run env \
HOME="$HOME" \
PATH="$fake_brew_bin:/usr/bin:/bin" \
BREW_LOG="$brew_log" \
CURL_URL_LOG="$curl_url_log" \
INSTALLER_ARGS_LOG="$installer_args_log" \
INSTALLER_VERSION_LOG="$installer_version_log" \
"$manual_bin/mo" update

[ "$status" -eq 0 ]
[ -f "$installer_args_log" ]
grep -q -- "--prefix" "$installer_args_log"
grep -q -- "$manual_bin" "$installer_args_log"
[ "$(cat "$installer_version_log")" = "V$current_version" ]
grep -q "raw.githubusercontent.com/tw93/mole/V${current_version#V}/install.sh" "$curl_url_log"
if grep -q "raw.githubusercontent.com/tw93/mole/main/install.sh" "$curl_url_log"; then
return 1
fi
if grep -q '^upgrade mole$' "$brew_log"; then
return 1
fi
}

@test "mo update keeps Homebrew installs on the Homebrew update path" {
local fake_brew_bin="$TEST_ROOT/homebrew/bin"
local fake_brew_mole="$TEST_ROOT/homebrew/Cellar/mole/9.9.9/bin/mole"
local brew_log="$TEST_ROOT/brew.log"

make_homebrew_shadow "$fake_brew_bin" "$fake_brew_mole"
: > "$brew_log"

run env \
HOME="$HOME" \
PATH="$fake_brew_bin:/usr/bin:/bin" \
BREW_LOG="$brew_log" \
"$fake_brew_bin/mo" update

[ "$status" -eq 0 ]
grep -q '^update$' "$brew_log"
grep -q '^upgrade mole$' "$brew_log"
}
Loading