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
16 changes: 16 additions & 0 deletions changelog.d/unreleased/1751.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 1751
affected:
- install.sh
- tests/CodeIndex.Tests/InstallScriptTests.cs
---

## English

- **The installer now verifies the installed binary before reporting success (#1751)** — `install.sh` runs `cdidx --version`, checks that the installed version matches the requested release, and reports likely architecture or native-runtime problems before printing the success path.

## 日本語

- **インストーラーが成功報告前にインストール済みバイナリを検証するようになりました (#1751)** — `install.sh` は `cdidx --version` を実行し、インストールされたバージョンが要求リリースと一致することを確認し、成功扱いにする前に architecture や native runtime の問題候補を表示します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/1766.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 1766
affected:
- install.sh
- tests/CodeIndex.Tests/InstallScriptTests.cs
---

## English

- **The installer now preflights temporary storage before `mktemp` use (#1766)** — `install.sh` checks that `TMPDIR` is a writable directory with at least 100 MiB free and warns when it appears to be mounted `noexec`.

## 日本語

- **インストーラーが `mktemp` 使用前に一時領域を事前検査するようになりました (#1766)** — `install.sh` は `TMPDIR` が書き込み可能なディレクトリで 100 MiB 以上の空き容量を持つことを確認し、`noexec` mount と思われる場合は警告します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2011.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2011
affected:
- install.sh
- tests/CodeIndex.Tests/InstallScriptTests.cs
---

## English

- **The installer can now update shell profiles for PATH setup on opt-in (#2011)** — users can rerun with `CDIDX_INSTALL_UPDATE_PATH=1` to append the installer PATH export to the detected shell profile and make the new path active for the installer process.

## 日本語

- **インストーラーが opt-in で shell profile の PATH 設定を更新できるようになりました (#2011)** — `CDIDX_INSTALL_UPDATE_PATH=1` を付けて再実行すると、検出した shell profile に installer の PATH export を追記し、インストーラー処理内でも新しい PATH を有効化します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2014.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2014
affected:
- install.sh
- tests/CodeIndex.Tests/InstallScriptTests.cs
---

## English

- **The installer now warns when an older `cdidx` shadows the new install on PATH (#2014)** — `check_path` resolves the active binary, lists every `cdidx` found on PATH with versions, and points users to put the install directory first.

## 日本語

- **古い `cdidx` が PATH 上で新しいインストールを shadow している場合に警告するようになりました (#2014)** — `check_path` は有効なバイナリを解決し、PATH 上の全 `cdidx` とバージョンを一覧表示して、インストール先ディレクトリを先頭に置くよう案内します。
188 changes: 188 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,54 @@ need_cmd() {
fi
}

temp_root() {
printf '%s' "${TMPDIR:-/tmp}"
}

probe_temp_root() {
local root
root="$(temp_root)"

if [ ! -d "$root" ]; then
error "TMPDIR not usable: ${root} is not a directory. Set TMPDIR to a writable directory with at least 100 MiB free."
fi

local probe
if ! probe="$(mktemp "${root%/}/.cdidx-install-probe.XXXXXX")"; then
error "TMPDIR not writable: ${root}. Set TMPDIR to a writable directory and rerun the installer."
fi
rm -f "$probe"

local free_kb=""
if command -v df > /dev/null 2>&1; then
free_kb="$(df -Pk "$root" 2>/dev/null | awk 'NR==2 {print $4}' || true)"
fi

if [ -n "$free_kb" ] && [ "$free_kb" -lt 102400 ] 2>/dev/null; then
error "Insufficient temp space in ${root}: ${free_kb} KiB available; need at least 102400 KiB. Set TMPDIR to a larger writable directory."
fi

if command -v mount > /dev/null 2>&1 && mount 2>/dev/null | awk -v root="$root" '
index($0, " on " root " ") && index($0, "noexec") { found = 1 }
END { exit found ? 0 : 1 }
'; then
warn "TMPDIR appears to be on a noexec filesystem: ${root}. The installer will avoid executing staged files from TMPDIR."
fi
}

verify_temp_path_space() {
local path="$1"
local free_kb=""

if command -v df > /dev/null 2>&1; then
free_kb="$(df -Pk "$path" 2>/dev/null | awk 'NR==2 {print $4}' || true)"
fi

if [ -n "$free_kb" ] && [ "$free_kb" -lt 102400 ] 2>/dev/null; then
error "Insufficient temp space for ${path}: ${free_kb} KiB available; need at least 102400 KiB."
fi
}

acquire_install_lock() {
mkdir -p "$INSTALL_DIR"

Expand Down Expand Up @@ -228,6 +276,39 @@ semver_ge() {
}'
}

verify_cdidx_binary() {
local binary_path="$1"
local expected_version="${VERSION#v}"
local version_output=""
local actual_version=""

if [ ! -x "$binary_path" ]; then
report_error "Installed binary is not executable: ${binary_path}."
return 1
fi

if ! version_output="$("$binary_path" --version 2>&1)"; then
report_error "Installed binary failed to run: ${binary_path} --version."
report_error "Output: ${version_output}"
report_error "Likely causes include a wrong-architecture release asset or missing native runtime dependency next to the binary."
return 1
fi

actual_version="$(semver_core "$version_output")"
if [ -z "$actual_version" ]; then
report_error "Installed binary returned an unparsable version from ${binary_path}: ${version_output}"
return 1
fi

if [ -n "$expected_version" ] && [ "$actual_version" != "$expected_version" ]; then
report_error "Installed binary version mismatch at ${binary_path}: expected ${expected_version}, got ${actual_version}."
report_error "Check for a stale release archive, wrong architecture, or PATH shadowing by an older cdidx."
return 1
fi

return 0
}

extract_release_tag_name() {
local api_response="$1"
local version=""
Expand Down Expand Up @@ -403,10 +484,12 @@ curl_http_get() {
local http_code
local curl_stderr

probe_temp_root
if ! curl_stderr="$(mktemp)"; then
report_error "Failed to create temporary curl stderr capture while fetching ${source_label} at $url."
return 1
fi
verify_temp_path_space "$curl_stderr"

if http_code="$(run_curl_with_optional_loopback_bypass "$url" -sSL -o "$output_path" -w '%{http_code}' "$url" 2>"$curl_stderr")"; then
rm -f "$curl_stderr"
Expand Down Expand Up @@ -457,9 +540,11 @@ fetch_latest_release_version() {
api_url="$(latest_release_api_url)"
api_label="$(latest_release_api_diagnostic_label)"
local response_file
probe_temp_root
if ! response_file="$(mktemp)"; then
error "Failed to create temporary file for latest-release lookup."
fi
verify_temp_path_space "$response_file"

local http_code
if ! http_code="$(curl_http_get "$api_url" "$response_file" "$api_label")"; then
Expand Down Expand Up @@ -884,6 +969,7 @@ download_and_install() {
need_cmd curl
need_cmd tar
need_cmd mktemp
need_cmd awk

local archive_name="CodeIndex-${RID}.tar.gz"
local base_url
Expand All @@ -892,9 +978,11 @@ download_and_install() {
local checksums_url="${base_url}/sha256sums.txt"

local tmpdir
probe_temp_root
if ! tmpdir="$(mktemp -d)"; then
error "Failed to create temporary working directory for install."
fi
verify_temp_path_space "$tmpdir"
TMPDIR_CLEANUP="$tmpdir"

info "Downloading ${archive_name}..."
Expand Down Expand Up @@ -1016,6 +1104,9 @@ download_and_install() {
done
write_integrity_version_json "${stage_dir}/version.json"
chmod +x "${stage_dir}/${BINARY_NAME}"
if ! verify_cdidx_binary "${stage_dir}/${BINARY_NAME}"; then
return 1
fi

local backup_dir
if ! backup_dir="$(mktemp -d "${INSTALL_DIR}/.cdidx-backup.XXXXXX")"; then
Expand All @@ -1029,6 +1120,10 @@ download_and_install() {
if ! promote_staged_install "$stage_dir" "$backup_dir" "$INSTALL_DIR" "$required_files" "$staged_assets"; then
return 1
fi
chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
if ! verify_cdidx_binary "${INSTALL_DIR}/${BINARY_NAME}"; then
return 1
fi

rm -rf "$stage_dir"
STAGE_DIR_CLEANUP=""
Expand All @@ -1040,11 +1135,74 @@ download_and_install() {

# --- PATH guidance / PATHガイダンス ---

active_cdidx_path() {
command -v "$BINARY_NAME" 2>/dev/null || true
}

list_path_cdidx_binaries() {
local old_ifs="$IFS"
local dir
IFS=:
for dir in ${PATH:-}; do
[ -n "$dir" ] || dir="."
if [ -x "${dir}/${BINARY_NAME}" ]; then
printf '%s\n' "${dir}/${BINARY_NAME}"
fi
done
IFS="$old_ifs"
}

print_path_cdidx_versions() {
local binary
list_path_cdidx_binaries | while IFS= read -r binary; do
[ -n "$binary" ] || continue
printf ' %s -> %s\n' "$binary" "$("$binary" --version 2>/dev/null || printf '%s' "unavailable")"
done
}

candidate_shell_profile() {
local shell_name
shell_name="$(basename "${SHELL:-/bin/bash}")"
case "$shell_name" in
zsh) printf '%s' "${HOME}/.zshrc" ;;
bash)
if [ -f "${HOME}/.bash_profile" ]; then
printf '%s' "${HOME}/.bash_profile"
else
printf '%s' "${HOME}/.bashrc"
fi
;;
*) printf '%s' "${HOME}/.profile" ;;
esac
}

append_path_to_shell_profile() {
local profile_path
profile_path="$(candidate_shell_profile)"
mkdir -p "$(dirname "$profile_path")"

if [ -f "$profile_path" ] && grep -F "export PATH=\"${INSTALL_DIR}:\$PATH\"" "$profile_path" >/dev/null 2>&1; then
info "PATH export already present in ${profile_path}"
return 0
fi

{
printf '\n# Added by cdidx installer\n'
printf 'export PATH="%s:$PATH"\n' "$INSTALL_DIR"
} >> "$profile_path"

info "Added ${INSTALL_DIR} to PATH in ${profile_path}"
}

check_path() {
if [ "${SELF_TEST_LOCAL_MIRROR:-0}" = "1" ]; then
return 0
fi

local installed_bin="${INSTALL_DIR}/${BINARY_NAME}"
local active_bin
active_bin="$(active_cdidx_path)"

case ":${PATH}:" in
*":${INSTALL_DIR}:"*) ;;
*)
Expand Down Expand Up @@ -1073,6 +1231,36 @@ check_path() {
echo ""
;;
esac

if [ "${CDIDX_INSTALL_UPDATE_PATH:-0}" = "1" ]; then
append_path_to_shell_profile
case ":${PATH}:" in
*":${INSTALL_DIR}:"*) ;;
*) PATH="${INSTALL_DIR}:${PATH}"; export PATH ;;
esac
else
echo " To let the installer update your shell profile, rerun with CDIDX_INSTALL_UPDATE_PATH=1."
echo ""
fi

active_bin="$(active_cdidx_path)"
if [ -n "$active_bin" ] && [ "$active_bin" != "$installed_bin" ]; then
warn "The active cdidx on PATH is ${active_bin}, not the newly installed ${installed_bin}."
warn "An earlier PATH entry is shadowing the new install."
echo ""
echo " cdidx binaries found on PATH:"
print_path_cdidx_versions
echo ""
echo " Put ${INSTALL_DIR} before the earlier directory in PATH, or rerun with CDIDX_INSTALL_UPDATE_PATH=1."
echo ""
return 0
fi

if [ -n "$active_bin" ]; then
if ! "$active_bin" --version >/dev/null 2>&1; then
warn "The active cdidx at ${active_bin} failed to run --version. Check architecture and native runtime assets."
fi
fi
}

report_local_mirror_start_failure() {
Expand Down
Loading
Loading