## Summary - add a direct install script for macOS and Linux at `scripts/install/install.sh` - stage `install.sh` into `dist/` during release so it is published as a GitHub release asset - reuse the existing platform npm payload so the installer includes both `codex` and `rg` ## Testing - `bash -n scripts/install/install.sh` - local macOS `curl | sh` smoke test against a locally served copy of the script
244 lines
4.9 KiB
Bash
Executable file
244 lines
4.9 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
set -eu
|
|
|
|
VERSION="${1:-latest}"
|
|
INSTALL_DIR="${CODEX_INSTALL_DIR:-$HOME/.local/bin}"
|
|
path_action="already"
|
|
path_profile=""
|
|
|
|
step() {
|
|
printf '==> %s\n' "$1"
|
|
}
|
|
|
|
normalize_version() {
|
|
case "$1" in
|
|
"" | latest)
|
|
printf 'latest\n'
|
|
;;
|
|
rust-v*)
|
|
printf '%s\n' "${1#rust-v}"
|
|
;;
|
|
v*)
|
|
printf '%s\n' "${1#v}"
|
|
;;
|
|
*)
|
|
printf '%s\n' "$1"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
download_file() {
|
|
url="$1"
|
|
output="$2"
|
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl -fsSL "$url" -o "$output"
|
|
return
|
|
fi
|
|
|
|
if command -v wget >/dev/null 2>&1; then
|
|
wget -q -O "$output" "$url"
|
|
return
|
|
fi
|
|
|
|
echo "curl or wget is required to install Codex." >&2
|
|
exit 1
|
|
}
|
|
|
|
download_text() {
|
|
url="$1"
|
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl -fsSL "$url"
|
|
return
|
|
fi
|
|
|
|
if command -v wget >/dev/null 2>&1; then
|
|
wget -q -O - "$url"
|
|
return
|
|
fi
|
|
|
|
echo "curl or wget is required to install Codex." >&2
|
|
exit 1
|
|
}
|
|
|
|
add_to_path() {
|
|
path_action="already"
|
|
path_profile=""
|
|
|
|
case ":$PATH:" in
|
|
*":$INSTALL_DIR:"*)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
profile="$HOME/.profile"
|
|
case "${SHELL:-}" in
|
|
*/zsh)
|
|
profile="$HOME/.zshrc"
|
|
;;
|
|
*/bash)
|
|
profile="$HOME/.bashrc"
|
|
;;
|
|
esac
|
|
|
|
path_profile="$profile"
|
|
path_line="export PATH=\"$INSTALL_DIR:\$PATH\""
|
|
if [ -f "$profile" ] && grep -F "$path_line" "$profile" >/dev/null 2>&1; then
|
|
path_action="configured"
|
|
return
|
|
fi
|
|
|
|
{
|
|
printf '\n# Added by Codex installer\n'
|
|
printf '%s\n' "$path_line"
|
|
} >>"$profile"
|
|
path_action="added"
|
|
}
|
|
|
|
release_url_for_asset() {
|
|
asset="$1"
|
|
resolved_version="$2"
|
|
|
|
printf 'https://github.com/openai/codex/releases/download/rust-v%s/%s\n' "$resolved_version" "$asset"
|
|
}
|
|
|
|
require_command() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "$1 is required to install Codex." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
require_command mktemp
|
|
require_command tar
|
|
|
|
resolve_version() {
|
|
normalized_version="$(normalize_version "$VERSION")"
|
|
|
|
if [ "$normalized_version" != "latest" ]; then
|
|
printf '%s\n' "$normalized_version"
|
|
return
|
|
fi
|
|
|
|
release_json="$(download_text "https://api.github.com/repos/openai/codex/releases/latest")"
|
|
resolved="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name":[[:space:]]*"rust-v\([^"]*\)".*/\1/p' | head -n 1)"
|
|
|
|
if [ -z "$resolved" ]; then
|
|
echo "Failed to resolve the latest Codex release version." >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf '%s\n' "$resolved"
|
|
}
|
|
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
os="darwin"
|
|
;;
|
|
Linux)
|
|
os="linux"
|
|
;;
|
|
*)
|
|
echo "install.sh supports macOS and Linux. Use install.ps1 on Windows." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$(uname -m)" in
|
|
x86_64 | amd64)
|
|
arch="x86_64"
|
|
;;
|
|
arm64 | aarch64)
|
|
arch="aarch64"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $(uname -m)" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if [ "$os" = "darwin" ] && [ "$arch" = "x86_64" ]; then
|
|
if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || true)" = "1" ]; then
|
|
arch="aarch64"
|
|
fi
|
|
fi
|
|
|
|
if [ "$os" = "darwin" ]; then
|
|
if [ "$arch" = "aarch64" ]; then
|
|
npm_tag="darwin-arm64"
|
|
vendor_target="aarch64-apple-darwin"
|
|
platform_label="macOS (Apple Silicon)"
|
|
else
|
|
npm_tag="darwin-x64"
|
|
vendor_target="x86_64-apple-darwin"
|
|
platform_label="macOS (Intel)"
|
|
fi
|
|
else
|
|
if [ "$arch" = "aarch64" ]; then
|
|
npm_tag="linux-arm64"
|
|
vendor_target="aarch64-unknown-linux-musl"
|
|
platform_label="Linux (ARM64)"
|
|
else
|
|
npm_tag="linux-x64"
|
|
vendor_target="x86_64-unknown-linux-musl"
|
|
platform_label="Linux (x64)"
|
|
fi
|
|
fi
|
|
|
|
if [ -x "$INSTALL_DIR/codex" ]; then
|
|
install_mode="Updating"
|
|
else
|
|
install_mode="Installing"
|
|
fi
|
|
|
|
step "$install_mode Codex CLI"
|
|
step "Detected platform: $platform_label"
|
|
|
|
resolved_version="$(resolve_version)"
|
|
asset="codex-npm-$npm_tag-$resolved_version.tgz"
|
|
download_url="$(release_url_for_asset "$asset" "$resolved_version")"
|
|
|
|
step "Resolved version: $resolved_version"
|
|
|
|
tmp_dir="$(mktemp -d)"
|
|
cleanup() {
|
|
rm -rf "$tmp_dir"
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
archive_path="$tmp_dir/$asset"
|
|
|
|
step "Downloading Codex CLI"
|
|
download_file "$download_url" "$archive_path"
|
|
|
|
tar -xzf "$archive_path" -C "$tmp_dir"
|
|
|
|
step "Installing to $INSTALL_DIR"
|
|
mkdir -p "$INSTALL_DIR"
|
|
cp "$tmp_dir/package/vendor/$vendor_target/codex/codex" "$INSTALL_DIR/codex"
|
|
cp "$tmp_dir/package/vendor/$vendor_target/path/rg" "$INSTALL_DIR/rg"
|
|
chmod 0755 "$INSTALL_DIR/codex"
|
|
chmod 0755 "$INSTALL_DIR/rg"
|
|
|
|
add_to_path
|
|
|
|
case "$path_action" in
|
|
added)
|
|
step "PATH updated for future shells in $path_profile"
|
|
step "Run now: export PATH=\"$INSTALL_DIR:\$PATH\" && codex"
|
|
step "Or open a new terminal and run: codex"
|
|
;;
|
|
configured)
|
|
step "PATH is already configured for future shells in $path_profile"
|
|
step "Run now: export PATH=\"$INSTALL_DIR:\$PATH\" && codex"
|
|
step "Or open a new terminal and run: codex"
|
|
;;
|
|
*)
|
|
step "$INSTALL_DIR is already on PATH"
|
|
step "Run: codex"
|
|
;;
|
|
esac
|
|
|
|
printf 'Codex CLI %s installed successfully.\n' "$resolved_version"
|