Skip to content

Instantly share code, notes, and snippets.

@mokshchadha
Created September 5, 2024 16:23
Show Gist options
  • Save mokshchadha/6c5590e339959a91dc6985b96dee25cb to your computer and use it in GitHub Desktop.
Save mokshchadha/6c5590e339959a91dc6985b96dee25cb to your computer and use it in GitHub Desktop.
pg_freebsd.sh - install custom pg16 on freebsd
#!/bin/sh
# Configuration variables
POSTGRES_VERSION="16.3"
POSTGRES_PREFIX="/usr/local/pgsql"
DATA_DIR="$POSTGRES_PREFIX/data"
LOGFILE="$POSTGRES_PREFIX/logfile"
BUILD_DIR="/tmp/postgresql-build"
PYTHON3_PATH=$(which python3)
# Helper functions
error_exit() {
echo "Error: $1" >&2
cleanup
exit 1
}
warning_message() {
echo "Warning: $1" >&2
}
cleanup() {
echo "Cleaning up..."
[ -d "$BUILD_DIR" ] && rm -rf "$BUILD_DIR" || warning_message "Failed to remove build directory."
}
check_prerequisites() {
# Check for GCC 13
if ! command -v gcc13 >/dev/null 2>&1; then
echo "GCC 13 is not installed. Installing GCC 13..."
pkg install -y gcc13 || error_exit "Failed to install GCC 13. Please install it manually using 'pkg install gcc13'."
else
echo "GCC 13 is installed. Checking version and configuration..."
gcc13 --version
gcc13 -v 2>&1 | grep "Configured with"
# Check for specs file issue
GCC_LIBDIR="/usr/local/lib/gcc13"
SPECS_FILE="$GCC_LIBDIR/specs"
if [ ! -f "$SPECS_FILE" ]; then
echo "specs file not found. Attempting to create..."
if ! gcc13 -dumpspecs > "$SPECS_FILE" 2>/dev/null; then
error_exit "Failed to create specs file. Please check GCC 13 installation."
fi
fi
# Verify GCC functionality
if ! gcc13 -v >/dev/null 2>&1; then
error_exit "GCC 13 is not functioning correctly. Please check your GCC installation."
fi
fi
# Check for GNU Make
if ! command -v gmake >/dev/null 2>&1; then
echo "GNU Make is not installed. Installing GNU Make..."
pkg install -y gmake || error_exit "Failed to install GNU Make. Please install it manually using 'pkg install gmake'."
fi
command -v fetch >/dev/null 2>&1 || error_exit "fetch is required but not installed. Please install it using 'pkg install fetch'."
command -v python3 >/dev/null 2>&1 || error_exit "Python3 is required but not installed. Please install it using 'pkg install python3'."
command -v openssl >/dev/null 2>&1 || error_exit "OpenSSL is required but not installed. Please install it using 'pkg install openssl'."
# Check for pkg-config
if ! command -v pkg-config >/dev/null 2>&1; then
echo "pkg-config is not installed. Installing pkg-config..."
pkg install -y pkgconf || error_exit "Failed to install pkg-config. Please install it manually using 'pkg install pkgconf'."
fi
# Check for LZ4
if ! pkg info -e liblz4 >/dev/null 2>&1; then
echo "LZ4 is not installed. Installing LZ4..."
pkg install -y liblz4 || error_exit "Failed to install LZ4. Please install it manually using 'pkg install liblz4'."
fi
# Verify LZ4 installation
if ! pkg-config --exists liblz4; then
error_exit "LZ4 library not found by pkg-config. Please check your LZ4 installation."
fi
# Check for ICU
if ! pkg info -e icu >/dev/null 2>&1; then
echo "ICU is not installed. Installing ICU..."
pkg install -y icu || error_exit "Failed to install ICU. Please install it manually using 'pkg install icu'."
fi
# Verify ICU installation
if [ -f /usr/local/lib/libicuuc.so ]; then
echo "ICU library found at /usr/local/lib/libicuuc.so"
else
error_exit "ICU library not found at expected location. Please check your ICU installation."
fi
# Print ICU version
echo "ICU version:"
pkg info icu | grep Version
# Print LZ4 version
echo "LZ4 version:"
pkg info liblz4 | grep Version
}
ensure_install_directory() {
if [ ! -d "$POSTGRES_PREFIX" ]; then
mkdir -p "$POSTGRES_PREFIX" || error_exit "Failed to create installation directory."
elif [ ! -w "$POSTGRES_PREFIX" ]; then
chmod u+w "$POSTGRES_PREFIX" || error_exit "Failed to set permissions on installation directory."
fi
}
create_postgres_user() {
if ! pw groupshow postgres >/dev/null 2>&1; then
echo "Creating 'postgres' group..."
pw groupadd postgres || error_exit "Failed to create 'postgres' group."
fi
if ! pw usershow postgres >/dev/null 2>&1; then
echo "Creating 'postgres' user..."
pw useradd postgres -g postgres -m -s /usr/local/bin/bash || error_exit "Failed to create 'postgres' user."
else
echo "'postgres' user already exists."
fi
}
download_postgresql() {
echo "Downloading PostgreSQL $POSTGRES_VERSION..."
mkdir -p "$BUILD_DIR" || error_exit "Failed to create build directory."
cd "$BUILD_DIR" || error_exit "Failed to enter build directory."
if [ ! -f "postgresql-$POSTGRES_VERSION.tar.bz2" ]; then
fetch "https://ftp.postgresql.org/pub/source/v$POSTGRES_VERSION/postgresql-$POSTGRES_VERSION.tar.bz2" || error_exit "Failed to download PostgreSQL source."
else
echo "Source tarball already exists, skipping download."
fi
if [ ! -d "postgresql-$POSTGRES_VERSION" ]; then
tar -xvf "postgresql-$POSTGRES_VERSION.tar.bz2" || error_exit "Failed to extract PostgreSQL source."
else
echo "Source directory already exists, skipping extraction."
fi
cd "postgresql-$POSTGRES_VERSION" || error_exit "Failed to enter PostgreSQL source directory."
}
configure_postgresql() {
echo "Configuring PostgreSQL with custom options..."
PYTHON_INCLUDE_DIR=$($PYTHON3_PATH -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())")
PYTHON_LIB_DIR=$($PYTHON3_PATH -c "from distutils.sysconfig import get_config_var; print(get_config_var('LIBDIR'))")
# Add ICU library and include paths
ICU_LIBS="-L/usr/local/lib -licui18n -licuuc -licudata"
ICU_CFLAGS="-I/usr/local/include"
# Add LZ4 library and include paths
LZ4_LIBS=$(pkg-config --libs liblz4)
LZ4_CFLAGS=$(pkg-config --cflags liblz4)
export CC=gcc13
export LDFLAGS="-L/usr/local/lib -L$PYTHON_LIB_DIR $ICU_LIBS $LZ4_LIBS"
export CPPFLAGS="-I/usr/local/include -I$PYTHON_INCLUDE_DIR $ICU_CFLAGS $LZ4_CFLAGS"
export ICU_LIBS
export ICU_CFLAGS
export LZ4_LIBS
export LZ4_CFLAGS
export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"
export LIBRARY_PATH="/usr/local/lib:$LIBRARY_PATH"
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"
config_command="./configure \
CC=gcc13 \
--prefix=\"$POSTGRES_PREFIX\" \
--with-blocksize=32 \
--with-segsize=8 \
--with-openssl \
--with-ssl=openssl \
--with-lz4 \
--with-python \
--with-icu \
--with-includes=\"/usr/local/include $PYTHON_INCLUDE_DIR\" \
--with-libraries=\"/usr/local/lib $PYTHON_LIB_DIR\""
echo "Configuration command: $config_command"
echo "LDFLAGS: $LDFLAGS"
echo "CPPFLAGS: $CPPFLAGS"
echo "ICU_LIBS: $ICU_LIBS"
echo "ICU_CFLAGS: $ICU_CFLAGS"
echo "LZ4_LIBS: $LZ4_LIBS"
echo "LZ4_CFLAGS: $LZ4_CFLAGS"
echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
echo "LIBRARY_PATH: $LIBRARY_PATH"
echo "PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
# Run configure and capture output
if ! eval $config_command > configure_output.log 2>&1; then
echo "Configuration failed. Last 50 lines of output:"
tail -n 50 configure_output.log
error_exit "Configuration failed. See configure_output.log for details."
fi
}
verify_compilation_options() {
echo "Verifying compilation options..."
grep -E "BLCKSZ|RELSEG_SIZE" src/include/pg_config.h
}
compile_postgresql() {
echo "Compiling PostgreSQL..."
gmake || error_exit "Compilation failed."
echo "Compiling contrib modules (including pg_trgm)..."
cd contrib || error_exit "Failed to enter contrib directory."
gmake || error_exit "Compilation of contrib modules failed."
cd .. || error_exit "Failed to return to main PostgreSQL directory."
verify_compilation_options
}
install_postgresql() {
echo "Installing PostgreSQL..."
gmake install || error_exit "Installation failed."
echo "Installing contrib modules (including pg_trgm)..."
cd contrib || error_exit "Failed to enter contrib directory."
gmake install || error_exit "Installation of contrib modules failed."
cd .. || error_exit "Failed to return to main PostgreSQL directory."
}
setup_environment() {
echo "Setting up environment variables..."
if ! grep -q "$POSTGRES_PREFIX/bin" /etc/profile; then
echo "export PATH=\"$POSTGRES_PREFIX/bin:\$PATH\"" >> /etc/profile || warning_message "Failed to update /etc/profile."
. /etc/profile || warning_message "Failed to source /etc/profile."
else
echo "PATH already includes $POSTGRES_PREFIX/bin."
fi
}
initialize_database() {
echo "Initializing the PostgreSQL database..."
mkdir -p "$DATA_DIR" || error_exit "Failed to create data directory."
chown postgres:postgres "$DATA_DIR"
su -m postgres -c "$POSTGRES_PREFIX/bin/initdb -D $DATA_DIR" || error_exit "Database initialization failed."
}
create_extension_pg_trgm() {
echo "Creating pg_trgm extension..."
su -m postgres -c "$POSTGRES_PREFIX/bin/psql -d postgres -c 'CREATE EXTENSION IF NOT EXISTS pg_trgm;'" || warning_message "Failed to create pg_trgm extension. You may need to create it manually in your databases."
}
start_postgresql() {
echo "Starting PostgreSQL..."
su -m postgres -c "$POSTGRES_PREFIX/bin/pg_ctl -D $DATA_DIR -l $LOGFILE -w start"
sleep 5 # Give the server a moment to start up
if ! su -m postgres -c "$POSTGRES_PREFIX/bin/pg_isready -q"; then
check_log_file
error_exit "Failed to start PostgreSQL."
fi
echo "PostgreSQL started successfully."
}
check_log_file() {
echo "Checking PostgreSQL log file for errors..."
if [ -f "$LOGFILE" ]; then
tail -n 50 "$LOGFILE"
else
echo "Log file not found at $LOGFILE"
fi
}
verify_custom_options() {
echo "Verifying custom build options..."
su -m postgres -c "$POSTGRES_PREFIX/bin/psql -d postgres -c \"SHOW block_size;\"" || warning_message "Failed to verify block size."
su -m postgres -c "$POSTGRES_PREFIX/bin/psql -d postgres -c \"SHOW segment_size;\"" || warning_message "Failed to verify segment size."
echo "Checking PostgreSQL version and compile-time options:"
su -m postgres -c "$POSTGRES_PREFIX/bin/postgres -V"
su -m postgres -c "$POSTGRES_PREFIX/bin/pg_config --configure"
echo "Verifying pg_trgm extension installation:"
su -m postgres -c "$POSTGRES_PREFIX/bin/psql -d postgres -c \"SELECT * FROM pg_extension WHERE extname = 'pg_trgm';\"" || warning_message "Failed to verify pg_trgm extension."
}
stop_postgresql() {
echo "Stopping PostgreSQL..."
if command -v "$POSTGRES_PREFIX/bin/pg_ctl" > /dev/null 2>&1; then
su -m postgres -c "$POSTGRES_PREFIX/bin/pg_ctl -D $DATA_DIR stop -m fast" || warning_message "Failed to stop PostgreSQL."
else
echo "pg_ctl command not found; assuming PostgreSQL is not running."
fi
}
uninstall_postgresql() {
echo "Uninstalling PostgreSQL..."
stop_postgresql
if [ -d "$POSTGRES_PREFIX" ]; then
rm -rf "$POSTGRES_PREFIX" || warning_message "Failed to remove PostgreSQL directories."
echo "PostgreSQL uninstalled successfully."
else
echo "No PostgreSQL installation detected."
fi
}
perform_installation() {
check_prerequisites
create_postgres_user
ensure_install_directory
download_postgresql
configure_postgresql
compile_postgresql
install_postgresql
setup_environment
initialize_database
start_postgresql
create_extension_pg_trgm
check_log_file
verify_custom_options
echo "PostgreSQL installed and configured successfully with pg_trgm extension!"
}
# Ensure cleanup happens on script exit
trap cleanup EXIT
# Main function
case "$1" in
stop)
stop_postgresql
;;
uninstall)
uninstall_postgresql
;;
install)
perform_installation
;;
*)
echo "Usage: $0 {install|stop|uninstall}"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment