#!/usr/bin/env bash # Install Exercism CLI - Offline Coding Challenges # # Exercism is a free, open source platform with: # - 65+ programming languages # - Built-in test suites for each exercise # - Works offline after downloading exercises # # Website: https://exercism.org # License: AGPL-3.0 set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' success() { echo -e "${GREEN}✓ $1${NC}"; } warn() { echo -e "${YELLOW}⚠ $1${NC}"; } error() { echo -e "${RED}✗ $1${NC}"; } info() { echo -e "${BLUE}ℹ $1${NC}"; } EXERCISM_DIR="${HOME}/exercism" echo "==============================================" echo " Exercism - Offline Coding Challenges" echo " Free & Open Source with Built-in Tests" echo "==============================================" echo "" # Install Exercism CLI install_exercism_cli() { if command -v exercism &>/dev/null; then local version version=$(exercism version 2>/dev/null | head -1) success "Exercism CLI already installed: $version" return 0 fi echo "Installing Exercism CLI..." # Try package managers first if command -v pacman &>/dev/null; then # Check AUR if command -v yay &>/dev/null; then yay -S --noconfirm exercism-bin success "Exercism CLI installed via AUR" return 0 elif command -v paru &>/dev/null; then paru -S --noconfirm exercism-bin success "Exercism CLI installed via AUR" return 0 fi elif command -v brew &>/dev/null; then brew install exercism success "Exercism CLI installed via Homebrew" return 0 fi # Manual installation from GitHub releases info "Installing from GitHub releases..." local arch case "$(uname -m)" in x86_64) arch="x86_64" ;; aarch64 | arm64) arch="arm64" ;; armv7l) arch="armv7" ;; i686) arch="i386" ;; *) error "Unsupported architecture: $(uname -m)" return 1 ;; esac local os="linux" [[ "$(uname -s)" == "Darwin" ]] && os="darwin" # Get latest release local latest_url="https://api.github.com/repos/exercism/cli/releases/latest" local download_url download_url=$(curl -fsSL "$latest_url" | grep "browser_download_url.*${os}-${arch}" | head -1 | cut -d '"' -f 4) if [[ -z "$download_url" ]]; then error "Could not find download URL for your system" echo "Please install manually from: https://exercism.org/docs/using/solving-exercises/working-locally" return 1 fi echo "Downloading from: $download_url" local temp_dir temp_dir=$(mktemp -d) curl -fL --progress-bar "$download_url" -o "$temp_dir/exercism.tar.gz" tar -xzf "$temp_dir/exercism.tar.gz" -C "$temp_dir" # Install to ~/.local/bin mkdir -p "$HOME/.local/bin" mv "$temp_dir/exercism" "$HOME/.local/bin/" chmod +x "$HOME/.local/bin/exercism" rm -rf "$temp_dir" success "Exercism CLI installed to ~/.local/bin/exercism" # Check PATH if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then warn "Add ~/.local/bin to your PATH:" echo ' export PATH="$HOME/.local/bin:$PATH"' fi } # Configure exercism workspace configure_exercism() { echo "" echo "=== Configuring Exercism ===" mkdir -p "$EXERCISM_DIR" # Check if already configured if exercism configure 2>&1 | grep -q "workspace"; then success "Exercism already configured" else # Set workspace directory exercism configure --workspace="$EXERCISM_DIR" success "Workspace set to: $EXERCISM_DIR" fi echo "" info "To fully configure Exercism with your account:" echo " 1. Create free account at https://exercism.org" echo " 2. Go to https://exercism.org/settings/api_cli" echo " 3. Copy your API token" echo " 4. Run: exercism configure --token=YOUR_TOKEN" echo "" } # Install test runners for languages install_test_runners() { echo "" echo "=== Installing Test Runners ===" echo "" # Python - pytest if command -v python3 &>/dev/null; then if python3 -c "import pytest" 2>/dev/null; then success "Python: pytest already installed" else info "Installing pytest for Python exercises..." pip3 install --user pytest 2>/dev/null && success "Python: pytest installed" || warn "Python: install pytest manually" fi fi # JavaScript/TypeScript - Node.js + npm if command -v node &>/dev/null; then success "JavaScript/TypeScript: Node.js available ($(node --version))" info " Tests run with: npm test (or jest)" else warn "JavaScript/TypeScript: Install Node.js for JS/TS exercises" fi # C - gcc + criterion/cmocka if command -v gcc &>/dev/null; then success "C: gcc available" info " Some C exercises use Unity test framework (included in exercise)" else warn "C: Install gcc for C exercises" fi # C++ - g++ + Catch2/doctest if command -v g++ &>/dev/null; then success "C++: g++ available" info " C++ exercises use Catch2 (header-only, included in exercise)" else warn "C++: Install g++ for C++ exercises" fi # Rust if command -v cargo &>/dev/null; then success "Rust: cargo available (tests with: cargo test)" fi # Go if command -v go &>/dev/null; then success "Go: go available (tests with: go test)" fi } # Download exercises for a track (language) download_track() { local track="$1" local count="${2:-10}" echo "" info "Downloading $count exercises for $track track..." # Get list of exercises local exercises exercises=$(curl -fsSL "https://exercism.org/api/v2/tracks/${track}/exercises" 2>/dev/null | grep -oP '"slug":"\K[^"]+' | head -n "$count") if [[ -z "$exercises" ]]; then warn "Could not fetch exercise list for $track" return 1 fi local downloaded=0 for exercise in $exercises; do local exercise_dir="$EXERCISM_DIR/$track/$exercise" if [[ -d "$exercise_dir" ]]; then echo " [exists] $exercise" else if exercism download --track="$track" --exercise="$exercise" 2>/dev/null; then echo " [downloaded] $exercise" ((downloaded++)) else echo " [failed] $exercise (may require auth)" fi fi done success "Downloaded $downloaded new exercises for $track" } # Show available tracks and usage show_usage() { echo "" echo "==============================================" echo " Exercism Usage Guide" echo "==============================================" echo "" echo -e "${CYAN}Download exercises:${NC}" echo " exercism download --track=python --exercise=hello-world" echo " exercism download --track=javascript --exercise=two-fer" echo " exercism download --track=c --exercise=isogram" echo "" echo -e "${CYAN}Run tests locally:${NC}" echo " Python: cd ~/exercism/python/hello-world && pytest" echo " JavaScript: cd ~/exercism/javascript/hello-world && npm test" echo " TypeScript: cd ~/exercism/typescript/hello-world && npm test" echo " C: cd ~/exercism/c/hello-world && make test" echo " C++: cd ~/exercism/cpp/hello-world && make" echo " Rust: cd ~/exercism/rust/hello-world && cargo test" echo " Go: cd ~/exercism/go/hello-world && go test" echo "" echo -e "${CYAN}Submit solution (when online):${NC}" echo " exercism submit solution.py" echo "" echo -e "${CYAN}Popular tracks:${NC}" echo " python, javascript, typescript, c, cpp, rust, go, java, ruby" echo " bash, elixir, haskell, kotlin, swift, csharp, php, sql" echo "" echo -e "${CYAN}Batch download (requires API token):${NC}" echo " # Download first 20 Python exercises:" echo " for ex in \$(exercism download --track=python 2>&1 | head -20); do" echo " exercism download --track=python --exercise=\$ex" echo " done" echo "" echo "Exercises are in: $EXERCISM_DIR" echo "" echo "==============================================" } # Main main() { # Step 1: Install CLI echo "" echo "=== Step 1: Installing Exercism CLI ===" install_exercism_cli # Step 2: Configure configure_exercism # Step 3: Install test runners install_test_runners # Step 4: Download sample exercises echo "" echo "=== Step 4: Downloading Sample Exercises ===" echo "" echo "Downloading a few starter exercises for common languages..." echo "(Full download requires API token from exercism.org)" echo "" # Try to download hello-world for each track local tracks=("python" "javascript" "typescript" "c" "cpp") for track in "${tracks[@]}"; do local exercise_dir="$EXERCISM_DIR/$track/hello-world" if [[ -d "$exercise_dir" ]]; then echo " [$track] hello-world already exists" else if exercism download --track="$track" --exercise="hello-world" 2>/dev/null; then success "[$track] hello-world downloaded" else warn "[$track] hello-world requires authentication" fi fi done # Show usage show_usage echo "" success "Installation complete!" echo "" echo "Next steps:" echo " 1. Sign up at https://exercism.org (free)" echo " 2. Get your token from https://exercism.org/settings/api_cli" echo " 3. Run: exercism configure --token=YOUR_TOKEN" echo " 4. Download exercises and code offline!" echo "" } main "$@"