Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Last active May 5, 2025 22:15
Show Gist options
  • Save WomB0ComB0/1f68b8ccf77aabdfc16d07e1c722d480 to your computer and use it in GitHub Desktop.
Save WomB0ComB0/1f68b8ccf77aabdfc16d07e1c722d480 to your computer and use it in GitHub Desktop.
full-stack language install
#!/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