| #!/bin/bash |
| set -e |
| set -u |
| set -o pipefail |
|
|
| |
| RED='\033[0;31m' |
| GREEN='\033[0;32m' |
| YELLOW='\033[1;33m' |
| BLUE='\033[0;34m' |
| NC='\033[0m' |
|
|
| |
| log_info() { |
| echo -e "${GREEN}[INFO]${NC} $1" |
| } |
|
|
| log_error() { |
| echo -e "${RED}[ERROR]${NC} $1" >&2 |
| } |
|
|
| log_warn() { |
| echo -e "${YELLOW}[WARN]${NC} $1" |
| } |
|
|
| log_debug() { |
| echo -e "${BLUE}[DEBUG]${NC} $1" |
| } |
|
|
| |
| cleanup() { |
| local exit_code=$? |
| if [ $exit_code -ne 0 ]; then |
| log_error "Installation failed with exit code $exit_code" |
| fi |
| exit $exit_code |
| } |
|
|
| trap cleanup EXIT |
|
|
| |
| detect_os() { |
| log_info "Detecting operating system..." |
| |
| if [[ "$OSTYPE" == "linux-gnu"* ]]; then |
| if [ -f /etc/os-release ]; then |
| . /etc/os-release |
| OS_NAME=$ID |
| OS_VERSION=$VERSION_ID |
| log_info "Detected: $NAME $VERSION_ID" |
| elif [ -f /etc/lsb-release ]; then |
| . /etc/lsb-release |
| OS_NAME=$DISTRIB_ID |
| OS_VERSION=$DISTRIB_RELEASE |
| log_info "Detected: $DISTRIB_ID $DISTRIB_RELEASE" |
| else |
| OS_NAME="linux" |
| OS_VERSION="unknown" |
| log_warn "Could not determine specific Linux distribution" |
| fi |
| elif [[ "$OSTYPE" == "darwin"* ]]; then |
| OS_NAME="macos" |
| OS_VERSION=$(sw_vers -productVersion) |
| log_info "Detected: macOS $OS_VERSION" |
| elif [[ "$OSTYPE" == "freebsd"* ]]; then |
| OS_NAME="freebsd" |
| OS_VERSION=$(freebsd-version) |
| log_info "Detected: FreeBSD $OS_VERSION" |
| else |
| log_error "Unsupported operating system: $OSTYPE" |
| exit 1 |
| fi |
| } |
|
|
| |
| check_root_if_needed() { |
| if [[ "$OS_NAME" == "ubuntu" ]] || [[ "$OS_NAME" == "debian" ]] || [[ "$OS_NAME" == "linuxmint" ]] || [[ "$OS_NAME" == "kali" ]]; then |
| if [ "$EUID" -ne 0 ]; then |
| log_error "This script requires root privileges for apt. Please run with sudo." |
| exit 1 |
| fi |
| elif [[ "$OS_NAME" == "fedora" ]] || [[ "$OS_NAME" == "rhel" ]] || [[ "$OS_NAME" == "centos" ]] || [[ "$OS_NAME" == "rocky" ]] || [[ "$OS_NAME" == "almalinux" ]]; then |
| if [ "$EUID" -ne 0 ]; then |
| log_error "This script requires root privileges for dnf/yum. Please run with sudo." |
| exit 1 |
| fi |
| elif [[ "$OS_NAME" == "arch" ]] || [[ "$OS_NAME" == "manjaro" ]]; then |
| if [ "$EUID" -ne 0 ]; then |
| log_error "This script requires root privileges for pacman. Please run with sudo." |
| exit 1 |
| fi |
| fi |
| } |
|
|
| |
| update_packages() { |
| log_info "Updating package manager..." |
| |
| case "$OS_NAME" in |
| ubuntu|debian|linuxmint|kali|pop) |
| if ! apt update; then |
| log_error "Failed to update apt package lists" |
| exit 1 |
| fi |
| ;; |
| fedora|rhel|centos|rocky|almalinux) |
| if command -v dnf &> /dev/null; then |
| if ! dnf check-update; then |
| |
| if [ $? -ne 100 ]; then |
| log_warn "dnf check-update returned non-standard exit code" |
| fi |
| fi |
| else |
| if ! yum check-update; then |
| if [ $? -ne 100 ]; then |
| log_warn "yum check-update returned non-standard exit code" |
| fi |
| fi |
| fi |
| ;; |
| arch|manjaro) |
| if ! pacman -Syu; then |
| log_error "Failed to update pacman database" |
| exit 1 |
| fi |
| ;; |
| macos) |
| if command -v brew &> /dev/null; then |
| log_info "Updating Homebrew..." |
| brew update |
| else |
| log_warn "Homebrew not installed. Skipping package manager update." |
| fi |
| ;; |
| *) |
| log_warn "Unknown package manager for $OS_NAME. Skipping update." |
| ;; |
| esac |
| } |
|
|
| |
| install_git() { |
| if ! command -v git &> /dev/null; then |
| log_info "Installing git..." |
| |
| case "$OS_NAME" in |
| ubuntu|debian|linuxmint|kali|pop) |
| if ! apt install git -y; then |
| log_error "Failed to install git" |
| exit 1 |
| fi |
| ;; |
| fedora|rhel|centos|rocky|almalinux) |
| if command -v dnf &> /dev/null; then |
| if ! dnf install git -y; then |
| log_error "Failed to install git" |
| exit 1 |
| fi |
| else |
| if ! yum install git -y; then |
| log_error "Failed to install git" |
| exit 1 |
| fi |
| fi |
| ;; |
| arch|manjaro) |
| if ! pacman -S git --noconfirm; then |
| log_error "Failed to install git" |
| exit 1 |
| fi |
| ;; |
| macos) |
| if command -v brew &> /dev/null; then |
| if ! brew install git; then |
| log_error "Failed to install git" |
| exit 1 |
| fi |
| else |
| log_error "Homebrew is required for macOS. Install from https://brew.sh/" |
| exit 1 |
| fi |
| ;; |
| *) |
| log_error "Don't know how to install git on $OS_NAME" |
| exit 1 |
| ;; |
| esac |
| else |
| log_info "Git is already installed ($(git --version))" |
| fi |
| } |
|
|
| |
| detect_os |
|
|
| |
| check_root_if_needed |
|
|
| log_info "Starting installation process..." |
|
|
| |
| update_packages |
|
|
| |
| install_git |
|
|
| |
| if ! command -v uv &> /dev/null; then |
| log_info "Installing uv package manager..." |
| if ! curl -Ls https://astral.sh/uv/install.sh | sh; then |
| log_error "Failed to install uv" |
| exit 1 |
| fi |
| |
| |
| if [ -f "$HOME/.local/bin/env" ]; then |
| source "$HOME/.local/bin/env" |
| elif [ -f "$HOME/.cargo/env" ]; then |
| source "$HOME/.cargo/env" |
| fi |
| |
| |
| if ! command -v uv &> /dev/null; then |
| log_error "uv installation failed - command not found after install" |
| exit 1 |
| fi |
| else |
| log_info "uv is already installed" |
| fi |
|
|
| |
| log_info "Checking project directory..." |
| if [ -f "./web.py" ]; then |
| log_info "Already in target directory" |
| elif [ -f "./gcli2api/web.py" ]; then |
| log_info "Changing to gcli2api directory" |
| cd ./gcli2api || exit 1 |
| else |
| log_info "Cloning repository..." |
| if [ -d "./gcli2api" ]; then |
| log_warn "gcli2api directory exists but web.py not found. Removing and re-cloning..." |
| rm -rf ./gcli2api |
| fi |
| |
| if ! git clone https://github.com/su-kaka/gcli2api.git; then |
| log_error "Failed to clone repository" |
| exit 1 |
| fi |
| |
| cd ./gcli2api || exit 1 |
| fi |
|
|
| |
| if [ -d ".git" ]; then |
| log_info "Updating repository..." |
| if ! git pull; then |
| log_warn "Git pull failed, continuing anyway..." |
| fi |
| else |
| log_warn "Not a git repository, skipping update" |
| fi |
|
|
| |
| log_info "Creating relocatable virtual environment..." |
| export UV_VENV_CLEAR=1 |
| if ! uv venv --relocatable; then |
| log_error "Failed to create virtual environment" |
| exit 1 |
| fi |
|
|
| |
| log_info "Syncing dependencies with uv..." |
| if ! uv sync; then |
| log_error "Failed to sync dependencies" |
| exit 1 |
| fi |
|
|
| |
| log_info "Activating virtual environment..." |
| if [ -f ".venv/bin/activate" ]; then |
| source .venv/bin/activate |
| else |
| log_error "Virtual environment not found at .venv/bin/activate" |
| exit 1 |
| fi |
|
|
| |
| if ! command -v python3 &> /dev/null; then |
| log_error "python3 not found in virtual environment" |
| exit 1 |
| fi |
|
|
| |
| if [ ! -f "web.py" ]; then |
| log_error "web.py not found in current directory" |
| exit 1 |
| fi |
|
|
| |
| log_info "Starting application..." |
| python3 web.py |