498 lines
15 KiB
Bash
Executable File
498 lines
15 KiB
Bash
Executable File
#!/bin/bash
|
|
# Memvid Installer for macOS and Linux
|
|
# v1 - System package managers only, install-if-missing
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Print success message
|
|
print_success() {
|
|
echo -e "${GREEN}✔${NC} $1"
|
|
}
|
|
|
|
# Print error message
|
|
print_error() {
|
|
echo -e "${RED}✖${NC} $1"
|
|
}
|
|
|
|
# Print info message
|
|
print_info() {
|
|
echo -e "${BLUE}→${NC} $1"
|
|
}
|
|
|
|
# Print warning message
|
|
print_warning() {
|
|
echo -e "${YELLOW}⚠${NC} $1"
|
|
}
|
|
|
|
# Detect OS
|
|
detect_os() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
OS="macos"
|
|
PKG_MANAGER="brew"
|
|
|
|
# Check if Homebrew is installed
|
|
if ! command_exists brew; then
|
|
print_error "Homebrew is not installed"
|
|
print_info "Please install Homebrew first:"
|
|
print_info " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
exit 1
|
|
fi
|
|
elif [[ -f /etc/os-release ]]; then
|
|
. /etc/os-release
|
|
DISTRO_NAME="${PRETTY_NAME:-${NAME:-$ID}}"
|
|
|
|
if [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]]; then
|
|
OS="linux"
|
|
PKG_MANAGER="apt"
|
|
DISTRO_FAMILY="debian"
|
|
elif [[ "$ID" == "fedora" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "centos" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]]; then
|
|
OS="linux"
|
|
PKG_MANAGER="dnf"
|
|
DISTRO_FAMILY="rhel"
|
|
elif [[ "$ID" == "arch" ]] || [[ "$ID" == "manjaro" ]]; then
|
|
OS="linux"
|
|
PKG_MANAGER="pacman"
|
|
DISTRO_FAMILY="arch"
|
|
elif [[ "$ID" == "alpine" ]]; then
|
|
OS="linux"
|
|
PKG_MANAGER="apk"
|
|
DISTRO_FAMILY="alpine"
|
|
else
|
|
print_error "Unsupported Linux distribution: $ID"
|
|
print_info "Supported distributions: Ubuntu, Debian, Fedora, RHEL, CentOS, Arch, Alpine"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if sudo is available (except for Alpine which might use su)
|
|
if ! command_exists sudo && [[ "$DISTRO_FAMILY" != "alpine" ]]; then
|
|
print_error "sudo is not available"
|
|
print_info "Please install sudo or run as root"
|
|
exit 1
|
|
fi
|
|
else
|
|
print_error "Unable to detect operating system"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$OS" == "linux" ]]; then
|
|
print_info "Detected OS: $OS ($DISTRO_NAME)"
|
|
else
|
|
print_info "Detected OS: $OS"
|
|
fi
|
|
}
|
|
|
|
# Check if command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Check for Xcode Command Line Tools on macOS
|
|
check_xcode_cli_tools() {
|
|
if [[ "$OS" != "macos" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Check if Xcode CLI Tools are installed
|
|
if xcode-select -p &>/dev/null; then
|
|
print_success "Xcode Command Line Tools already installed"
|
|
return 0
|
|
else
|
|
print_error "Xcode Command Line Tools not found"
|
|
print_warning "Xcode Command Line Tools are required for everything to work properly"
|
|
echo ""
|
|
|
|
# Ask for confirmation
|
|
if [[ -t 0 ]] && [[ -t 1 ]]; then
|
|
read -p "Install Xcode Command Line Tools now? [Y/n] " -n 1 -r
|
|
echo
|
|
elif [[ -c /dev/tty ]]; then
|
|
read -p "Install Xcode Command Line Tools now? [Y/n] " -n 1 -r < /dev/tty
|
|
echo
|
|
else
|
|
REPLY="Y"
|
|
fi
|
|
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ ! $REPLY == "" ]]; then
|
|
print_error "Xcode Command Line Tools are required for everything to work properly"
|
|
print_info "Please install them manually with: xcode-select --install"
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Installing Xcode Command Line Tools..."
|
|
xcode-select --install
|
|
|
|
print_info "Please complete the Xcode Command Line Tools installation in the popup window"
|
|
print_info "Then run this installer again"
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
# Install system dependencies for Linux
|
|
install_system_deps() {
|
|
if [[ "$OS" != "linux" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
print_info "Checking system dependencies..."
|
|
|
|
NEEDS_DEPS=false
|
|
DEPS_TO_INSTALL=()
|
|
|
|
# Check and collect missing dependencies
|
|
if [[ "$DISTRO_FAMILY" == "debian" ]]; then
|
|
if ! dpkg -l | grep -q "^ii.*ca-certificates"; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("ca-certificates")
|
|
fi
|
|
if ! command_exists curl; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("curl")
|
|
fi
|
|
if ! dpkg -l | grep -q "^ii.*libssl3"; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("libssl3")
|
|
fi
|
|
elif [[ "$DISTRO_FAMILY" == "rhel" ]]; then
|
|
if ! rpm -q ca-certificates &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("ca-certificates")
|
|
fi
|
|
if ! command_exists curl; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("curl")
|
|
fi
|
|
if ! rpm -q openssl &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("openssl")
|
|
fi
|
|
elif [[ "$DISTRO_FAMILY" == "arch" ]]; then
|
|
if ! pacman -Q ca-certificates &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("ca-certificates")
|
|
fi
|
|
if ! command_exists curl; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("curl")
|
|
fi
|
|
if ! pacman -Q openssl &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("openssl")
|
|
fi
|
|
elif [[ "$DISTRO_FAMILY" == "alpine" ]]; then
|
|
if ! apk info -e ca-certificates &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("ca-certificates")
|
|
fi
|
|
if ! command_exists curl; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("curl")
|
|
fi
|
|
if ! apk info -e openssl &>/dev/null; then
|
|
NEEDS_DEPS=true
|
|
DEPS_TO_INSTALL+=("openssl")
|
|
fi
|
|
fi
|
|
|
|
if [[ "$NEEDS_DEPS" == false ]]; then
|
|
print_success "All system dependencies are installed"
|
|
return 0
|
|
fi
|
|
|
|
print_info "Installing system dependencies: ${DEPS_TO_INSTALL[*]}..."
|
|
|
|
if [[ "$DISTRO_FAMILY" == "debian" ]]; then
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends "${DEPS_TO_INSTALL[@]}"
|
|
elif [[ "$DISTRO_FAMILY" == "rhel" ]]; then
|
|
sudo dnf install -y "${DEPS_TO_INSTALL[@]}"
|
|
elif [[ "$DISTRO_FAMILY" == "arch" ]]; then
|
|
sudo pacman -S --noconfirm "${DEPS_TO_INSTALL[@]}"
|
|
elif [[ "$DISTRO_FAMILY" == "alpine" ]]; then
|
|
if command_exists sudo; then
|
|
sudo apk add --no-cache "${DEPS_TO_INSTALL[@]}"
|
|
else
|
|
apk add --no-cache "${DEPS_TO_INSTALL[@]}"
|
|
fi
|
|
fi
|
|
|
|
print_success "System dependencies installed successfully"
|
|
}
|
|
|
|
# Check for git
|
|
check_git() {
|
|
if command_exists git; then
|
|
GIT_VERSION=$(git --version | cut -d' ' -f3)
|
|
print_success "git already installed (version $GIT_VERSION)"
|
|
return 0
|
|
else
|
|
print_error "git not found"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check for node
|
|
check_node() {
|
|
if command_exists node; then
|
|
NODE_VERSION=$(node --version)
|
|
print_success "node already installed ($NODE_VERSION)"
|
|
|
|
# Check if it's LTS (rough check - version should be even major version)
|
|
MAJOR_VERSION=$(echo "$NODE_VERSION" | cut -d'v' -f2 | cut -d'.' -f1)
|
|
if [ "$((MAJOR_VERSION % 2))" -eq 0 ]; then
|
|
print_info "Node version appears to be LTS-compatible"
|
|
fi
|
|
|
|
# Check for npm
|
|
if command_exists npm; then
|
|
NPM_VERSION=$(npm --version)
|
|
print_success "npm already installed (version $NPM_VERSION)"
|
|
return 0
|
|
else
|
|
print_error "npm not found (should come with node)"
|
|
return 1
|
|
fi
|
|
else
|
|
print_error "node not found"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Install git
|
|
install_git() {
|
|
print_info "Installing git using $PKG_MANAGER..."
|
|
|
|
if [[ "$OS" == "macos" ]]; then
|
|
brew install git
|
|
elif [[ "$OS" == "linux" ]]; then
|
|
if [[ "$DISTRO_FAMILY" == "debian" ]]; then
|
|
sudo apt-get update
|
|
sudo apt-get install -y git
|
|
elif [[ "$DISTRO_FAMILY" == "rhel" ]]; then
|
|
sudo dnf install -y git
|
|
elif [[ "$DISTRO_FAMILY" == "arch" ]]; then
|
|
sudo pacman -S --noconfirm git
|
|
elif [[ "$DISTRO_FAMILY" == "alpine" ]]; then
|
|
if command_exists sudo; then
|
|
sudo apk add --no-cache git
|
|
else
|
|
apk add --no-cache git
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if command_exists git; then
|
|
print_success "git installed successfully"
|
|
else
|
|
print_error "git installation failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Install node (LTS)
|
|
install_node() {
|
|
print_info "Installing node (LTS) using $PKG_MANAGER..."
|
|
|
|
if [[ "$OS" == "macos" ]]; then
|
|
brew install node@lts
|
|
# Add to PATH if needed
|
|
if ! command_exists node; then
|
|
print_info "Adding node to PATH..."
|
|
# Detect Homebrew prefix (Apple Silicon vs Intel)
|
|
if [[ -d "/opt/homebrew" ]]; then
|
|
BREW_PREFIX="/opt/homebrew"
|
|
else
|
|
BREW_PREFIX="/usr/local"
|
|
fi
|
|
|
|
# Detect shell
|
|
if [[ "$SHELL" == *"zsh"* ]]; then
|
|
SHELL_RC="$HOME/.zshrc"
|
|
else
|
|
SHELL_RC="$HOME/.bash_profile"
|
|
fi
|
|
|
|
echo "export PATH=\"$BREW_PREFIX/opt/node@lts/bin:\$PATH\"" >> "$SHELL_RC"
|
|
export PATH="$BREW_PREFIX/opt/node@lts/bin:$PATH"
|
|
fi
|
|
elif [[ "$OS" == "linux" ]]; then
|
|
if [[ "$DISTRO_FAMILY" == "debian" ]]; then
|
|
# Install Node.js LTS from NodeSource
|
|
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
|
sudo apt-get install -y --no-install-recommends nodejs
|
|
elif [[ "$DISTRO_FAMILY" == "rhel" ]]; then
|
|
# Install Node.js LTS from NodeSource
|
|
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo -E bash -
|
|
sudo dnf install -y nodejs
|
|
elif [[ "$DISTRO_FAMILY" == "arch" ]]; then
|
|
sudo pacman -S --noconfirm nodejs npm
|
|
elif [[ "$DISTRO_FAMILY" == "alpine" ]]; then
|
|
if command_exists sudo; then
|
|
sudo apk add --no-cache nodejs npm
|
|
else
|
|
apk add --no-cache nodejs npm
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if command_exists node && command_exists npm; then
|
|
NODE_VERSION=$(node --version)
|
|
NPM_VERSION=$(npm --version)
|
|
print_success "node installed successfully ($NODE_VERSION)"
|
|
print_success "npm installed successfully (version $NPM_VERSION)"
|
|
else
|
|
print_error "node installation failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Check if memvid is already installed
|
|
check_memvid() {
|
|
if command_exists memvid; then
|
|
# Get version - output format is "memvid 2.0.131"
|
|
MEMVID_VERSION=$(memvid --version 2>&1 | awk '{print $2}')
|
|
print_success "memvid already installed ($MEMVID_VERSION)"
|
|
return 0
|
|
else
|
|
print_error "memvid not found"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Install missing tools
|
|
install_missing() {
|
|
NEEDS_GIT=false
|
|
NEEDS_NODE=false
|
|
NEEDS_MEMVID=false
|
|
|
|
if ! check_git; then
|
|
NEEDS_GIT=true
|
|
fi
|
|
|
|
if ! check_node; then
|
|
NEEDS_NODE=true
|
|
fi
|
|
|
|
if ! check_memvid; then
|
|
NEEDS_MEMVID=true
|
|
fi
|
|
|
|
if [[ "$NEEDS_GIT" == false ]] && [[ "$NEEDS_NODE" == false ]] && [[ "$NEEDS_MEMVID" == false ]]; then
|
|
print_info "All dependencies are already installed"
|
|
return 0
|
|
fi
|
|
|
|
# Show what will be installed
|
|
echo ""
|
|
print_warning "The following tools will be installed:"
|
|
[[ "$NEEDS_GIT" == true ]] && echo " - git"
|
|
[[ "$NEEDS_NODE" == true ]] && echo " - node (LTS)"
|
|
[[ "$NEEDS_MEMVID" == true ]] && echo " - memvid-cli (latest)"
|
|
echo ""
|
|
|
|
# Ask for confirmation
|
|
# Read from /dev/tty to ensure it works when piped via curl | bash
|
|
if [[ -t 0 ]] && [[ -t 1 ]]; then
|
|
# Interactive terminal - read normally
|
|
read -p "Continue? [Y/n] " -n 1 -r
|
|
echo
|
|
elif [[ -c /dev/tty ]]; then
|
|
# Piped input - read from terminal device
|
|
read -p "Continue? [Y/n] " -n 1 -r < /dev/tty
|
|
echo
|
|
else
|
|
# No terminal available - proceed automatically (non-interactive mode)
|
|
print_info "No terminal detected, proceeding with installation..."
|
|
REPLY="Y"
|
|
fi
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ ! $REPLY == "" ]]; then
|
|
print_info "Installation cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
# Install missing tools
|
|
[[ "$NEEDS_GIT" == true ]] && install_git
|
|
[[ "$NEEDS_NODE" == true ]] && install_node
|
|
[[ "$NEEDS_MEMVID" == true ]] && install_memvid
|
|
}
|
|
|
|
# Install memvid
|
|
install_memvid() {
|
|
print_info "Installing memvid globally..."
|
|
|
|
if [[ "$OS" == "linux" ]]; then
|
|
# Linux requires sudo for global npm installs
|
|
if sudo npm install -g memvid-cli@latest; then
|
|
print_success "memvid installed successfully"
|
|
else
|
|
print_error "memvid installation failed"
|
|
exit 1
|
|
fi
|
|
else
|
|
# macOS typically doesn't need sudo if npm was installed via Homebrew
|
|
if npm install -g memvid-cli@latest; then
|
|
print_success "memvid installed successfully"
|
|
else
|
|
print_error "memvid installation failed"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Verify installation
|
|
verify() {
|
|
print_info "Verifying installation..."
|
|
|
|
if command_exists memvid; then
|
|
# Get version - output format is "memvid 2.0.131"
|
|
MEMVID_VERSION=$(memvid --version 2>&1 | awk '{print $2}')
|
|
|
|
print_success "memvid is installed and accessible"
|
|
print_info "Version: $MEMVID_VERSION"
|
|
echo ""
|
|
print_success "Installation complete! You can now use 'memvid' command."
|
|
else
|
|
print_error "memvid verification failed"
|
|
print_info "The installation may have completed, but 'memvid' command is not in PATH"
|
|
print_info "Please check your npm global bin directory and add it to PATH if needed"
|
|
print_info "Or try: npm list -g memvid-cli"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
echo "Memvid Installer"
|
|
echo "Checking system requirements…"
|
|
echo ""
|
|
|
|
detect_os
|
|
echo ""
|
|
|
|
# Check Xcode CLI Tools on macOS
|
|
if [[ "$OS" == "macos" ]]; then
|
|
check_xcode_cli_tools
|
|
echo ""
|
|
fi
|
|
|
|
# Install system dependencies on Linux
|
|
if [[ "$OS" == "linux" ]]; then
|
|
install_system_deps
|
|
echo ""
|
|
fi
|
|
|
|
install_missing
|
|
echo ""
|
|
|
|
verify
|
|
}
|
|
|
|
# Run main function
|
|
main
|