- Replace grep -oP (Perl regex) with portable sed — fixes "grep: invalid option -- P" on macOS - Add sedi() wrapper for cross-platform sed -i (BSD vs GNU) - Detect macOS via uname and use apple-darwin binary suffix instead of linux-musl - Add is_native_binary() helper: checks both ELF (Linux) and Mach-O (macOS) - macOS env vars: use launchctl setenv + /etc/codex-env.sh + ~/.zshrc source line - Linux env vars: keep /etc/environment + /etc/profile.d/ as before - Wrapper script uses dynamic ENV_FILE path instead of hardcoded /etc/profile.d/ - Fix SUDO_USER handling for correct ~/.zshrc path when run via sudo - Uninstaller: also remove .codex-bin, /etc/codex-env.sh, launchctl vars, rc file entries - Uninstaller: scan /Users/* on macOS instead of /home/* - Fix CRLF line endings in ucodex_uninstall.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
186 lines
6.4 KiB
Bash
Executable File
186 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
||
#
|
||
# Универсальный скрипт обновления OpenAI Codex CLI
|
||
# Автоматически скачивает последнюю версию с GitHub Releases
|
||
# Использует musl версию для совместимости со старыми системами
|
||
#
|
||
|
||
set -e
|
||
|
||
# Цвета для вывода
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Определяем путь к codex
|
||
CODEX_PATH=$(which codex 2>/dev/null || echo "/usr/local/bin/codex")
|
||
CODEX_DIR=$(dirname "$CODEX_PATH")
|
||
TEMP_DIR="/tmp/codex-update-$$"
|
||
GITHUB_API="https://api.github.com/repos/openai/codex/releases/latest"
|
||
|
||
# Определяем архитектуру - используем musl для совместимости
|
||
ARCH=$(uname -m)
|
||
case "$ARCH" in
|
||
x86_64)
|
||
BINARY_SUFFIX="x86_64-unknown-linux-musl"
|
||
;;
|
||
aarch64|arm64)
|
||
BINARY_SUFFIX="aarch64-unknown-linux-musl"
|
||
;;
|
||
*)
|
||
echo -e "${RED}Неподдерживаемая архитектура: $ARCH${NC}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
echo -e "${BLUE}========================================${NC}"
|
||
echo -e "${BLUE} OpenAI Codex CLI Updater${NC}"
|
||
echo -e "${BLUE}========================================${NC}"
|
||
echo ""
|
||
|
||
# Функция получения текущей версии
|
||
get_current_version() {
|
||
if command -v codex &> /dev/null; then
|
||
local ver=$(codex --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||
if [ -n "$ver" ]; then
|
||
echo "$ver"
|
||
else
|
||
echo "не работает"
|
||
fi
|
||
else
|
||
echo "не установлен"
|
||
fi
|
||
}
|
||
|
||
# Функция получения последней версии с GitHub
|
||
get_latest_version() {
|
||
curl -s "$GITHUB_API" | sed -n 's/.*"tag_name":[[:space:]]*"rust-v\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/p' | head -1
|
||
}
|
||
|
||
# Функция сравнения версий (возвращает 0 если нужно обновление)
|
||
version_gt() {
|
||
test "$(printf '%s\n' "$1" "$2" | sort -V | tail -n 1)" != "$2"
|
||
}
|
||
|
||
# Получаем версии
|
||
echo -e "${YELLOW}Проверка версий...${NC}"
|
||
CURRENT_VERSION=$(get_current_version)
|
||
echo -e "Текущая версия: ${BLUE}$CURRENT_VERSION${NC}"
|
||
|
||
LATEST_VERSION=$(get_latest_version)
|
||
if [ -z "$LATEST_VERSION" ]; then
|
||
echo -e "${RED}Не удалось получить информацию о последней версии${NC}"
|
||
exit 1
|
||
fi
|
||
echo -e "Последняя версия: ${GREEN}$LATEST_VERSION${NC}"
|
||
echo ""
|
||
|
||
# Проверяем нужно ли обновление
|
||
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
|
||
echo -e "${GREEN}✓ Codex уже обновлён до последней версии!${NC}"
|
||
exit 0
|
||
fi
|
||
|
||
# Если текущая не работает или не установлена - всегда обновляем
|
||
if [ "$CURRENT_VERSION" != "не установлен" ] && [ "$CURRENT_VERSION" != "не работает" ]; then
|
||
if ! version_gt "$LATEST_VERSION" "$CURRENT_VERSION"; then
|
||
echo -e "${GREEN}✓ Текущая версия актуальна или новее${NC}"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
echo -e "${YELLOW}Требуется обновление: $CURRENT_VERSION → $LATEST_VERSION${NC}"
|
||
echo ""
|
||
|
||
# Формируем URL для скачивания
|
||
DOWNLOAD_URL="https://github.com/openai/codex/releases/download/rust-v${LATEST_VERSION}/codex-${BINARY_SUFFIX}.tar.gz"
|
||
echo -e "${BLUE}Архитектура: $ARCH (${BINARY_SUFFIX})${NC}"
|
||
echo -e "${BLUE}URL: $DOWNLOAD_URL${NC}"
|
||
echo ""
|
||
|
||
# Создаём временную директорию
|
||
mkdir -p "$TEMP_DIR"
|
||
cd "$TEMP_DIR"
|
||
|
||
# Скачиваем
|
||
echo -e "${YELLOW}Скачивание...${NC}"
|
||
if ! curl -L -# -o codex.tar.gz "$DOWNLOAD_URL"; then
|
||
echo -e "${RED}Ошибка скачивания${NC}"
|
||
rm -rf "$TEMP_DIR"
|
||
exit 1
|
||
fi
|
||
|
||
# Распаковываем
|
||
echo -e "${YELLOW}Распаковка...${NC}"
|
||
tar -xzf codex.tar.gz
|
||
|
||
# Ищем бинарник (может называться codex или codex-$BINARY_SUFFIX)
|
||
BINARY_FILE=""
|
||
if [ -f "codex" ]; then
|
||
BINARY_FILE="codex"
|
||
elif [ -f "codex-${BINARY_SUFFIX}" ]; then
|
||
BINARY_FILE="codex-${BINARY_SUFFIX}"
|
||
else
|
||
# Ищем любой файл начинающийся с codex (исключая .tar.gz)
|
||
BINARY_FILE=$(find . -maxdepth 1 -name 'codex*' -type f ! -name '*.gz' | head -1)
|
||
fi
|
||
|
||
if [ -z "$BINARY_FILE" ] || [ ! -f "$BINARY_FILE" ]; then
|
||
echo -e "${RED}Бинарник codex не найден в архиве${NC}"
|
||
ls -la
|
||
rm -rf "$TEMP_DIR"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}Найден бинарник: $BINARY_FILE${NC}"
|
||
|
||
# Проверяем запущен ли codex и завершаем
|
||
if pgrep -x "codex" > /dev/null; then
|
||
echo -e "${YELLOW}Обнаружен запущенный процесс codex, завершаем...${NC}"
|
||
pkill -9 -x "codex" 2>/dev/null || true
|
||
sleep 1
|
||
echo -e "${GREEN}✓ Процесс завершён${NC}"
|
||
fi
|
||
|
||
# Устанавливаем
|
||
echo -e "${YELLOW}Установка в $CODEX_PATH...${NC}"
|
||
chmod +x "$BINARY_FILE"
|
||
|
||
# Проверяем нужен ли sudo
|
||
if [ -w "$CODEX_DIR" ]; then
|
||
mv -f "$BINARY_FILE" "$CODEX_PATH"
|
||
else
|
||
echo -e "${YELLOW}Требуются права sudo для записи в $CODEX_DIR${NC}"
|
||
sudo mv -f "$BINARY_FILE" "$CODEX_PATH"
|
||
fi
|
||
|
||
# Очистка
|
||
cd /
|
||
rm -rf "$TEMP_DIR"
|
||
|
||
# Обновляем PATH кэш
|
||
hash -r 2>/dev/null || true
|
||
|
||
# Проверяем результат
|
||
echo ""
|
||
NEW_VERSION=$(get_current_version)
|
||
|
||
echo -e "${BLUE}========================================${NC}"
|
||
echo -e "${GREEN}✓ Обновление завершено!${NC}"
|
||
echo -e "${BLUE}========================================${NC}"
|
||
echo -e "Было: ${RED}$CURRENT_VERSION${NC}"
|
||
echo -e "Стало: ${GREEN}$NEW_VERSION${NC}"
|
||
echo ""
|
||
|
||
# Финальная проверка
|
||
if [ "$NEW_VERSION" = "$LATEST_VERSION" ]; then
|
||
echo -e "${GREEN}✓ Версия успешно обновлена до $LATEST_VERSION${NC}"
|
||
elif [ "$NEW_VERSION" = "не работает" ]; then
|
||
echo -e "${RED}✗ Бинарник не запускается! Проверьте зависимости.${NC}"
|
||
ldd "$CODEX_PATH" 2>&1 | grep "not found" || true
|
||
else
|
||
echo -e "${YELLOW}⚠ Версия после установки: $NEW_VERSION (ожидалась $LATEST_VERSION)${NC}"
|
||
fi
|