361 lines
13 KiB
Bash
Executable File
361 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# WordPress Version Check and Update Script
|
|
# Copyright 2024 A.D. Federated Computer, Inc.
|
|
# saint@federated.computer
|
|
# ---------------------------------------
|
|
# This script checks the running WordPress version in a Docker container and updates
|
|
# the IMAGE_VERSION in the .env file to match if needed.
|
|
#
|
|
# Version Detection Methods (in order):
|
|
# 1. WP-CLI: Uses 'wp core version'
|
|
# 2. PHP Direct: Uses wp_eval to get bloginfo('version')
|
|
# 3. File Check: Reads version from /bitnami/wordpress/wp-includes/version.php
|
|
# 4. Database Primary: Reads from wp_options._transient_wp_core_block_css_files
|
|
# 5. Database Backup: Reads from wp_options._site_transient_update_core
|
|
#
|
|
# The script will:
|
|
# - Use the highest valid version found from any method
|
|
# - Check if that version is newer than the one in .env
|
|
# - If newer, look for matching Docker image on Docker Hub
|
|
# - If exact version not found, use next newer version or closest older version
|
|
# - Update .env with the new version and add IMAGE_VERSION_HOLD=true if needed
|
|
|
|
# Enable debug output
|
|
## set -x
|
|
|
|
# Set your container name and .env file path
|
|
CONTAINER_NAME="wordpress"
|
|
APP_DIR="/federated/apps/$CONTAINER_NAME"
|
|
ENV_FILE="$APP_DIR/.env"
|
|
DOCKER_COMPOSE_FILE="$APP_DIR/docker-compose.yml"
|
|
|
|
# Function to validate version string
|
|
is_valid_version() {
|
|
local version=$1
|
|
# Allow x, x.y, x.y.z, or x.y.z.a where all parts are integers
|
|
[[ $version =~ ^[0-9]+(\.[0-9]+)*$ ]] || return 1
|
|
# Count parts
|
|
local parts
|
|
IFS='.' read -ra parts <<< "$version"
|
|
# Allow 1 to 4 parts
|
|
[ ${#parts[@]} -le 4 ] || return 1
|
|
return 0
|
|
}
|
|
|
|
echo "Starting WordPress version check and update script..."
|
|
|
|
# Function to get version from different sources
|
|
get_wp_version() {
|
|
local wpcli_version php_version file_version db_version admin_version highest_version
|
|
|
|
# 1. Try wp-cli version
|
|
wpcli_version=$(docker exec "$CONTAINER_NAME" wp core version --allow-root) || true
|
|
if ! is_valid_version "$wpcli_version"; then wpcli_version=""; fi
|
|
|
|
# 2. Try version.php direct access
|
|
php_version=$(docker exec "$CONTAINER_NAME" wp eval 'echo get_bloginfo("version");' --allow-root) || true
|
|
if ! is_valid_version "$php_version"; then php_version=""; fi
|
|
|
|
# 3. Try direct file content check (fixed quotes)
|
|
file_version=$(docker exec "$CONTAINER_NAME" bash -c "grep '\\\$wp_version = ' /bitnami/wordpress/wp-includes/version.php | sed -n 's/.*= .\\([0-9.]*\\).*/\\1/p'") || true
|
|
if [ -z "$file_version" ]; then
|
|
file_version=$(docker exec "$CONTAINER_NAME" bash -c "grep '\\\$wp_version = ' /opt/bitnami/wordpress/wp-includes/version.php | sed -n 's/.*= .\\([0-9.]*\\).*/\\1/p'") || true
|
|
fi
|
|
if ! is_valid_version "$file_version"; then file_version=""; fi
|
|
|
|
# 4. Try database version through wp-cli with socket path
|
|
db_version=$(docker exec "$CONTAINER_NAME" bash -c '
|
|
is_valid_version() {
|
|
local version=$1
|
|
# Allow x, x.y, x.y.z, or x.y.z.a formats
|
|
[[ $version =~ ^[0-9]+(\.[0-9]+)*$ ]] || return 1
|
|
# Count parts and ensure not more than 4
|
|
local parts
|
|
IFS='.' read -ra parts <<< "$version"
|
|
[ ${#parts[@]} -le 4 ] || return 1
|
|
return 0
|
|
}
|
|
|
|
if [ -f /opt/bitnami/mysql/bin/mariadb ]; then
|
|
MYSQL_CMD="/opt/bitnami/mysql/bin/mariadb"
|
|
else
|
|
MYSQL_CMD="/opt/bitnami/mysql/bin/mysql"
|
|
fi
|
|
export MYSQL_PWD="$WORDPRESS_DATABASE_PASSWORD"
|
|
|
|
# First try _transient_wp_core_block_css_files as it has simpler structure
|
|
version=$($MYSQL_CMD -u "$WORDPRESS_DATABASE_USER" \
|
|
-h "$WORDPRESS_DATABASE_HOST" \
|
|
--skip-ssl \
|
|
"$WORDPRESS_DATABASE_NAME" \
|
|
-N -e "SELECT option_value FROM wp_options WHERE option_name = \"_transient_wp_core_block_css_files\";" | \
|
|
sed -n "s/.*s:7:\"version\";s:[0-9]*:\"\([0-9][0-9.]*\)\".*/\1/p")
|
|
|
|
# Validate first version before accepting it
|
|
if ! is_valid_version "$version"; then
|
|
# If first attempt fails or gives invalid version, try _site_transient_update_core
|
|
version=$($MYSQL_CMD -u "$WORDPRESS_DATABASE_USER" \
|
|
-h "$WORDPRESS_DATABASE_HOST" \
|
|
--skip-ssl \
|
|
"$WORDPRESS_DATABASE_NAME" \
|
|
-N -e "SELECT option_value FROM wp_options WHERE option_name = \"_site_transient_update_core\";" | \
|
|
sed -n "s/.*\"version_checked\":\"\([0-9][0-9.]*\)\".*/\1/p")
|
|
fi
|
|
|
|
# Only output version if it is valid
|
|
if is_valid_version "$version"; then
|
|
echo "$version"
|
|
fi
|
|
') || true
|
|
if ! is_valid_version "$db_version"; then db_version=""; fi
|
|
|
|
# 5. Try reading version from version.php using PHP
|
|
admin_version=$(docker exec "$CONTAINER_NAME" bash -c "php -r '
|
|
\$files = array(\"/bitnami/wordpress/wp-includes/version.php\", \"/opt/bitnami/wordpress/wp-includes/version.php\");
|
|
foreach (\$files as \$file) {
|
|
if (file_exists(\$file)) {
|
|
include \$file;
|
|
echo \$wp_version;
|
|
break;
|
|
}
|
|
}
|
|
'") || true
|
|
if ! is_valid_version "$admin_version"; then admin_version=""; fi
|
|
|
|
# Log all found versions (to stderr for debugging)
|
|
{
|
|
echo "WP-CLI reports version: ${wpcli_version:-not found}" >&2
|
|
echo "wp eval reports version: ${php_version:-not found}" >&2
|
|
echo "File check reports version: ${file_version:-not found}" >&2
|
|
echo "Database reports version: ${db_version:-not found}" >&2
|
|
echo "Admin page reports version: ${admin_version:-not found}" >&2
|
|
}
|
|
|
|
# Compare all versions and take the highest one, excluding db version
|
|
local versions=()
|
|
[ ! -z "$wpcli_version" ] && versions+=("$wpcli_version")
|
|
[ ! -z "$php_version" ] && versions+=("$php_version")
|
|
[ ! -z "$file_version" ] && versions+=("$file_version")
|
|
[ ! -z "$admin_version" ] && versions+=("$admin_version")
|
|
|
|
if [ ${#versions[@]} -eq 0 ]; then
|
|
echo "Error: Could not determine WordPress version from any source" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Return just the version number
|
|
printf '%s\n' "${versions[@]}" | sort -V | tail -n 1
|
|
}
|
|
|
|
# Function to find closest available version on Docker Hub
|
|
find_closest_version() {
|
|
local target_version=$1
|
|
local available_versions=""
|
|
local page=1
|
|
local page_size=100
|
|
local next_url="https://hub.docker.com/v2/repositories/bitnami/wordpress/tags?page_size=$page_size"
|
|
|
|
echo "Retrieving available WordPress versions from Docker Hub..." >&2
|
|
|
|
# Keep fetching pages until we hit an empty page or no next URL
|
|
while [ ! -z "$next_url" ]; do
|
|
echo "Fetching page $page..." >&2
|
|
|
|
# Get the current page and extract versions and next URL
|
|
local response=$(curl -s "$next_url")
|
|
|
|
# Extract versions from this page
|
|
local page_versions=$(echo "$response" | \
|
|
grep -o '"name":"[^"]*"' | \
|
|
grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | \
|
|
sort -V | uniq)
|
|
|
|
# If we got no versions, break
|
|
if [ -z "$page_versions" ]; then
|
|
break
|
|
fi
|
|
|
|
# Append to our list of versions
|
|
available_versions="$available_versions"$'\n'"$page_versions"
|
|
|
|
# Get next page URL and decode \u0026 to &
|
|
next_url=$(echo "$response" | \
|
|
grep -o '"next":"[^"]*"' | \
|
|
cut -d'"' -f4 | \
|
|
sed 's/\\u0026/\&/g' )
|
|
|
|
# If no next URL or we've hit page limit, break
|
|
if [ -z "$next_url" ] || [ $page -ge 10 ]; then
|
|
break
|
|
fi
|
|
|
|
((page++))
|
|
done
|
|
|
|
# Clean up and sort the final list
|
|
available_versions=$(echo "$available_versions" | grep -v '^$' | sort -V | uniq)
|
|
|
|
if [ -z "$available_versions" ]; then
|
|
echo "Failed to get versions from Docker Hub" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Print all versions for debugging
|
|
echo "Available versions:" >&2
|
|
echo "$available_versions" >&2
|
|
|
|
# First, check if target version exists
|
|
if echo "$available_versions" | grep -Fxq "$target_version"; then
|
|
printf '%s\n' "$target_version"
|
|
return 0
|
|
fi
|
|
|
|
# If not, find next newer version
|
|
local newer_version
|
|
newer_version=$(echo "$available_versions" | awk -v ver="$target_version" '$1 > ver' | head -n1)
|
|
|
|
# If no newer version, find closest older version
|
|
if [ -z "$newer_version" ]; then
|
|
echo "$available_versions" | awk -v ver="$target_version" '$1 <= ver' | tail -n1
|
|
else
|
|
printf '%s\n' "$newer_version"
|
|
fi
|
|
}
|
|
|
|
# Function to compare version numbers
|
|
version_greater_than() {
|
|
local ver1=$1
|
|
local ver2=$2
|
|
|
|
if ! is_valid_version "$ver1" || ! is_valid_version "$ver2"; then
|
|
echo "Invalid version format" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Convert versions to arrays
|
|
local v1_parts=() v2_parts=()
|
|
IFS='.' read -ra v1_parts <<< "$ver1"
|
|
IFS='.' read -ra v2_parts <<< "$ver2"
|
|
|
|
# Pad shorter version with zeros
|
|
while [ ${#v1_parts[@]} -lt 4 ]; do
|
|
v1_parts+=("0")
|
|
done
|
|
while [ ${#v2_parts[@]} -lt 4 ]; do
|
|
v2_parts+=("0")
|
|
done
|
|
|
|
# Compare each part numerically
|
|
for i in {0..3}; do
|
|
if [ "${v1_parts[i]:-0}" -gt "${v2_parts[i]:-0}" ]; then
|
|
return 0 # ver1 is greater
|
|
elif [ "${v1_parts[i]:-0}" -lt "${v2_parts[i]:-0}" ]; then
|
|
return 1 # ver1 is not greater
|
|
fi
|
|
done
|
|
return 1 # versions are equal
|
|
}
|
|
|
|
# Test cases (can be commented out in production)
|
|
test_versions() {
|
|
local test_pairs=(
|
|
"6.7 6.6.2" # should return 0 (true)
|
|
"7 6.7" # should return 0 (true)
|
|
"6.6.2 6.6.2" # should return 1 (false)
|
|
"6.6.1 6.6.2" # should return 1 (false)
|
|
"6.7.0 6.7" # should return 1 (false)
|
|
"6.7.1 6.7" # should return 0 (true)
|
|
"6.7.0.1 6.7" # should return 0 (true)
|
|
)
|
|
|
|
echo "Running version comparison tests..."
|
|
for pair in "${test_pairs[@]}"; do
|
|
read -r v1 v2 <<< "$pair"
|
|
if version_greater_than "$v1" "$v2"; then
|
|
echo "$v1 > $v2 (OK)"
|
|
else
|
|
echo "$v1 <= $v2"
|
|
fi
|
|
done
|
|
|
|
echo "Running version validation tests..."
|
|
local test_versions=(
|
|
"6" # valid
|
|
"6.7" # valid
|
|
"6.7.2" # valid
|
|
"6.7.2.1" # valid
|
|
"6.7.2.1.5" # invalid
|
|
"6.7.2a" # invalid
|
|
"6.7." # invalid
|
|
".6.7" # invalid
|
|
"a.b.c" # invalid
|
|
)
|
|
|
|
for ver in "${test_versions[@]}"; do
|
|
if is_valid_version "$ver"; then
|
|
echo "$ver is valid"
|
|
else
|
|
echo "$ver is invalid"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Uncomment to run tests
|
|
## test_versions
|
|
|
|
# Get the current WordPress version
|
|
current_wp_version=$(get_wp_version | tr -d '\r')
|
|
if [ -z "$current_wp_version" ] || ! is_valid_version "$current_wp_version"; then
|
|
echo "Failed to get valid WordPress version"
|
|
exit 1
|
|
fi
|
|
echo "Using WordPress version: $current_wp_version"
|
|
|
|
## current_wp_version="6.7.0"
|
|
|
|
# Check the current IMAGE_VERSION from the .env file
|
|
echo "Reading IMAGE_VERSION from .env file..."
|
|
env_wp_version=$(grep '^IMAGE_VERSION=' "$ENV_FILE" | cut -d= -f2 | tr -d '"' | tr -d "'")
|
|
if ! is_valid_version "$env_wp_version"; then
|
|
echo "Invalid version in .env file"
|
|
exit 1
|
|
fi
|
|
echo "WordPress version in .env file (IMAGE_VERSION): $env_wp_version"
|
|
|
|
# Check if current_wp_version is greater than env_wp_version
|
|
if version_greater_than "$current_wp_version" "$env_wp_version"; then
|
|
echo "Upgrade detected: WordPress ($current_wp_version) is newer than .env ($env_wp_version)"
|
|
|
|
# Find the best available version to use
|
|
target_version=$(find_closest_version "$current_wp_version" | tr -d '\r')
|
|
|
|
if [ -n "$target_version" ]; then
|
|
echo "Found appropriate Docker image version: $target_version"
|
|
|
|
# Backup current .env file
|
|
echo "Backing up current .env file..."
|
|
cp "$ENV_FILE" "${ENV_FILE}.bck-versionprotect"
|
|
|
|
# Update the IMAGE_VERSION in the .env file
|
|
echo "Updating IMAGE_VERSION in .env file to: $target_version"
|
|
sed -i "s/^IMAGE_VERSION=.*$/IMAGE_VERSION=\"$target_version\"/" "$ENV_FILE"
|
|
|
|
# Check if IMAGE_VERSION_HOLD exists, add it if it doesn't
|
|
if ! grep -q "^IMAGE_VERSION_HOLD=" "$ENV_FILE"; then
|
|
echo "Adding IMAGE_VERSION_HOLD=true after IMAGE_VERSION..."
|
|
sed -i "/^IMAGE_VERSION=.*/a IMAGE_VERSION_HOLD=true" "$ENV_FILE"
|
|
fi
|
|
|
|
echo "Successfully updated .env to version $target_version"
|
|
else
|
|
echo "Failed to find an appropriate version on Docker Hub"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "No update required. WordPress version ($current_wp_version) is not newer than .env version ($env_wp_version)."
|
|
fi
|
|
|
|
echo "WordPress version check and update script completed."
|
|
|