Last active
May 5, 2025 22:15
-
-
Save WomB0ComB0/1f68b8ccf77aabdfc16d07e1c722d480 to your computer and use it in GitHub Desktop.
full-stack language install
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
#!/bin/bash | |
# Exit immediately if a command exits with a non-zero status. | |
set -e | |
# Treat unset variables as an error. | |
set -u | |
# --- Colors --- | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# --- Helper Functions --- | |
print_status() { | |
local message="$1" | |
local status=$2 # 0 for success, non-zero for failure | |
local color="${GREEN}" | |
local symbol="✓" | |
if [ "$status" -ne 0 ]; then | |
color="${RED}" | |
symbol="✗" | |
fi | |
echo -e "${color}${symbol} ${message}${NC}" | |
} | |
command_exists() { | |
command -v "$1" >/dev/null 2>&1 | |
} | |
is_apt() { | |
command_exists apt-get | |
} | |
is_brew() { | |
command_exists brew | |
} | |
run_apt_update() { | |
if is_apt; then | |
echo -e "${BLUE}--> Running apt update...${NC}" | |
sudo apt-get update | |
print_status "apt update" $? | |
fi | |
} | |
# Helper to install or update a package using apt or brew | |
# $1: Package name for apt | |
# $2: Package name for brew | |
# $3: Command to check existence (optional, defaults to $1) | |
install_or_update_package() { | |
local apt_pkg="$1" | |
local brew_pkg="$2" | |
local check_cmd="${3:-$1}" # Default check command is the apt package name | |
echo -e "${BLUE}--> Checking for ${check_cmd}...${NC}" | |
if command_exists "$check_cmd"; then | |
echo -e "${YELLOW}${check_cmd} found. Attempting update...${NC}" | |
if is_apt; then | |
sudo apt-get update && sudo apt-get upgrade -y "$apt_pkg" | |
print_status "Updated ${apt_pkg}" $? | |
elif is_brew; then | |
brew upgrade "$brew_pkg" | |
print_status "Updated ${brew_pkg}" $? | |
fi | |
else | |
echo -e "${YELLOW}${check_cmd} not found. Installing...${NC}" | |
if is_apt; then | |
run_apt_update | |
sudo apt-get install -y "$apt_pkg" | |
print_status "Installed ${apt_pkg}" $? | |
elif is_brew; then | |
brew install "$brew_pkg" | |
print_status "Installed ${brew_pkg}" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
return 1 # Indicate failure | |
fi | |
fi | |
} | |
# --- Language Installation Functions --- | |
install_python() { | |
echo -e "\n${YELLOW}Setting up Python environment...${NC}" | |
install_or_update_package python3 python3 python3 | |
# Specific Python tools | |
if command_exists python3; then | |
echo -e "${BLUE}--> Upgrading pip and installing virtualenv...${NC}" | |
python3 -m pip install --upgrade pip || print_status "Upgraded pip" 1 # Don't fail script if pip upgrade fails | |
pip3 install virtualenv || print_status "Installed virtualenv" 1 # Don't fail script if virtualenv install fails | |
else | |
print_status "Python not installed, skipping pip/virtualenv setup" 1 | |
fi | |
print_status "Python setup complete" 0 # Overall status for the section | |
} | |
install_node() { | |
echo -e "\n${YELLOW}Setting up Node.js environment (LTS)...${NC}" | |
if command_exists node; then | |
echo -e "${YELLOW}Node.js found. Attempting update...${NC}" | |
if is_apt; then | |
# NodeSource updates are done by re-running the setup script or apt upgrade nodejs | |
echo -e "${BLUE}--> Attempting update via apt...${NC}" | |
sudo apt-get update && sudo apt-get upgrade -y nodejs | |
print_status "Updated nodejs via apt" $? | |
elif is_brew; then | |
brew upgrade node | |
print_status "Updated node via brew" $? | |
fi | |
else | |
echo -e "${YELLOW}Node.js not found. Installing (LTS)...${NC}" | |
if is_apt; then | |
run_apt_update | |
# Use NodeSource script for latest LTS on Apt-based systems | |
echo -e "${BLUE}--> Running NodeSource setup script...${NC}" | |
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - | |
sudo apt-get install -y nodejs | |
print_status "Installed nodejs via NodeSource" $? | |
elif is_brew; then | |
brew install node | |
print_status "Installed node via brew" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
print_status "Node.js setup failed" 1 | |
return 1 | |
fi | |
fi | |
# Optional: Install global tools like Typescript (consider if always desired) | |
if command_exists npm; then | |
echo -e "${BLUE}--> Installing/Updating global npm packages (e.g., typescript)...${NC}" | |
npm install -g typescript || print_status "Installed/Updated typescript" 1 # Don't fail script | |
else | |
print_status "npm not found, skipping global packages setup" 1 | |
fi | |
print_status "Node.js setup complete" 0 # Overall status | |
} | |
install_java() { | |
echo -e "\n${YELLOW}Setting up Java environment...${NC}" | |
# Use default-jdk/default-jre for general Java on Apt. OpenJDK on Brew. | |
# Check for 'java' command as the indicator. | |
install_or_update_package default-jdk openjdk java | |
print_status "Java setup complete" 0 | |
} | |
install_cpp() { | |
echo -e "\n${YELLOW}Setting up C/C++ environment...${NC}" | |
# build-essential includes g++, gcc, make etc. | |
install_or_update_package build-essential gcc g++ | |
# Install cmake separately as it's a common build tool | |
echo -e "${BLUE}--> Checking for CMake...${NC}" | |
install_or_update_package cmake cmake cmake | |
print_status "C/C++ setup complete" 0 | |
} | |
install_dart() { | |
echo -e "\n${YELLOW}Setting up Dart environment...${NC}" | |
if command_exists dart; then | |
echo -e "${YELLOW}Dart found. Attempting update...${NC}" | |
if is_apt; then | |
sudo apt-get update && sudo apt-get upgrade -y dart | |
print_status "Updated dart via apt" $? | |
elif is_brew; then | |
brew upgrade dart | |
print_status "Updated dart via brew" $? | |
fi | |
else | |
echo -e "${YELLOW}Dart not found. Installing...${NC}" | |
if is_apt; then | |
# Standard recommended way via Google's repository for Apt | |
echo -e "${BLUE}--> Adding Dart repository...${NC}" | |
sudo apt-get update | |
sudo apt-get install -y apt-transport-https | |
# Check if key already added to avoid warnings (basic check) | |
if ! sudo apt-key list | grep -q "Google Inc."; then | |
wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - | |
fi | |
# Check if source list already exists | |
if [ ! -f "/etc/apt/sources.list.d/dart_stable.list" ]; then | |
sudo sh -c 'wget -qO- https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list' | |
fi | |
run_apt_update # Update again after adding repo | |
sudo apt-get install -y dart | |
print_status "Installed dart via Google repository" $? | |
elif is_brew; then | |
# Brew method | |
brew tap dart-lang/dart || print_status "Tapped dart-lang/dart" 1 # Don't fail script | |
brew install dart | |
print_status "Installed dart via brew" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
print_status "Dart setup failed" 1 | |
return 1 | |
fi | |
fi | |
print_status "Dart setup complete" 0 | |
} | |
install_php() { | |
echo -e "\n${YELLOW}Setting up PHP environment...${NC}" | |
# PHP versioning on Apt is complex. Using ondrej/php PPA is common for recent versions. | |
# Brew is simpler. Check for 'php' command. | |
if command_exists php; then | |
echo -e "${YELLOW}PHP found. Attempting update...${NC}" | |
if is_apt; then | |
# Update via PPA/apt upgrade | |
sudo apt-get update && sudo apt-get upgrade -y "php*" | |
print_status "Updated PHP via apt" $? | |
elif is_brew; then | |
brew upgrade php | |
print_status "Updated PHP via brew" $? | |
fi | |
else | |
echo -e "${YELLOW}PHP not found. Installing...${NC}" | |
if is_apt; then | |
# Use ondrej/php PPA for a recent version | |
echo -e "${BLUE}--> Adding ondrej/php PPA...${NC}" | |
run_apt_update | |
sudo apt-get install -y software-properties-common | |
# Use --yes for add-apt-repository as it might require confirmation | |
sudo add-apt-repository ppa:ondrej/php -y | |
run_apt_update # Update again after adding repo | |
# Install a common version (e.g., php8.2) and essential modules | |
# NOTE: This still hardcodes 8.2. A truly version-agnostic apt install is hard without PPAs. | |
# If you need the *absolute latest* via PPA, you might need to adjust the package name. | |
# This installs a recent, common one. | |
sudo apt-get install -y php php-cli php-common php-mysql php-zip php-gd php-mbstring php-curl php-xml php-bcmath | |
print_status "Installed PHP via ondrej/php PPA" $? | |
elif is_brew; then | |
brew install php | |
print_status "Installed PHP via brew" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
print_status "PHP setup failed" 1 | |
return 1 | |
fi | |
fi | |
# Install Composer (PHP dependency manager) | |
if ! command_exists composer; then | |
echo -e "${BLUE}--> Installing Composer...${NC}" | |
EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)" | |
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" | |
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" | |
if [ "$EXPECTED_CHECKSUM" = "$ACTUAL_CHECKSUM" ]; then | |
php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer | |
print_status "Installed Composer globally" $? | |
else | |
echo -e "${RED}Composer checksum mismatch. Skipping installation.${NC}" | |
print_status "Installed Composer globally" 1 | |
fi | |
# Clean up installer file regardless of checksum result | |
if [ -f "composer-setup.php" ]; then | |
rm composer-setup.php | |
fi | |
else | |
echo -e "${YELLOW}Composer already installed. Attempting update...${NC}" | |
composer self-update || print_status "Updated Composer" 1 # Don't fail script | |
fi | |
print_status "PHP setup complete" 0 | |
} | |
install_csharp() { | |
echo -e "\n${YELLOW}Setting up C# (.NET) environment...${NC}" | |
if command_exists dotnet; then | |
echo -e "${YELLOW}.NET SDK found. Attempting update...${NC}" | |
if is_apt; then | |
# Update via Microsoft repo/apt upgrade | |
sudo apt-get update && sudo apt-get upgrade -y "dotnet-sdk-*" | |
print_status "Updated .NET SDK via apt" $? | |
elif is_brew; then | |
brew upgrade --cask dotnet-sdk | |
print_status "Updated .NET SDK via brew" $? | |
fi | |
else | |
echo -e "${YELLOW}.NET SDK not found. Installing...${NC}" | |
if is_apt; then | |
# Use Microsoft's repository for Apt (Ubuntu 22.04 assumed based on original) | |
echo -e "${BLUE}--> Adding Microsoft package repository...${NC}" | |
# This assumes Ubuntu 22.04 or compatible. Adjust filename/URL if needed for other versions. | |
# A truly distribution-agnostic script would need to detect the distro and version. | |
# Sticking to the original's implied compatibility. | |
local ms_repo_deb="packages-microsoft-prod.deb" | |
wget https://packages.microsoft.com/config/ubuntu/22.04/${ms_repo_deb} -O ${ms_repo_deb} | |
sudo dpkg -i ${ms_repo_deb} | |
rm ${ms_repo_deb} | |
run_apt_update | |
# Install the latest SDK (e.g., dotnet-sdk-8.0, but using wildcard for latest) | |
sudo apt-get install -y dotnet-sdk-$(apt list dotnet-sdk-* 2>/dev/null | grep -m 1 -oP 'dotnet-sdk-\K[0-9.]+' | cut -d'.' -f1).0 | |
# Fallback if wildcard fails or repo doesn't list by major version | |
if [ $? -ne 0 ]; then | |
echo -e "${YELLOW}Attempting to install dotnet-sdk-8.0 directly if latest wildcard failed...${NC}" | |
sudo apt-get install -y dotnet-sdk-8.0 || true # Allow this to fail if 8.0 isn't available either | |
fi | |
print_status "Installed .NET SDK via Microsoft repository" $? | |
elif is_brew; then | |
brew install --cask dotnet-sdk | |
print_status "Installed .NET SDK via brew" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
print_status "C# (.NET) setup failed" 1 | |
return 1 | |
fi | |
fi | |
print_status "C# (.NET) setup complete" 0 | |
} | |
install_go() { | |
echo -e "\n${YELLOW}Setting up Go environment...${NC}" | |
# Use golang-go on Apt, go on Brew. Check for 'go' command. | |
install_or_update_package golang-go go go | |
print_status "Go setup complete" 0 | |
} | |
install_rust() { | |
echo -e "\n${YELLOW}Setting up Rust environment...${NC}" | |
if command_exists rustc; then | |
echo -e "${YELLOW}Rust found via rustup. Attempting update...${NC}" | |
rustup update || print_status "Updated Rust via rustup" 1 # Don't fail script | |
else | |
echo -e "${YELLOW}Rust not found. Installing via rustup...${NC}" | |
# Recommended method is using rustup.rs | |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | |
# rustup adds itself to PATH in $HOME/.cargo/env | |
print_status "Installed Rust via rustup" $? | |
echo -e "${BLUE}--> Rust's cargo bin directory was added to \$PATH in \$HOME/.cargo/env${NC}" | |
echo -e "${BLUE}--> You may need to source this file or restart your terminal for 'cargo' and 'rustc' to be available.${NC}" | |
# Source it for the current script environment | |
# shellcheck source=/dev/null | |
source "$HOME/.cargo/env" || echo -e "${YELLOW}Warning: Could not source $HOME/.cargo/env for this script's environment.${NC}" | |
fi | |
print_status "Rust setup complete" 0 | |
} | |
install_ruby() { | |
echo -e "\n${YELLOW}Setting up Ruby environment...${NC}" | |
# Use ruby-full on Apt, ruby on Brew. Check for 'ruby' command. | |
install_or_update_package ruby-full ruby ruby | |
print_status "Ruby setup complete" 0 | |
} | |
install_swift() { | |
echo -e "\n${YELLOW}Setting up Swift environment...${NC}" | |
if command_exists swift; then | |
echo -e "${YELLOW}Swift found. Attempting update...${NC}" | |
if is_apt; then | |
# Swift.org downloads are versioned. Updating means downloading the *new* latest and updating PATH. | |
# This is complex to automate cleanly without versioning. | |
# The simplest "update" on apt for swift.org users is to tell them to manually download | |
# the latest version from swift.org and update their PATH. | |
# We'll skip an automated update for this method and just confirm it exists. | |
echo -e "${BLUE}--> Swift was likely installed manually or via swift.org tarball.${NC}" | |
echo -e "${BLUE}--> Automatic updating for this method is not supported by this script.${NC}" | |
echo -e "${BLUE}--> Please check swift.org for the latest release and update manually if needed.${NC}" | |
elif is_brew; then | |
brew upgrade swift | |
print_status "Updated swift via brew" $? | |
fi | |
else | |
echo -e "${YELLOW}Swift not found. Installing...${NC}" | |
if is_apt; then | |
# Swift.org recommended method for Linux involves downloading a tarball. | |
# We need to find the latest tarball URL dynamically or hardcode the base URL structure. | |
# Let's stick to installing dependencies needed for the swift.org tarball, | |
# download the latest tarball, and instruct the user on adding to PATH. | |
echo -e "${BLUE}--> Installing Swift dependencies for Apt...${NC}" | |
sudo apt-get update | |
sudo apt-get install -y \ | |
binutils \ | |
git \ | |
gnupg2 \ | |
libc6-dev \ | |
libcurl4-openssl-dev \ | |
libedit2 \ | |
libgcc-9-dev \ | |
python3 \ | |
libsqlite3-0 \ | |
libstdc++-9-dev \ | |
libxml2-dev \ | |
libz3-dev \ | |
pkg-config \ | |
tzdata \ | |
zlib1g-dev | |
print_status "Installed Swift dependencies" $? | |
echo -e "${BLUE}--> Downloading latest Swift toolchain from swift.org...${NC}" | |
# Find the latest version dynamically requires scraping the page, which is fragile. | |
# A common pattern is a redirect from a generic URL, but swift.org uses specific versioned URLs. | |
# Let's hardcode the pattern for a recent Ubuntu LTS release (like 22.04 as in original). | |
# This link points to the *latest* 5.10 toolchain for Ubuntu 22.04 as of late 2023/early 2024. | |
# It's the closest we can get to "latest" without complex web scraping. | |
# Note this STILL links to a specific *major.minor* version release series. | |
# For true "latest", you'd ideally use a package manager if it's updated frequently, or rustup-like tool for Swift. | |
local swift_download_base="https://download.swift.org/latest-5.10/ubuntu2204/swift-5.10-RELEASE/swift-5.10-RELEASE-ubuntu22.04.tar.gz" | |
local tarball_name=$(basename "$swift_download_base") | |
local extract_dir=$(basename "$tarball_name" .tar.gz) | |
if [ -f "$tarball_name" ]; then | |
echo -e "${YELLOW}Download found locally: ${tarball_name}. Skipping download.${NC}" | |
else | |
echo -e "${BLUE}Downloading ${swift_download_base}...${NC}" | |
wget "$swift_download_base" -O "$tarball_name" | |
print_status "Downloaded Swift toolchain" $? | |
fi | |
echo -e "${BLUE}--> Extracting Swift toolchain to /usr/local/...${NC}" | |
# Remove existing toolchain directory with the same name before extracting? Risky if used by other users/systems. | |
# Let's just extract. If /usr/local/swift-XYZ already exists, tar might warn or overwrite. | |
# A safer approach is to extract to a temporary location and then move/link. | |
# Simpler for now: just extract directly. User might need to manage older versions in /usr/local. | |
sudo tar xzf "$tarball_name" -C /usr/local/ --checkpoint=.100 || print_status "Extracted Swift toolchain" 1 # Checkpoint for verbose output | |
print_status "Extracted Swift toolchain" $? | |
echo -e "${BLUE}--> Swift installation requires adding to PATH.${NC}" | |
echo -e "${BLUE}--> Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc.):${NC}" | |
echo -e "${BLUE} export PATH=\"/usr/local/${extract_dir}/usr/bin:\$PATH\"${NC}" | |
echo -e "${BLUE}--> Then source your profile file (e.g., 'source ~/.bashrc') or restart your terminal.${NC}" | |
# Don't delete the tarball immediately in case of issues, maybe move it. | |
# rm "$tarball_name" | |
elif is_brew; then | |
brew install swift | |
print_status "Installed swift via brew" $? | |
else | |
echo -e "${RED}Error: No supported package manager (apt or brew) found.${NC}" | |
print_status "Swift setup failed" 1 | |
return 1 | |
fi | |
fi | |
print_status "Swift setup complete" 0 | |
} | |
install_kotlin() { | |
echo -e "\n${YELLOW}Setting up Kotlin environment...${NC}" | |
# Use kotlin on Apt, kotlin on Brew. Check for 'kotlin' command. | |
install_or_update_package kotlin kotlin kotlin | |
print_status "Kotlin setup complete" 0 | |
} | |
# --- Main Logic --- | |
main() { | |
echo -e "${YELLOW}Starting development environment setup...${NC}" | |
# Check for package managers upfront | |
if ! is_apt && ! is_brew; then | |
echo -e "${RED}Error: Neither apt nor brew package managers found.${NC}" | |
echo "Please install either apt (Linux) or brew (macOS/Linux) first." | |
exit 1 | |
fi | |
local -a languages_to_install=() | |
if [[ " $@ " =~ " all " ]]; then | |
echo -e "${YELLOW}Selected 'all' languages.${NC}" | |
languages_to_install=("python" "node" "java" "cpp" "dart" "php" "csharp" "go" "rust" "ruby" "swift" "kotlin") | |
else | |
# Collect valid language arguments | |
for arg in "$@"; do | |
case "$arg" in | |
python|typescript|javascript|java|cpp|c|dart|php|csharp|go|rust|ruby|swift|kotlin) | |
# Map aliases to primary function name | |
case "$arg" in | |
typescript|javascript) languages_to_install+=("node") ;; | |
c) languages_to_install+=("cpp") ;; | |
*) languages_to_install+=("$arg") ;; # Add valid language directly | |
esac | |
;; | |
all) | |
# Already handled above, ignore here | |
;; | |
*) | |
echo -e "${RED}Skipping unsupported language: $arg${NC}" | |
;; | |
esac | |
done | |
fi | |
if [ ${#languages_to_install[@]} -eq 0 ]; then | |
echo -e "${RED}No valid languages selected.${NC}" | |
echo "Usage: $0 [language1] [language2] ..." | |
echo "Available languages: python, typescript, javascript, java, cpp, c, dart, php, csharp, go, rust, ruby, swift, kotlin, all" | |
exit 1 | |
fi | |
# Process each selected language (unique list) | |
printf "%s\n" "${languages_to_install[@]}" | sort -u | while IFS= read -r lang; do | |
case "$lang" in | |
python) install_python ;; | |
node) install_node ;; | |
java) install_java ;; | |
cpp) install_cpp ;; | |
dart) install_dart ;; | |
php) install_php ;; | |
csharp) install_csharp ;; | |
go) install_go ;; | |
rust) install_rust ;; | |
ruby) install_ruby ;; | |
swift) install_swift ;; | |
kotlin) install_kotlin ;; | |
*) | |
# This case should ideally not be reached due to the filtering above | |
echo -e "${RED}Unexpected language in processing list: $lang${NC}" | |
;; | |
esac | |
done | |
echo -e "\n${GREEN}Development environment setup complete!${NC}" | |
echo -e "${GREEN}Please check the output for any specific instructions (like updating PATH).${NC}" | |
} | |
# --- Script Entry Point --- | |
if [ $# -eq 0 ]; then | |
echo "Usage: $0 [language1] [language2] ..." | |
echo "Available languages: python, typescript, javascript, java, cpp, c, dart, php, csharp, go, rust, ruby, swift, kotlin, all" | |
exit 1 | |
fi | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment