captaincore/lib/remote-scripts/component-hashes
Austin Ginder ff36ae2faa 👌 IMPROVE: Hashing
2026-04-06 08:02:24 -04:00

100 lines
2.7 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Generates per-component SHA256 content hashes for plugins, themes, and mu-plugins.
#
# For each plugin/theme directory, computes a deterministic SHA256 hash of all file
# contents (sorted by relative path). MU-plugins are hashed as a single directory unit.
#
# Output format (one line per component):
# plugin:<slug>:<sha256>
# theme:<slug>:<sha256>
# mu-plugins:_mu_plugins:<sha256>
#
# Usage: captaincore ssh <site> --script=component-hashes -- --wp_content=wp-content
#
# Parse arguments and flags
for arg in "$@"; do
if [[ $arg != --* ]]; then
count=1+${#arguments[*]}
arguments[$count]=$arg
continue
fi
flag_name=$( echo $arg | cut -c 3- )
count=1+${#flags[*]}
flags[$count]=$arg
if [[ $arg != *"="* ]]; then
flag_name=${flag_name//-/_}
declare "$flag_name"=true
fi
if [[ $arg == *"="* ]]; then
flag_value=$( echo $flag_name | perl -n -e '/.+?=(.+)/&& print $1' )
flag_name=$( echo $flag_name | perl -n -e '/(.+?)=.+/&& print $1' )
flag_name=${flag_name//-/_}
declare "$flag_name"="$flag_value"
fi
done
# Default wp_content path
if [[ -z "$wp_content" ]]; then
wp_content="wp-content"
fi
cd "$wp_content" 2>/dev/null || exit 1
# Hash a single directory: find all files, sort by path, hash contents, then hash the result.
# Symlinks are included as "SYMLINK:<target>" so injected symlinks change the hash.
hash_directory() {
local dir="$1"
{
find "$dir" -type f \
! -path '*/node_modules/*' \
! -path '*/.git/*' \
! -name .DS_Store \
! -name error_log \
-exec sha256sum {} + 2>/dev/null
find "$dir" -type l \
! -path '*/node_modules/*' \
! -path '*/.git/*' \
2>/dev/null | while IFS= read -r link; do
target=$(readlink "$link")
echo "$(echo -n "SYMLINK:${target}" | sha256sum | awk '{print $1}') ${link}"
done
} | LC_ALL=C sort -k2 | sha256sum | awk '{print $1}'
}
# Hash plugins
if [[ -d "plugins" ]]; then
for dir in plugins/*/; do
[[ -d "$dir" ]] || continue
slug=$(basename "$dir")
hash=$(hash_directory "$dir")
echo "plugin:${slug}:${hash}"
done
fi
# Hash themes
if [[ -d "themes" ]]; then
for dir in themes/*/; do
[[ -d "$dir" ]] || continue
slug=$(basename "$dir")
hash=$(hash_directory "$dir")
echo "theme:${slug}:${hash}"
done
fi
# Hash mu-plugins as a single unit
if [[ -d "mu-plugins" ]]; then
file_count=$(find mu-plugins/ -type f \
! -path '*/node_modules/*' \
! -path '*/.git/*' \
! -name .DS_Store 2>/dev/null | wc -l)
if [[ "$file_count" -gt 0 ]]; then
hash=$(hash_directory "mu-plugins")
echo "mu-plugins:_mu_plugins:${hash}"
fi
fi