#!/bin/bash
log() { echo "[post-create] $*"; }
warn() { echo "[post-create] WARN: $*"; }
configure_user_bin() {
log "Configuring user bin directory..."
mkdir -p "$HOME/.local/bin"
npm config set prefix "$HOME/.local" 2>/dev/null || warn "npm config set prefix failed"
local marker="# mspti-devcontainer-user-bin"
for rcfile in "$HOME/.bashrc" "$HOME/.bash_profile"; do
if [ -f "$rcfile" ] && ! grep -qF "$marker" "$rcfile"; then
cat >> "$rcfile" <<EOF
$marker
export PATH="\$HOME/.local/bin:\$PATH"
EOF
log "Appended PATH to $rcfile"
fi
done
}
configure_python3() {
log "Configuring Python 3..."
if [ -f "/etc/profile.d/pyenv.sh" ]; then
source /etc/profile.d/pyenv.sh 2>/dev/null || warn "Failed to source pyenv.sh"
log "Loaded pyenv profile"
fi
local pyenv_python=""
for candidate in /opt/python/cp*-cp*; do
if [ -d "$candidate/bin" ] && [ -x "$candidate/bin/python3" ]; then
pyenv_python="$candidate/bin"
break
fi
done
if [ -n "$pyenv_python" ]; then
log "Python (pyenv) found at $pyenv_python"
local marker="# mspti-pyenv-python"
for rcfile in "$HOME/.bashrc" "$HOME/.bash_profile"; do
if [ -f "$rcfile" ] && ! grep -qF "$marker" "$rcfile"; then
cat >> "$rcfile" <<EOF
$marker
export PATH="$pyenv_python:\$PATH"
EOF
log "Prepended pyenv Python to PATH in $rcfile"
fi
done
export PATH="$pyenv_python:$PATH"
else
warn "pyenv Python not found, using default: $(python3 --version 2>&1)"
fi
}
install_build_deps() {
log "Installing system build dependencies..."
if command -v dnf &>/dev/null; then
local sys_pkgs=(
python3-devel
)
local missing_sys=()
for pkg in "${sys_pkgs[@]}"; do
if ! rpm -q "$pkg" &>/dev/null; then
missing_sys+=("$pkg")
else
log " System pkg OK: $pkg"
fi
done
if [ ${#missing_sys[@]} -gt 0 ]; then
log " Installing: ${missing_sys[*]}"
sudo dnf install -y "${missing_sys[@]}" 2>/dev/null || warn "dnf install failed: ${missing_sys[*]}"
fi
if ! command -v gitleaks &>/dev/null; then
log " Installing gitleaks..."
GITLEAKS_VER="8.18.4"
case "$(uname -m)" in
x86_64) GITLEAKS_ARCH="amd64"; GITLEAKS_SHA256="";;
aarch64) GITLEAKS_ARCH="arm64"; GITLEAKS_SHA256="";;
*) warn "Unsupported architecture $(uname -m), skipping gitleaks"; return;;
esac
GITLEAKS_INSTALLED=false
for MIRROR in \
"https://ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz" \
"https://mirror.ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz"; do
log " Trying: ${MIRROR}"
curl -fsSL "${MIRROR}" -o /tmp/gitleaks.tar.gz --connect-timeout 10 2>/dev/null && \
sudo tar -xzf /tmp/gitleaks.tar.gz -C /usr/local/bin gitleaks 2>/dev/null && \
GITLEAKS_INSTALLED=true && break
rm -f /tmp/gitleaks.tar.gz
done
if ${GITLEAKS_INSTALLED}; then
sudo chmod +x /usr/local/bin/gitleaks
log " gitleaks ${GITLEAKS_VER} (${GITLEAKS_ARCH}) installed"
else
warn "gitleaks install failed (all mirrors unreachable)"
fi
else
log " System pkg OK: gitleaks"
fi
elif command -v apt-get &>/dev/null; then
local sys_pkgs=(
python3-dev
)
local missing_sys=()
for pkg in "${sys_pkgs[@]}"; do
if ! dpkg -s "$pkg" &>/dev/null; then
missing_sys+=("$pkg")
else
log " System pkg OK: $pkg"
fi
done
if [ ${#missing_sys[@]} -gt 0 ]; then
log " Installing: ${missing_sys[*]}"
sudo apt-get update -qq && sudo apt-get install -y "${missing_sys[@]}" 2>/dev/null || warn "apt-get install failed: ${missing_sys[*]}"
fi
fi
local pip_pkgs=(
packaging
wheel
pre-commit
"bandit[toml]"
)
for PY in $(command -v python3 2>/dev/null) $(command -v python 2>/dev/null); do
log "Installing pip packages for: $($PY --version 2>&1)"
"$PY" -m pip install --quiet --upgrade pip setuptools >/dev/null 2>&1 || warn "pip/setuptools upgrade failed for $PY"
local missing_pip=()
for pkg in "${pip_pkgs[@]}"; do
if ! "$PY" -m pip show "$pkg" &>/dev/null; then
missing_pip+=("$pkg")
else
log " Pip pkg OK ($PY): $pkg"
fi
done
if [ ${#missing_pip[@]} -gt 0 ]; then
log " Installing for $PY: ${missing_pip[*]}"
"$PY" -m pip install "${missing_pip[@]}" || warn "pip install failed for $PY: ${missing_pip[*]}"
fi
done
if [ -f "scripts/download_thirdparty.sh" ]; then
log "Pre-downloading third-party dependencies..."
bash scripts/download_thirdparty.sh 2>/dev/null || warn "Third-party download failed (will retry during build)"
fi
log "Build dependencies check complete"
}
sync_git_identity() {
log "Syncing Git identity..."
local gitconfig="/home/mindstudio/.devcontainer-host-gitconfig"
if [ -f "$gitconfig" ] && [ -s "$gitconfig" ]; then
local name email
name=$(git config --file "$gitconfig" --get user.name 2>/dev/null) || true
email=$(git config --file "$gitconfig" --get user.email 2>/dev/null) || true
[ -n "$name" ] && git config --global user.name "$name"
[ -n "$email" ] && git config --global user.email "$email"
log "Git identity synced from host"
else
warn "No host Git config found, skipping identity sync"
fi
}
append_dev_hint_once() {
local marker="# mspti-dev-hint"
local rcfile="$HOME/.bashrc"
if grep -qF "$marker" "$rcfile" 2>/dev/null; then
return
fi
cat >> "$rcfile" <<EOF
$marker
# mspti development commands:
# python3 build.py Build Release (full)
# python3 build.py local Build Release (skip deps)
# python3 build.py test Build and run unit tests
# python3 build.py test local Run unit tests (skip deps)
EOF
log "Appended dev hints to $rcfile"
}
install_pre_commit_hook() {
log "Installing pre-commit hook..."
export PATH="$HOME/.local/bin:$PATH"
local pre_commit_cmd=""
if command -v pre-commit &>/dev/null; then
pre_commit_cmd="pre-commit"
elif python3 -m pre_commit --version &>/dev/null 2>&1; then
pre_commit_cmd="python3 -m pre_commit"
elif python -m pre_commit --version &>/dev/null 2>&1; then
pre_commit_cmd="python -m pre_commit"
else
warn "pre-commit not found, skipping hook installation"
return
fi
if ! git rev-parse --git-dir &>/dev/null; then
warn "Not a Git repository, skipping pre-commit hook"
return
fi
$pre_commit_cmd install || warn "pre-commit install failed"
log "pre-commit hook installed via: $pre_commit_cmd"
}
setup_clangd() {
log "Setting up clangd..."
if command -v clangd &>/dev/null; then
log "clangd found: $(clangd --version 2>&1 | head -1)"
return
fi
warn "clangd not found, attempting to install..."
if command -v dnf &>/dev/null; then
sudo dnf install -y clangd 2>/dev/null || sudo dnf install -y clang-tools-extra 2>/dev/null || warn "Failed to install clangd via dnf"
elif command -v apt-get &>/dev/null; then
sudo apt-get update -qq && sudo apt-get install -y clangd 2>/dev/null || warn "Failed to install clangd via apt-get"
else
warn "Cannot install clangd automatically"
fi
if command -v clangd &>/dev/null; then
log "clangd installed successfully"
else
warn "clangd is not available, C++ IDE features will be limited"
fi
}
ignore_local_changes() {
log "Setting up skip-worktree for local-modifiable files..."
if [ -f ".vscode/settings.json" ]; then
git update-index --skip-worktree .vscode/settings.json 2>/dev/null || true
log " skip-worktree: .vscode/settings.json"
fi
if [ -f "version.info" ]; then
git update-index --skip-worktree version.info 2>/dev/null || true
log " skip-worktree: version.info"
fi
}
check_compile_commands() {
if [ ! -f "build/compile_commands.json" ]; then
warn "build/compile_commands.json not found (expected on cold start)"
warn "Run 'python3 build.py' to generate it for clangd support"
else
log "compile_commands.json found, clangd ready"
fi
}
log "Starting container initialization (mspti)..."
configure_user_bin
configure_python3
install_build_deps
sync_git_identity
append_dev_hint_once
install_pre_commit_hook
setup_clangd
ignore_local_changes
check_compile_commands
log "Container initialization complete!"