295 lines
11 KiB
Bash
Executable File
295 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
echo "🚀 Initializing development environment as user: $(whoami)"
|
|
|
|
# =============================================================================
|
|
# Create coder user if it doesn't exist
|
|
# =============================================================================
|
|
if ! id -u coder >/dev/null 2>&1; then
|
|
echo "👤 Creating coder user..."
|
|
useradd -m -s /bin/bash coder
|
|
usermod -aG sudo coder
|
|
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
|
elif [ "$(id -u coder)" != "1000" ]; then
|
|
echo "👤 Coder user exists but with different UID, updating..."
|
|
usermod -u 1000 coder
|
|
fi
|
|
|
|
# =============================================================================
|
|
# Create necessary directories
|
|
# =============================================================================
|
|
echo "📁 Creating user directories..."
|
|
mkdir -p /home/coder/bin
|
|
mkdir -p /home/coder/.local/bin
|
|
mkdir -p /home/coder/.config
|
|
mkdir -p /tmp/git-metadata
|
|
mkdir -p /workspaces
|
|
|
|
# Ensure proper ownership (only if coder user exists, excluding read-only bind mounts)
|
|
if id -u coder >/dev/null 2>&1; then
|
|
chown -R coder:coder /home/coder/.local /home/coder/.config /home/coder/bin /workspaces
|
|
# Set ownership for coder home directory files (not subdirectories that might be bind mounted)
|
|
find /home/coder -maxdepth 1 -type f -exec chown coder:coder {} \; 2>/dev/null || true
|
|
fi
|
|
|
|
# =============================================================================
|
|
# Switch to coder user for remaining operations
|
|
# =============================================================================
|
|
echo "🔄 Switching to coder user context..."
|
|
export HOME=/home/coder
|
|
export USER=coder
|
|
|
|
# =============================================================================
|
|
# Git Configuration
|
|
# =============================================================================
|
|
echo "⚙️ Configuring Git..."
|
|
git config --global user.name "${GIT_AUTHOR_NAME}"
|
|
git config --global user.email "${GIT_AUTHOR_EMAIL}"
|
|
git config --global commit.gpgsign false
|
|
git config --global tag.gpgsign false
|
|
git config --global init.defaultBranch main
|
|
git config --global pull.rebase false
|
|
|
|
# Capture and log git information
|
|
echo "📝 Capturing Git metadata..."
|
|
cd /workspaces
|
|
if [ -d ".git" ]; then
|
|
git branch --show-current > /tmp/git-metadata/current-branch 2>/dev/null || echo "main" > /tmp/git-metadata/current-branch
|
|
git rev-parse HEAD > /tmp/git-metadata/commit-hash 2>/dev/null || echo "no-commits" > /tmp/git-metadata/commit-hash
|
|
git remote get-url origin > /tmp/git-metadata/remote-url 2>/dev/null || echo "no-remote" > /tmp/git-metadata/remote-url
|
|
else
|
|
echo "no-repo" > /tmp/git-metadata/current-branch
|
|
echo "no-repo" > /tmp/git-metadata/commit-hash
|
|
echo "no-repo" > /tmp/git-metadata/remote-url
|
|
fi
|
|
|
|
# =============================================================================
|
|
# System Package Updates and Installation
|
|
# =============================================================================
|
|
echo "📦 Installing system packages..."
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y make tree jq curl wget unzip build-essential postgresql-client redis-tools
|
|
|
|
# =============================================================================
|
|
# Node.js and npm Setup (as coder user)
|
|
# =============================================================================
|
|
echo "🟢 Setting up Node.js and npm..."
|
|
|
|
# Clean any existing npm caches and config files with wrong ownership (as root before switching users)
|
|
rm -rf /home/coder/.npm /home/coder/.npm-global /home/coder/.npmrc 2>/dev/null || true
|
|
rm -rf /root/.npm /root/.npmrc 2>/dev/null || true
|
|
# Pre-create directories with proper ownership including lib and bin subdirectories
|
|
mkdir -p /home/coder/.npm /home/coder/.npm-global/{lib,bin,lib/node_modules}
|
|
chown -R coder:coder /home/coder/.npm /home/coder/.npm-global 2>/dev/null || true
|
|
|
|
# Create Node.js setup script
|
|
cat > /tmp/node_setup.sh << 'NODE_SCRIPT_END'
|
|
#!/bin/bash
|
|
# Create bash profile first
|
|
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.bashrc
|
|
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> ~/.bashrc
|
|
echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"' >> ~/.bashrc
|
|
|
|
# Clean any npmrc files that might conflict with nvm
|
|
rm -f ~/.npmrc /home/coder/.npmrc 2>/dev/null || true
|
|
|
|
# Verify npm directories exist and are owned by coder
|
|
ls -la ~/.npm ~/.npm-global || echo "npm directories ready"
|
|
|
|
if ! command -v nvm &> /dev/null; then
|
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
|
fi
|
|
|
|
# Load nvm properly
|
|
export NVM_DIR="/home/coder/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
|
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
|
|
nvm install ${NODE_VERSION}
|
|
nvm use ${NODE_VERSION}
|
|
nvm alias default ${NODE_VERSION}
|
|
|
|
# Clean npm config that conflicts with nvm
|
|
npm config delete globalconfig 2>/dev/null || true
|
|
npm config delete prefix 2>/dev/null || true
|
|
|
|
# Create npm-global lib directory structure
|
|
mkdir -p ~/.npm-global/{lib,bin}
|
|
|
|
# Configure npm to use user-writable directories
|
|
npm config set prefix ~/.npm-global
|
|
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
|
|
export PATH=~/.npm-global/bin:$PATH
|
|
|
|
# Verify npm configuration
|
|
echo "📋 npm configuration:"
|
|
npm config get prefix
|
|
npm config get cache
|
|
|
|
echo "📦 Installing npm packages..."
|
|
npm install -g repomix create-next-app nodemon concurrently @types/node typescript eslint prettier
|
|
NODE_SCRIPT_END
|
|
|
|
chmod +x /tmp/node_setup.sh
|
|
su - coder -c "/tmp/node_setup.sh"
|
|
rm /tmp/node_setup.sh
|
|
|
|
# =============================================================================
|
|
# Python Setup with uv (as coder user)
|
|
# =============================================================================
|
|
echo "🐍 Setting up Python and uv..."
|
|
|
|
# Install Python version (add deadsnakes PPA for newer Python versions)
|
|
if [[ "${PYTHON_VERSION}" > "3.10" ]]; then
|
|
echo "📦 Adding deadsnakes PPA for Python ${PYTHON_VERSION}..."
|
|
apt-get install -y software-properties-common
|
|
add-apt-repository ppa:deadsnakes/ppa -y
|
|
apt-get update
|
|
fi
|
|
|
|
apt-get install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-dev python${PYTHON_VERSION}-venv || {
|
|
echo "⚠️ Python ${PYTHON_VERSION} not available, falling back to default Python 3"
|
|
apt-get install -y python3 python3-dev python3-venv
|
|
export PYTHON_VERSION="3"
|
|
}
|
|
|
|
# Create Python setup script
|
|
cat > /tmp/python_setup.sh << 'PYTHON_SCRIPT_END'
|
|
#!/bin/bash
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
export PATH="/home/coder/.cargo/bin:$PATH"
|
|
|
|
echo "📦 Installing Python packages with uv..."
|
|
for package in fastapi uvicorn requests pandas numpy psycopg2-binary redis qdrant-client python-dotenv; do
|
|
uv tool install $package || echo "Failed to install $package"
|
|
done
|
|
|
|
uv venv /home/coder/.venv --python=${PYTHON_VERSION}
|
|
echo 'source /home/coder/.venv/bin/activate' >> /home/coder/.bashrc
|
|
PYTHON_SCRIPT_END
|
|
|
|
chmod +x /tmp/python_setup.sh
|
|
su - coder -c "/tmp/python_setup.sh"
|
|
rm /tmp/python_setup.sh
|
|
|
|
# =============================================================================
|
|
# Rust and Cargo Setup (as coder user)
|
|
# =============================================================================
|
|
echo "🦀 Installing Rust and Cargo..."
|
|
|
|
# Create Rust setup script
|
|
cat > /tmp/rust_setup.sh << 'RUST_SCRIPT_END'
|
|
#!/bin/bash
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
|
source "/home/coder/.cargo/env"
|
|
echo 'export PATH="/home/coder/.cargo/bin:$PATH"' >> /home/coder/.bashrc
|
|
cargo install cargo-watch cargo-edit cargo-audit
|
|
RUST_SCRIPT_END
|
|
|
|
chmod +x /tmp/rust_setup.sh
|
|
su - coder -c "/tmp/rust_setup.sh"
|
|
rm /tmp/rust_setup.sh
|
|
|
|
# =============================================================================
|
|
# repomix Installation (as coder user)
|
|
# =============================================================================
|
|
echo "📁 Installing repomix..."
|
|
su - coder -c "npm install -g repomix"
|
|
|
|
# =============================================================================
|
|
# Shell Configuration (as coder user)
|
|
# =============================================================================
|
|
echo "🐚 Setting up shell environment..."
|
|
|
|
# Create devinfo script
|
|
cat > /tmp/devinfo_script.sh << 'DEVINFO_SCRIPT_END'
|
|
#!/bin/bash
|
|
mkdir -p /home/coder/bin
|
|
cat > /home/coder/bin/devinfo << 'DEVINFO_END'
|
|
#!/bin/bash
|
|
echo '🚀 Development Environment Info'
|
|
echo '==============================='
|
|
echo ''
|
|
echo '🔧 Installed Tools:'
|
|
echo ' Node.js: '$(node --version 2>/dev/null || echo 'Not found')
|
|
echo ' npm: '$(npm --version 2>/dev/null || echo 'Not found')
|
|
echo ' Python: '$(python${PYTHON_VERSION} --version 2>/dev/null || echo 'Not found')
|
|
echo ' uv: '$(uv --version 2>/dev/null || echo 'Not found')
|
|
echo ' Rust: '$(rustc --version 2>/dev/null || echo 'Not found')
|
|
echo ' Cargo: '$(cargo --version 2>/dev/null || echo 'Not found')
|
|
echo ' repomix: '$(repomix --version 2>/dev/null || echo 'Not found')
|
|
echo ''
|
|
echo '🗄️ Database Services:'
|
|
if [ "${ENABLE_SERVICES}" = "true" ]; then
|
|
echo ' PostgreSQL: '${POSTGRES_URL}
|
|
echo ' Redis: '${REDIS_URL}
|
|
echo ' Qdrant: '${QDRANT_URL}
|
|
else
|
|
echo ' Services disabled'
|
|
fi
|
|
echo ''
|
|
echo '📝 Git Metadata:'
|
|
if [ -f /tmp/git-metadata/current-branch ]; then
|
|
echo ' Branch: '$(cat /tmp/git-metadata/current-branch)
|
|
echo ' Commit: '$(cat /tmp/git-metadata/commit-hash)
|
|
echo ' Remote: '$(cat /tmp/git-metadata/remote-url)
|
|
fi
|
|
DEVINFO_END
|
|
chmod +x /home/coder/bin/devinfo
|
|
DEVINFO_SCRIPT_END
|
|
|
|
chmod +x /tmp/devinfo_script.sh
|
|
su - coder -c "/tmp/devinfo_script.sh"
|
|
rm /tmp/devinfo_script.sh
|
|
|
|
# Create bashrc aliases script
|
|
cat > /tmp/bashrc_setup.sh << 'BASHRC_SCRIPT_END'
|
|
#!/bin/bash
|
|
cat >> /home/coder/.bashrc << 'BASHRC_END'
|
|
|
|
# Development Environment Aliases
|
|
alias ll='ls -alF'
|
|
alias la='ls -A'
|
|
alias l='ls -CF'
|
|
alias gs='git status'
|
|
alias gp='git push'
|
|
alias gc='git commit'
|
|
alias gco='git checkout'
|
|
alias gb='git branch'
|
|
|
|
# Development workflow shortcuts
|
|
alias devinfo='/home/coder/bin/devinfo'
|
|
|
|
# Package managers
|
|
alias pip='uv pip'
|
|
alias python='python${PYTHON_VERSION}'
|
|
|
|
# Docker shortcuts
|
|
alias dps='docker ps'
|
|
alias dimg='docker images'
|
|
alias dlog='docker logs'
|
|
|
|
BASHRC_END
|
|
BASHRC_SCRIPT_END
|
|
|
|
chmod +x /tmp/bashrc_setup.sh
|
|
su - coder -c "/tmp/bashrc_setup.sh"
|
|
rm /tmp/bashrc_setup.sh
|
|
|
|
# =============================================================================
|
|
# Final Environment Setup
|
|
# =============================================================================
|
|
echo "✅ Development environment initialization complete!"
|
|
echo ""
|
|
echo "🎉 Available tools:"
|
|
echo " - Node.js ${NODE_VERSION} with npm packages"
|
|
echo " - Python ${PYTHON_VERSION} with uv package manager"
|
|
echo " - Rust with Cargo"
|
|
echo " - repomix for repository packaging"
|
|
echo " - make, tree, and other build tools"
|
|
if [ "${ENABLE_SERVICES}" = "true" ]; then
|
|
echo " - PostgreSQL, Redis, Qdrant databases"
|
|
fi
|
|
echo ""
|
|
echo "🔧 Run 'devinfo' for detailed environment information"
|
|
echo "🚀 Ready for development!" |