mongo/.devcontainer/post-create.sh

291 lines
11 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# MongoDB Development Container Post-Create Setup Script
# This script handles setup tasks that run when the container is first created,
# including infrastructure setup, developer tooling installation, and workspace
# configuration. Steps are idempotent and safe to re-run.
echo "Starting MongoDB development container post-create setup..."
# Setup user's .bazelrc to import system-wide devcontainer config
echo "Setting up Bazel configuration..."
if [ -f "/etc/devcontainer/bazelrc" ]; then
if [ ! -f "${HOME}/.bazelrc" ]; then
# Create new .bazelrc with import
echo "# Import devcontainer system configuration" >"${HOME}/.bazelrc"
echo "try-import /etc/devcontainer/bazelrc" >>"${HOME}/.bazelrc"
echo "[OK] Created .bazelrc with system config import"
elif ! grep -q "try-import /etc/devcontainer/bazelrc" "${HOME}/.bazelrc" 2>/dev/null; then
# Add import to existing .bazelrc
echo "" >>"${HOME}/.bazelrc"
echo "# Import devcontainer system configuration" >>"${HOME}/.bazelrc"
echo "try-import /etc/devcontainer/bazelrc" >>"${HOME}/.bazelrc"
echo "[OK] Added system config import to existing .bazelrc"
else
echo "Info: .bazelrc already imports system config"
fi
fi
# Fix volume permissions
echo "Fixing volume permissions..."
sudo chown -R "$(whoami)": "${HOME}" || echo "Warning: Could not fix home directory permissions"
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}/python3-venv" || echo "Warning: Could not fix python3-venv permissions"
sudo chown "$(whoami)": "${WORKSPACE_FOLDER}/.." || echo "Warning: Could not fix parent directory permissions"
# Fix workspace root permissions (prevents bazelrc and other file permission issues)
echo "Fixing workspace root permissions..."
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}" || echo "Warning: Could not fix workspace permissions"
# Fix Git repository permissions (prevents "insufficient permission" errors)
echo "Fixing Git repository permissions..."
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}/.git" || echo "Warning: Could not fix .git permissions"
# Configure git safe.directory (prevents "dubious ownership" warnings)
echo "Configuring git safe.directory..."
git config --global --add safe.directory "${WORKSPACE_FOLDER}" || echo "Warning: Could not configure git safe.directory"
echo "[OK] Volume and Git permissions fixed"
# Configure Bazel with Docker information (one-time container setup)
echo "Configuring Bazel with Docker server information..."
# Helper function to add/update Bazel keyword with latest value
add_bazel_keyword() {
local keyword="$1"
local value="$2"
local bazelrc="${HOME}/.bazelrc"
# Ensure bazelrc exists
touch "${bazelrc}"
# Use a temporary file to avoid issues with in-place editing
grep -v "devcontainer:${keyword}" "${bazelrc}" >"${bazelrc}.tmp" 2>/dev/null || true
mv "${bazelrc}.tmp" "${bazelrc}"
# Add the keyword with current value
echo "common --bes_keywords=devcontainer:${keyword}=\"${value}\"" >>"${bazelrc}"
echo "[OK] ${keyword} configured: ${value}"
}
# Report Docker server platform and version
OS_NAME=$(docker info --format '{{.OperatingSystem}}' 2>/dev/null || echo "unknown")
DOCKER_NAME=$(docker info --format '{{.Name}}' 2>/dev/null || echo "unknown")
DOCKER_VERSION=$(docker info --format '{{.ServerVersion}}' 2>/dev/null || echo "unknown")
# Determine platform
if [ "${OS_NAME}" = "Docker Desktop" ]; then
DOCKER_PLATFORM="Docker Desktop"
elif [[ "${DOCKER_NAME}" =~ rancher ]]; then
DOCKER_PLATFORM="Rancher Desktop"
elif [ "${OS_NAME}" != "unknown" ]; then
DOCKER_PLATFORM="${OS_NAME}"
else
DOCKER_PLATFORM="unknown"
fi
add_bazel_keyword "docker_server_platform" "${DOCKER_PLATFORM}"
add_bazel_keyword "docker_server_version" "${DOCKER_VERSION}"
# Report architecture
ARCH=$(uname -i 2>/dev/null || echo "unknown")
add_bazel_keyword "arch" "${ARCH}"
# Unshallow Git repository (one-time setup)
echo "Setting up Git repository..."
# Helper function to handle git shallow lock
wait_for_git_lock() {
local lockfile=".git/shallow.lock"
if [ -f "${lockfile}" ]; then
echo "Warning: Git shallow lock detected, waiting for it to clear..."
local count=0
while [ -f "${lockfile}" ] && [ $count -lt 30 ]; do
sleep 1
((count++))
done
# If lock still exists after 30 seconds, remove it
if [ -f "${lockfile}" ]; then
echo "Warning: Removing stale git shallow lock..."
rm -f "${lockfile}"
fi
fi
}
wait_for_git_lock
# Proceed with git operations
if [ -f .git/shallow ]; then
echo "Info: Detected shallow repository, fetching complete history with tags..."
if git fetch --unshallow --tags; then
echo "[OK] Git repository unshallowed and tags fetched successfully"
else
echo "Warning: Failed to unshallow repository and fetch tags"
echo "Hint: You can manually run: git fetch --unshallow --tags"
fi
else
echo "Info: Repository is already complete, fetching tags..."
if git fetch --tags; then
echo "[OK] Git tags fetched successfully"
else
echo "Warning: Failed to fetch tags"
echo "Hint: You can manually run: git fetch --tags"
fi
fi
# Create Python virtual environment and install dependencies
echo "Creating Python virtual environment..."
venv_created=false
if [ ! -d "${WORKSPACE_FOLDER}/python3-venv/bin" ]; then
export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
/opt/mongodbtoolchain/v5/bin/python3 -m venv "${WORKSPACE_FOLDER}/python3-venv"
venv_created=true
# Install dependencies in the newly created venv
set +o nounset
source "${WORKSPACE_FOLDER}/python3-venv/bin/activate"
set -o nounset
if command -v poetry &>/dev/null; then
POETRY_VIRTUALENVS_IN_PROJECT=true poetry install --no-root --sync
echo "[OK] Python virtual environment created and dependencies installed"
else
echo "Warning: poetry not available, skipping dependency installation"
fi
set +o nounset
deactivate
set -o nounset
else
echo "Info: Python virtual environment already exists"
fi
# Build clang configuration
echo "Building clang configuration..."
# Backup existing .bazelrc.compiledb if it exists, then use our known-good config
COMPILEDB_RC="${WORKSPACE_FOLDER}/.bazelrc.compiledb"
COMPILEDB_RC_BACKUP="${WORKSPACE_FOLDER}/.bazelrc.compiledb.backup"
if [ -f "${COMPILEDB_RC}" ]; then
echo "Info: Backing up existing .bazelrc.compiledb"
mv "${COMPILEDB_RC}" "${COMPILEDB_RC_BACKUP}"
fi
# Create our temporary config for setup (allow remote execution if auth is configured)
echo "common --config=dbg" >"${COMPILEDB_RC}"
# Check for engflow credentials (supports three auth methods: workspace certs, volume certs, or browser token)
if [ -f "${WORKSPACE_FOLDER}/engflow.cert" ] && [ -f "${WORKSPACE_FOLDER}/engflow.key" ]; then
echo "Info: Engflow TLS credentials found in workspace (CI mode), using remote execution"
elif [ -d "${HOME}/.config/engflow_auth" ] && [ -n "$(ls -A ${HOME}/.config/engflow_auth 2>/dev/null)" ]; then
echo "Info: Engflow auth directory exists (likely browser token), using remote execution"
else
echo "Info: No engflow credentials found, using local execution"
echo "common --config=local" >>"${COMPILEDB_RC}"
fi
# Ensure restore happens even if build fails
restore_compiledb_rc() {
if [ -f "${COMPILEDB_RC_BACKUP}" ]; then
echo "Info: Restoring user's .bazelrc.compiledb"
mv "${COMPILEDB_RC_BACKUP}" "${COMPILEDB_RC}"
else
rm -f "${COMPILEDB_RC}"
fi
}
trap restore_compiledb_rc EXIT
if bazel build compiledb; then
echo "[OK] Clang configuration built successfully"
else
echo "Warning: Failed to build clang configuration"
fi
# Setup GDB pretty printers
echo "Setting up GDB pretty printers..."
cd "${WORKSPACE_FOLDER}/.."
if [ -d "Boost-Pretty-Printer" ]; then
echo "Info: Boost-Pretty-Printer already exists"
else
if git clone https://github.com/mongodb-forks/Boost-Pretty-Printer.git; then
if ! grep -q "source ${HOME}/gdbinit" "${HOME}/.gdbinit" 2>/dev/null; then
echo "" >>"${HOME}/.gdbinit"
echo "# BEGIN Server Workflow Tool gdbinit" >>"${HOME}/.gdbinit"
echo "source ${HOME}/gdbinit" >>"${HOME}/.gdbinit"
echo "# END Server Workflow Tool gdbinit" >>"${HOME}/.gdbinit"
fi
echo "[OK] GDB pretty printers installed"
else
echo "Warning: Failed to clone Boost-Pretty-Printer"
fi
fi
cd "${WORKSPACE_FOLDER}"
# Configure automatic Python virtual environment activation
echo "Configuring automatic Python virtual environment activation..."
# Helper function to add Python venv activation to shell config
configure_shell_venv() {
local shell_config="$1"
local shell_name="$2"
if [ -f "${shell_config}" ]; then
if ! grep -q "python3-venv/bin/activate" "${shell_config}" 2>/dev/null; then
cat >>"${shell_config}" <<EOF
# Auto-activate MongoDB Python virtual environment
if [ -f "${WORKSPACE_FOLDER}/python3-venv/bin/activate" ]; then
source "${WORKSPACE_FOLDER}/python3-venv/bin/activate"
fi
EOF
echo "[OK] Python venv activation added to ${shell_name}"
else
echo "Info: Python venv activation already configured in ${shell_name}"
fi
fi
}
if [ -f "${WORKSPACE_FOLDER}/python3-venv/bin/activate" ]; then
configure_shell_venv "${HOME}/.bashrc" ".bashrc"
configure_shell_venv "${HOME}/.zshrc" ".zshrc"
else
echo "Warning: Python virtual environment not found at ${WORKSPACE_FOLDER}/python3-venv"
fi
# Sync Python dependencies
echo "Syncing Python dependencies..."
if [ -f "${WORKSPACE_FOLDER}/python3-venv/bin/activate" ]; then
# Only run sync if venv was just created OR if we're updating an existing one
if [ "${venv_created}" = true ]; then
echo "Info: Skipping sync for newly created venv (already installed via poetry)"
else
source "${WORKSPACE_FOLDER}/python3-venv/bin/activate"
if "${WORKSPACE_FOLDER}/buildscripts/poetry_sync.sh"; then
echo "[OK] Python dependencies synced successfully"
else
echo "Warning: Failed to sync Python dependencies"
fi
deactivate
fi
else
echo "Warning: Python virtual environment not found at ${WORKSPACE_FOLDER}/python3-venv"
fi
# Install Node modules
echo "Installing Node.js dependencies..."
if bazel run @pnpm//:pnpm --config=local -- --dir "${WORKSPACE_FOLDER}" install; then
echo "[OK] Node.js dependencies installed successfully"
else
echo "Error: Failed to install Node.js dependencies"
exit 1
fi
echo ""
echo "MongoDB development container setup completed successfully!"
echo "Info: All infrastructure and dependencies are now configured and up to date."
echo "Info: VS Code Python extension automatically handles virtual environment activation."
echo "Info: You can now start developing with MongoDB!"