293 lines
No EOL
9.2 KiB
Bash
Executable file
293 lines
No EOL
9.2 KiB
Bash
Executable file
#!/bin/bash
|
||
|
||
# Content Consistency Validation Script
|
||
# Validates that content structure is consistent and server can process all content
|
||
|
||
# set -e removed - handle errors explicitly to avoid early exits on warnings
|
||
|
||
# Configuration
|
||
CONTENT_DIR="${SITE_CONTENT_PATH:-site/content}"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Counters
|
||
TOTAL_CHECKS=0
|
||
PASSED_CHECKS=0
|
||
FAILED_CHECKS=0
|
||
|
||
# Function to print colored output
|
||
print_status() {
|
||
local status=$1
|
||
local message=$2
|
||
case $status in
|
||
"PASS")
|
||
echo -e "${GREEN}✅ PASS${NC}: $message"
|
||
((PASSED_CHECKS++))
|
||
;;
|
||
"FAIL")
|
||
echo -e "${RED}❌ FAIL${NC}: $message"
|
||
((FAILED_CHECKS++))
|
||
;;
|
||
"WARN")
|
||
echo -e "${YELLOW}⚠️ WARN${NC}: $message"
|
||
;;
|
||
"INFO")
|
||
echo -e "${BLUE}ℹ️ INFO${NC}: $message"
|
||
;;
|
||
esac
|
||
((TOTAL_CHECKS++))
|
||
}
|
||
|
||
# Function to check if directory exists and is not empty
|
||
check_directory() {
|
||
local dir=$1
|
||
local description=$2
|
||
|
||
if [ ! -d "$dir" ]; then
|
||
print_status "FAIL" "$description directory missing: $dir"
|
||
return 1
|
||
fi
|
||
|
||
local file_count
|
||
file_count=$(ls -A "$dir" 2>/dev/null | wc -l)
|
||
if [ "$file_count" -eq 0 ]; then
|
||
print_status "WARN" "$description directory is empty: $dir"
|
||
return 0 # Return 0 for warnings to not exit with set -e
|
||
fi
|
||
|
||
print_status "PASS" "$description directory exists and has content: $dir"
|
||
return 0
|
||
}
|
||
|
||
# Function to validate markdown files
|
||
validate_markdown_files() {
|
||
local base_dir=$1
|
||
local content_type=$2
|
||
|
||
print_status "INFO" "Validating $content_type markdown files in $base_dir"
|
||
|
||
local md_count=0
|
||
local invalid_count=0
|
||
|
||
while IFS= read -r -d '' file; do
|
||
((md_count++))
|
||
|
||
# Check if file has frontmatter
|
||
if ! head -n1 "$file" | grep -q "^---$"; then
|
||
print_status "FAIL" "Missing frontmatter in: ${file#$PROJECT_ROOT/}"
|
||
((invalid_count++))
|
||
continue
|
||
fi
|
||
|
||
# Check if file has closing frontmatter
|
||
if ! sed -n '2,$p' "$file" | grep -q "^---$"; then
|
||
print_status "FAIL" "Invalid frontmatter (no closing ---) in: ${file#$PROJECT_ROOT/}"
|
||
((invalid_count++))
|
||
continue
|
||
fi
|
||
|
||
# Check for required frontmatter fields
|
||
local frontmatter=$(sed -n '/^---$/,/^---$/p' "$file")
|
||
|
||
if ! echo "$frontmatter" | grep -q "^title:"; then
|
||
print_status "FAIL" "Missing 'title' field in: ${file#$PROJECT_ROOT/}"
|
||
((invalid_count++))
|
||
fi
|
||
|
||
if ! echo "$frontmatter" | grep -q "^slug:"; then
|
||
print_status "FAIL" "Missing 'slug' field in: ${file#$PROJECT_ROOT/}"
|
||
((invalid_count++))
|
||
fi
|
||
|
||
done < <(find "$base_dir" -name "*.md" -type f -print0)
|
||
|
||
if [ $md_count -eq 0 ]; then
|
||
print_status "WARN" "No markdown files found in $base_dir"
|
||
else
|
||
if [ $invalid_count -eq 0 ]; then
|
||
print_status "PASS" "All $md_count $content_type markdown files are valid"
|
||
else
|
||
print_status "FAIL" "$invalid_count of $md_count $content_type markdown files have issues"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Function to validate content structure
|
||
validate_content_structure() {
|
||
print_status "INFO" "=== Content Structure Validation ==="
|
||
|
||
# Check main content directory
|
||
check_directory "$CONTENT_DIR" "Main content"
|
||
|
||
# Check content-kinds.toml exists
|
||
local content_kinds_file="$CONTENT_DIR/content-kinds.toml"
|
||
if [ ! -f "$content_kinds_file" ]; then
|
||
print_status "FAIL" "content-kinds.toml missing: $content_kinds_file"
|
||
return 1
|
||
fi
|
||
print_status "PASS" "content-kinds.toml exists"
|
||
|
||
# Check routes configuration
|
||
if [ -f "$CONTENT_DIR/routes.toml" ]; then
|
||
print_status "PASS" "routes.toml exists"
|
||
elif [ -d "$CONTENT_DIR/routes/" ]; then
|
||
print_status "PASS" "routes/ directory exists"
|
||
else
|
||
print_status "FAIL" "No routes configuration found (routes.toml or routes/ directory)"
|
||
fi
|
||
|
||
# Validate each enabled content type
|
||
while IFS= read -r content_type; do
|
||
local content_dir="$CONTENT_DIR/$content_type"
|
||
if check_directory "$content_dir" "Content type '$content_type'"; then
|
||
# Check for language directories
|
||
local lang_count=0
|
||
for lang_dir in "$content_dir"/*/; do
|
||
if [ -d "$lang_dir" ]; then
|
||
local lang=$(basename "$lang_dir")
|
||
check_directory "$lang_dir" "Language '$lang' in '$content_type'"
|
||
validate_markdown_files "$lang_dir" "$content_type/$lang"
|
||
((lang_count++))
|
||
fi
|
||
done
|
||
|
||
if [ $lang_count -eq 0 ]; then
|
||
print_status "WARN" "No language directories found in $content_type"
|
||
fi
|
||
fi
|
||
done < <(get_enabled_content_types)
|
||
}
|
||
|
||
# Function to get enabled content types from content-kinds.toml
|
||
get_enabled_content_types() {
|
||
local content_kinds_file="$CONTENT_DIR/content-kinds.toml"
|
||
|
||
if [ ! -f "$content_kinds_file" ]; then
|
||
echo "blog"
|
||
echo "recipes"
|
||
return
|
||
fi
|
||
|
||
# Simplified parsing - look for directory entries that aren't commented out
|
||
grep -E '^\s*directory\s*=' "$content_kinds_file" | \
|
||
sed 's/.*directory\s*=\s*"\([^"]*\)".*/\1/' | \
|
||
while read -r dir; do
|
||
if [ -d "$CONTENT_DIR/$dir" ]; then
|
||
echo "$dir"
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Function to check server can process content
|
||
validate_server_processing() {
|
||
print_status "INFO" "=== Server Content Processing Validation ==="
|
||
|
||
# Check if server binary exists
|
||
if [ ! -f "$PROJECT_ROOT/target/debug/server" ] && [ ! -f "$PROJECT_ROOT/target/release/server" ]; then
|
||
print_status "WARN" "Server binary not found - run 'cargo build --features content-static' first"
|
||
return
|
||
fi
|
||
|
||
print_status "PASS" "Server binary is available for content processing"
|
||
}
|
||
|
||
# Function to validate i18n structure
|
||
validate_i18n_structure() {
|
||
print_status "INFO" "=== Internationalization Structure Validation ==="
|
||
|
||
local locales_dir="$CONTENT_DIR/locales"
|
||
if check_directory "$locales_dir" "Locales"; then
|
||
# Check for language directories in locales
|
||
for lang_dir in "$locales_dir"/*/; do
|
||
if [ -d "$lang_dir" ]; then
|
||
local lang=$(basename "$lang_dir")
|
||
check_directory "$lang_dir" "Locale '$lang'"
|
||
|
||
# Check for common.ftl
|
||
if [ -f "$lang_dir/common.ftl" ]; then
|
||
print_status "PASS" "common.ftl exists for language '$lang'"
|
||
else
|
||
print_status "WARN" "common.ftl missing for language '$lang'"
|
||
fi
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Check menus
|
||
local menus_dir="$CONTENT_DIR/menus"
|
||
if check_directory "$menus_dir" "Menus"; then
|
||
for menu_file in "$menus_dir"/*.toml; do
|
||
if [ -f "$menu_file" ]; then
|
||
local lang=$(basename "$menu_file" .toml)
|
||
print_status "PASS" "Menu configuration exists for language '$lang'"
|
||
fi
|
||
done
|
||
fi
|
||
}
|
||
|
||
# Function to remove deprecated files/directories
|
||
cleanup_deprecated() {
|
||
print_status "INFO" "=== Cleanup Deprecated Build Outputs ==="
|
||
|
||
# The /public directory is now deprecated since server processes content dynamically
|
||
if [ -d "$PROJECT_ROOT/public" ]; then
|
||
local item_count=$(find "$PROJECT_ROOT/public" -type f | wc -l)
|
||
if [ "$item_count" -gt 5 ]; then # Allow for a few static files
|
||
print_status "WARN" "Found $item_count files in /public - consider removing pre-built HTML"
|
||
print_status "INFO" "Server now processes content dynamically from /content"
|
||
else
|
||
print_status "PASS" "/public directory has minimal static files"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Main validation function
|
||
main() {
|
||
echo "🔍 Content Consistency Validation"
|
||
echo "=================================="
|
||
echo "Content directory: $CONTENT_DIR"
|
||
echo "Project root: $PROJECT_ROOT"
|
||
echo ""
|
||
|
||
validate_content_structure
|
||
echo ""
|
||
|
||
validate_i18n_structure
|
||
echo ""
|
||
|
||
validate_server_processing
|
||
echo ""
|
||
|
||
cleanup_deprecated
|
||
echo ""
|
||
|
||
# Summary
|
||
echo "🏁 Validation Summary"
|
||
echo "===================="
|
||
echo "Total checks: $TOTAL_CHECKS"
|
||
echo "Passed: $PASSED_CHECKS"
|
||
echo "Failed: $FAILED_CHECKS"
|
||
|
||
if [ $FAILED_CHECKS -eq 0 ]; then
|
||
print_status "PASS" "All content validation checks passed!"
|
||
echo ""
|
||
echo "✅ Content structure is consistent and ready for server processing"
|
||
echo "🚀 You can run: cargo run --features content-static"
|
||
exit 0
|
||
else
|
||
echo ""
|
||
echo "❌ Content validation found $FAILED_CHECKS issues"
|
||
echo "🔧 Please fix the issues above before building"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Run main function
|
||
main "$@" |