Created
June 26, 2025 20:22
-
-
Save okhsunrog/bff4504d990096b8c4ba9afdeb7a2e0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -euo pipefail | |
######################################## | |
# Logging Functions | |
######################################## | |
log_info() { | |
printf "[INFO] %s\n" "$1" | |
} | |
log_error() { | |
printf "[ERROR] %s\n" "$1" >&2 | |
} | |
######################################## | |
# OS Detection | |
######################################## | |
detect_os() { | |
local os | |
os="$(uname)" | |
if [[ "$os" == "Linux" ]]; then | |
echo "Linux" | |
elif [[ "$os" == "Darwin" ]]; then | |
echo "Darwin" | |
else | |
echo "$os" | |
fi | |
} | |
######################################## | |
# Install OS-Specific Dependencies | |
######################################## | |
install_dependencies() { | |
local os="$1" | |
if [[ "$os" == "Linux" ]]; then | |
SUDO="" | |
if command -v sudo >/dev/null 2>&1; then | |
SUDO="sudo" | |
else | |
log_error "sudo command not found. Please run this script as root or install sudo." | |
exit 1 | |
fi | |
# Check for Arch Linux (pacman) | |
if command -v pacman >/dev/null 2>&1; then | |
log_info "Detected Arch Linux. Checking for dependencies..." | |
local packages_to_install=() | |
# Essential build tools and libraries. --needed handles them gracefully. | |
packages_to_install+=("base-devel" "openssl" "systemd") | |
# Check for the 'clang' COMMAND. Only add the 'clang' package if the command is missing. | |
# Pacman will handle pulling in 'llvm' as a dependency automatically. | |
if ! command -v clang &>/dev/null; then | |
log_info "-> 'clang' command not found. Adding 'clang' to install list." | |
packages_to_install+=("clang") | |
else | |
log_info "-> Found clang: $(clang --version | head -n 1)" | |
fi | |
# Check for the 'protoc' COMMAND. | |
if ! command -v protoc &>/dev/null; then | |
log_info "-> 'protoc' command not found. Adding 'protobuf' to install list." | |
packages_to_install+=("protobuf") | |
else | |
log_info "-> Found protoc: $(protoc --version)" | |
fi | |
# --- THE FAULTY LINE HAS BEEN REMOVED FROM HERE --- | |
log_info "Attempting to install/update required packages with 'pacman --needed'..." | |
# The "${packages_to_install[@]}" syntax handles the case where the array is empty. | |
$SUDO pacman -Syu --noconfirm --needed "${packages_to_install[@]}" | |
# Check for Debian/Ubuntu (apt-get) | |
elif command -v apt-get >/dev/null 2>&1; then | |
log_info "Detected Debian/Ubuntu-based Linux. Updating and installing dependencies..." | |
$SUDO apt-get update | |
$SUDO apt-get install -y \ | |
build-essential \ | |
pkg-config \ | |
libudev-dev \ | |
llvm \ | |
libclang-dev \ | |
protobuf-compiler \ | |
libssl-dev | |
else | |
log_error "Unsupported Linux distribution. Please install dependencies manually." | |
log_error "Required dependencies are roughly: a C/C++ compiler (gcc/clang), make, pkg-config, llvm, clang, protobuf, openssl, and libudev." | |
exit 1 | |
fi | |
elif [[ "$os" == "Darwin" ]]; then | |
log_info "Detected macOS. Dependencies are typically handled by Solana/Anchor installers." | |
log_info "Ensure you have Xcode Command Line Tools installed: 'xcode-select --install'" | |
else | |
log_info "Detected an unsupported OS: $os." | |
fi | |
echo "" | |
} | |
######################################## | |
# Install Rust via rustup | |
######################################## | |
install_rust() { | |
if command -v rustc >/dev/null 2>&1; then | |
log_info "Rust is already installed. Updating..." | |
rustup update | |
else | |
log_info "Installing Rust..." | |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | |
# Source the Rust environment for the current script session | |
if [[ -f "$HOME/.cargo/env" ]]; then | |
. "$HOME/.cargo/env" | |
else | |
log_error "Could not find Rust environment file to source." | |
fi | |
fi | |
if command -v rustc >/dev/null 2>&1; then | |
rustc --version | |
else | |
log_error "Rust installation failed or was not added to PATH. Please check your ~/.profile or ~/.bashrc." | |
exit 1 | |
fi | |
echo "" | |
} | |
######################################## | |
# Install Solana CLI | |
######################################## | |
install_solana_cli() { | |
# Add Solana to PATH for the current script session | |
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" | |
if command -v solana >/dev/null 2>&1; then | |
log_info "Solana CLI is already installed. Updating..." | |
# The installer creates 'agave-install', not 'solana-install' | |
if command -v agave-install >/dev/null 2>&1; then | |
agave-install update | |
else | |
log_error "Cannot find 'agave-install' to update Solana. Please update manually or reinstall." | |
fi | |
else | |
log_info "Installing Solana CLI..." | |
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" | |
log_info "Solana CLI installation complete." | |
fi | |
# The installer modifies shell rc files, but we need the PATH for the current session | |
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" | |
if command -v solana >/dev/null 2>&1; then | |
solana --version | |
else | |
log_error "Solana CLI installation failed or not found in PATH." | |
log_error "Try adding 'export PATH=\"\$HOME/.local/share/solana/install/active_release/bin:\$PATH\"' to your shell rc file." | |
exit 1 | |
fi | |
echo "" | |
} | |
######################################## | |
# Install Anchor CLI | |
######################################## | |
install_anchor_cli() { | |
# Add cargo-installed binaries to PATH for the current session | |
export PATH="$HOME/.cargo/bin:$PATH" | |
if command -v anchor >/dev/null 2>&1; then | |
log_info "Anchor CLI is already installed. Updating..." | |
if ! command -v avm >/dev/null 2>&1; then | |
log_info "AVM is not installed. Installing AVM..." | |
cargo install --force --git https://github.com/coral-xyz/anchor avm | |
fi | |
avm update | |
else | |
log_info "Installing Anchor Version Manager (AVM) and Anchor CLI..." | |
cargo install --git https://github.com/coral-xyz/anchor avm --locked | |
avm install latest | |
avm use latest | |
log_info "Anchor CLI installation complete." | |
fi | |
if command -v anchor >/dev/null 2>&1; then | |
anchor --version | |
else | |
log_error "Anchor CLI installation failed or not found in PATH." | |
log_error "Try adding 'export PATH=\"\$HOME/.cargo/bin:\$PATH\"' to your shell rc file." | |
exit 1 | |
fi | |
echo "" | |
} | |
######################################## | |
# Install nvm and Node.js | |
######################################## | |
install_nvm_and_node() { | |
# Ensure NVM is sourced for the current session if it exists | |
if [ -s "$HOME/.nvm/nvm.sh" ]; then | |
export NVM_DIR="$HOME/.nvm" | |
# shellcheck disable=SC1091 | |
. "$NVM_DIR/nvm.sh" | |
fi | |
if ! command -v nvm >/dev/null 2>&1; then | |
log_info "Installing NVM..." | |
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash | |
# Source NVM for the current session after installation | |
export NVM_DIR="$HOME/.nvm" | |
# shellcheck disable=SC1091 | |
. "$NVM_DIR/nvm.sh" | |
else | |
log_info "NVM is already installed." | |
fi | |
if ! command -v node >/dev/null 2>&1; then | |
log_info "Installing latest Node.js via NVM..." | |
nvm install node # 'node' is an alias for the latest version | |
nvm alias default node | |
nvm use default | |
else | |
log_info "Node.js is already installed. Checking for updates..." | |
nvm install node # This will install the latest if not already present | |
nvm alias default node | |
fi | |
if command -v node >/dev/null 2>&1; then | |
log_info "Using Node.js version: $(node --version)" | |
else | |
log_error "Node.js installation failed." | |
exit 1 | |
fi | |
echo "" | |
} | |
######################################## | |
# Install Yarn | |
######################################## | |
install_yarn() { | |
if command -v yarn >/dev/null 2>&1; then | |
log_info "Yarn is already installed." | |
else | |
log_info "Installing Yarn..." | |
npm install --global yarn | |
fi | |
if command -v yarn >/dev/null 2>&1; then | |
yarn --version | |
else | |
log_error "Yarn installation failed." | |
exit 1 | |
fi | |
echo "" | |
} | |
######################################## | |
# Print Installed Versions | |
######################################## | |
print_versions() { | |
echo "----------------------------------------" | |
log_info "Installation Summary" | |
echo "----------------------------------------" | |
# Ensure PATHs are set for version checking | |
export PATH="$HOME/.cargo/bin:$HOME/.local/share/solana/install/active_release/bin:$PATH" | |
export NVM_DIR="$HOME/.nvm" | |
# shellcheck disable=SC1091 | |
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" | |
echo "Rust: $(rustc --version 2>/dev/null || echo 'Not found')" | |
echo "Solana CLI: $(solana --version 2>/dev/null || echo 'Not found')" | |
echo "Anchor CLI: $(anchor --version 2>/dev/null || echo 'Not found')" | |
echo "Node.js: $(node --version 2>/dev/null || echo 'Not found')" | |
echo "Yarn: $(yarn --version 2>/dev/null || echo 'Not found')" | |
echo "----------------------------------------" | |
} | |
######################################## | |
# Ensure RC files are configured | |
# NOTE: This only affects future terminal sessions. | |
######################################## | |
ensure_shell_config() { | |
local shell_rc="" | |
case "$SHELL" in | |
*/zsh) shell_rc="$HOME/.zshrc" ;; | |
*/bash) shell_rc="$HOME/.bashrc" ;; | |
*) shell_rc="$HOME/.profile" ;; | |
esac | |
log_info "Ensuring shell configuration is up to date in: $shell_rc" | |
# NVM | |
if ! grep -q 'export NVM_DIR' "$shell_rc"; then | |
log_info "-> Adding NVM configuration to $shell_rc" | |
{ | |
echo '' | |
echo '# Node Version Manager (NVM)' | |
echo 'export NVM_DIR="$HOME/.nvm"' | |
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm' | |
echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion' | |
} >> "$shell_rc" | |
fi | |
# Note: rustup and solana installers typically handle their own PATH additions. | |
# We will just verify and add if missing for robustness. | |
# Rust (Cargo) | |
if ! grep -q 'source "$HOME/.cargo/env"' "$shell_rc" && ! grep -q '.cargo/bin' "$shell_rc"; then | |
log_info "-> Adding Rust (Cargo) to PATH in $shell_rc" | |
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> "$shell_rc" | |
fi | |
# Solana | |
if ! grep -q 'solana/install/active_release/bin' "$shell_rc"; then | |
log_info "-> Adding Solana to PATH in $shell_rc" | |
echo 'export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"' >> "$shell_rc" | |
fi | |
} | |
######################################## | |
# Main Execution Flow | |
######################################## | |
main() { | |
local os | |
os=$(detect_os) | |
install_dependencies "$os" | |
install_rust | |
install_solana_cli "$os" | |
install_anchor_cli | |
install_nvm_and_node | |
install_yarn | |
ensure_shell_config | |
print_versions | |
log_info "Setup complete. Please restart your terminal or run 'source ~/${SHELL##*/}' to apply all changes." | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment