datahaven/.github/workflows/actions/setup-env/action.yml
2025-12-02 15:42:43 +01:00

227 lines
No EOL
9.3 KiB
YAML

name: "Setup Rust Environment"
description: "Creates a Rust environment with the specified toolchain, cache, and dependencies"
inputs:
cache-key:
description: "Cache key used to retrieve built data. Usually matches the profile of the build"
required: false
default: "cache"
install-deps:
description: "Whether to install system dependencies. Set to false for self-hosted runners with pre-installed deps"
required: false
default: "true"
runs:
using: "composite"
steps:
- name: Set Rust version
shell: bash
run: |
echo "BUILD_RUST_VERSION=$(rustc --version)" >> $GITHUB_ENV
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Show sccache stats
shell: bash
run: sccache --show-stats
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
# Install mold - always install locally to avoid sudo requirements
- name: Install mold
shell: bash
run: |
# Check if mold is already available and the right version
MOLD_VERSION="2.40.4"
if ! command -v mold &> /dev/null || [[ $(mold --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1) != "$MOLD_VERSION" ]]; then
echo "Installing mold $MOLD_VERSION in ~/.local"
mkdir -p ~/.local/bin
wget -q -O- "https://github.com/rui314/mold/releases/download/v${MOLD_VERSION}/mold-${MOLD_VERSION}-$(uname -m)-linux.tar.gz" | \
tar -xzf - -C ~/.local --strip-components=1
echo "$HOME/.local/bin" >> $GITHUB_PATH
export PATH="$HOME/.local/bin:$PATH"
else
echo "mold is already installed: $(mold --version)"
fi
# Export the mold path for use in RUSTFLAGS
MOLD_PATH=$(which mold)
echo "MOLD_PATH=${MOLD_PATH}" >> $GITHUB_ENV
echo "Mold installed at: ${MOLD_PATH}"
# Install system dependencies only when install-deps is true
- name: Install system dependencies
if: inputs.install-deps == 'true'
shell: bash
run: sudo apt-get update && sudo apt-get install -y libpq-dev libclang-dev
# Auto-install missing dependencies when install-deps is false (for self-hosted runners)
- name: Setup system dependencies (self-hosted)
if: inputs.install-deps == 'false'
shell: bash
run: |
echo "Checking and installing system dependencies locally if needed..."
# Setup local directories
LOCAL_DIR="$HOME/.local"
LOCAL_BIN="$LOCAL_DIR/bin"
LOCAL_LIB="$LOCAL_DIR/lib"
LOCAL_INCLUDE="$LOCAL_DIR/include"
LOCAL_PKG_CONFIG="$LOCAL_DIR/lib/pkgconfig"
mkdir -p "$LOCAL_BIN" "$LOCAL_LIB" "$LOCAL_INCLUDE" "$LOCAL_PKG_CONFIG"
# Export paths for future steps (avoid duplication)
echo "$LOCAL_BIN" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LOCAL_LIB:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$LOCAL_PKG_CONFIG:${PKG_CONFIG_PATH:-}" >> $GITHUB_ENV
echo "C_INCLUDE_PATH=$LOCAL_INCLUDE:${C_INCLUDE_PATH:-}" >> $GITHUB_ENV
echo "CPLUS_INCLUDE_PATH=$LOCAL_INCLUDE:${CPLUS_INCLUDE_PATH:-}" >> $GITHUB_ENV
# Check and install PostgreSQL client libraries if needed
if ! pkg-config --exists libpq 2>/dev/null; then
echo "Installing libpq..."
ARCH=$(dpkg --print-architecture 2>/dev/null || echo "amd64")
WORK_DIR="$LOCAL_DIR/tmp"
mkdir -p "$WORK_DIR" && cd "$WORK_DIR"
# Download PostgreSQL 18 packages
wget -q "https://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-18/libpq5_18.1-1.pgdg+2_${ARCH}.deb"
wget -q "https://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-18/libpq-dev_18.1-1.pgdg+2_${ARCH}.deb"
# Extract and install
for pkg in *.deb; do
ar p "$pkg" data.tar.xz | tar -xJ --no-same-owner 2>/dev/null || true
done
cp -r usr/lib/*/libpq* usr/lib/libpq* "$LOCAL_LIB/" 2>/dev/null || true
cp -r usr/include/* "$LOCAL_INCLUDE/" 2>/dev/null || true
find usr -name "*.pc" -exec cp {} "$LOCAL_PKG_CONFIG/" \; 2>/dev/null || true
# Fix pkg-config paths
sed -i "s|/usr|$LOCAL_DIR|g" "$LOCAL_PKG_CONFIG"/*.pc 2>/dev/null || true
cd "$HOME" && rm -rf "$WORK_DIR"
# Export build flags for libpq
echo "LDFLAGS=-L$LOCAL_LIB ${LDFLAGS:-}" >> $GITHUB_ENV
echo "CPPFLAGS=-I$LOCAL_INCLUDE ${CPPFLAGS:-}" >> $GITHUB_ENV
echo "LIBRARY_PATH=$LOCAL_LIB:${LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "RUSTFLAGS=-L $LOCAL_LIB" >> $GITHUB_ENV
echo "✓ libpq installed"
else
echo "✓ libpq found: $(pkg-config --modversion libpq 2>/dev/null || echo 'version unknown')"
fi
# Check and install LLVM/Clang if needed
if ! command -v clang &> /dev/null || ! ls $LOCAL_LIB/libclang* 2>/dev/null && ! ldconfig -p 2>/dev/null | grep -q libclang; then
echo "LLVM/Clang not found, installing locally..."
LLVM_VERSION="18.1.8"
ARCH=$(uname -m)
# Map architecture names
case "$ARCH" in
x86_64) LLVM_ARCH="x86_64-linux-gnu-ubuntu-22.04" ;;
aarch64) LLVM_ARCH="aarch64-linux-gnu" ;;
*) LLVM_ARCH="$ARCH-linux-gnu" ;;
esac
# Download pre-built LLVM/Clang binaries
echo "Downloading LLVM ${LLVM_VERSION} for ${LLVM_ARCH}..."
wget -q -O- "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-${LLVM_ARCH}.tar.xz" | \
tar -xJf - -C /tmp --strip-components=1 || {
echo "Failed to download pre-built binaries, trying alternative version..."
# Try an older, more widely available version
LLVM_VERSION="17.0.6"
wget -q -O- "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-${LLVM_ARCH}.tar.xz" | \
tar -xJf - -C /tmp --strip-components=1
}
# Copy required files
if [ -d "/tmp/bin" ]; then
cp /tmp/bin/clang* "$LOCAL_BIN/" 2>/dev/null || true
cp /tmp/bin/llvm-config "$LOCAL_BIN/" 2>/dev/null || true
cp -r /tmp/lib/libclang* "$LOCAL_LIB/" 2>/dev/null || true
cp -r /tmp/lib/clang "$LOCAL_LIB/" 2>/dev/null || true
cp -r /tmp/include/clang* "$LOCAL_INCLUDE/" 2>/dev/null || true
rm -rf /tmp/bin /tmp/lib /tmp/include /tmp/share
# Set LIBCLANG_PATH for rust bindgen
echo "LIBCLANG_PATH=$LOCAL_LIB" >> $GITHUB_ENV
echo "LLVM_CONFIG_PATH=$LOCAL_BIN/llvm-config" >> $GITHUB_ENV
fi
echo "✓ LLVM/Clang ${LLVM_VERSION} installed locally"
else
echo "✓ clang found: $(clang --version 2>/dev/null | head -n1 || echo 'installed')"
fi
echo "All required system dependencies ready!"
# Install protoc only when install-deps is true
- name: Install Protoc
if: inputs.install-deps == 'true'
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ github.token }}
# Auto-install protoc when install-deps is false (for self-hosted runners)
- name: Setup Protoc (self-hosted)
if: inputs.install-deps == 'false'
shell: bash
run: |
echo "Checking and installing protoc locally if needed..."
if ! command -v protoc &> /dev/null; then
echo "protoc not found, installing locally..."
PROTOC_VERSION="28.3"
ARCH=$(uname -m)
# Map architecture names for protoc
case "$ARCH" in
x86_64) PROTOC_ARCH="x86_64" ;;
aarch64) PROTOC_ARCH="aarch_64" ;;
*) PROTOC_ARCH="$ARCH" ;;
esac
# Download and install protoc
mkdir -p ~/.local/bin
wget -q -O /tmp/protoc.zip "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip"
unzip -q -o /tmp/protoc.zip -d ~/.local
rm /tmp/protoc.zip
# Make sure it's executable
chmod +x ~/.local/bin/protoc
# Add to PATH if not already there
echo "$HOME/.local/bin" >> $GITHUB_PATH
export PATH="$HOME/.local/bin:$PATH"
echo "✓ protoc ${PROTOC_VERSION} installed locally"
else
PROTOC_VERSION=$(protoc --version | grep -oP '\d+\.\d+(\.\d+)?')
echo "✓ protoc found: version $PROTOC_VERSION"
# Check minimum version (3.0 or higher recommended)
MAJOR_VERSION=$(echo $PROTOC_VERSION | cut -d. -f1)
if [ "$MAJOR_VERSION" -lt 3 ]; then
echo "WARNING: protoc version $PROTOC_VERSION is older than recommended (3.0+)"
fi
fi
echo "Protoc ready!"