diff --git a/scripts/utils/download_exercism_bulk.sh b/scripts/utils/download_exercism_bulk.sh new file mode 100755 index 0000000..fb904ed --- /dev/null +++ b/scripts/utils/download_exercism_bulk.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# Download ALL Exercism exercises for offline practice +# +# This clones the official Exercism track repositories which contain +# ALL exercises with their test suites - no need to unlock one by one! +# +# Exercises are in: exercises/practice// +# Each exercise has tests you can run locally. + +set -euo pipefail + +TRACKS_DIR="${HOME}/exercism-tracks" + +# Colors +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +success() { echo -e "${GREEN}✓ $1${NC}"; } +info() { echo -e "${BLUE}ℹ $1${NC}"; } +warn() { echo -e "${YELLOW}⚠ $1${NC}"; } + +echo "==============================================" +echo " Exercism Bulk Exercise Downloader" +echo " Download ALL exercises for offline practice" +echo "==============================================" +echo "" + +mkdir -p "$TRACKS_DIR" +cd "$TRACKS_DIR" + +# Tracks to download (add/remove as needed) +declare -A TRACKS=( + ["python"]="https://github.com/exercism/python.git" + ["c"]="https://github.com/exercism/c.git" + ["cpp"]="https://github.com/exercism/cpp.git" + ["javascript"]="https://github.com/exercism/javascript.git" + ["typescript"]="https://github.com/exercism/typescript.git" + ["rust"]="https://github.com/exercism/rust.git" + ["go"]="https://github.com/exercism/go.git" + ["bash"]="https://github.com/exercism/bash.git" +) + +# Optional tracks (uncomment to include) +# TRACKS["java"]="https://github.com/exercism/java.git" +# TRACKS["ruby"]="https://github.com/exercism/ruby.git" +# TRACKS["haskell"]="https://github.com/exercism/haskell.git" +# TRACKS["elixir"]="https://github.com/exercism/elixir.git" + +echo "Downloading ${#TRACKS[@]} tracks to: $TRACKS_DIR" +echo "" + +for track in "${!TRACKS[@]}"; do + url="${TRACKS[$track]}" + + if [[ -d "$track" ]]; then + info "Updating $track..." + (cd "$track" && git pull --quiet) && success "$track updated" + else + info "Cloning $track..." + git clone --depth 1 "$url" && success "$track cloned" + fi + + # Show exercise count + if [[ -d "$track/exercises/practice" ]]; then + count=$(ls "$track/exercises/practice" | wc -l) + echo " → $count practice exercises available" + fi + echo "" +done + +echo "==============================================" +echo " Download Complete!" +echo "==============================================" +echo "" +echo "Exercises location: $TRACKS_DIR//exercises/practice/" +echo "" +echo "Example - Running Python exercises:" +echo " cd $TRACKS_DIR/python/exercises/practice/hello-world" +echo " python -m pytest -v" +echo "" +echo "Example - Running C exercises:" +echo " cd $TRACKS_DIR/c/exercises/practice/hello-world" +echo " make test" +echo "" +echo "Example - Running JavaScript exercises:" +echo " cd $TRACKS_DIR/javascript/exercises/practice/hello-world" +echo " npm install && npm test" +echo "" +echo "Each exercise folder contains:" +echo " - README.md (instructions)" +echo " - *_test.* (test file - run these!)" +echo " - .meta/exemplar.* (reference solution - don't peek!)" +echo "" +echo "==============================================" + +# Summary +echo "" +echo "Track summary:" +for track in "${!TRACKS[@]}"; do + if [[ -d "$track/exercises/practice" ]]; then + count=$(ls "$track/exercises/practice" 2>/dev/null | wc -l) + printf " %-15s %3d exercises\n" "$track" "$count" + fi +done | sort diff --git a/scripts/utils/install_exercism.sh b/scripts/utils/install_exercism.sh new file mode 100755 index 0000000..7f6d7f3 --- /dev/null +++ b/scripts/utils/install_exercism.sh @@ -0,0 +1,319 @@ +#!/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 "$@"