website-htmx-rustelo-code/scripts/content/build-content-enhanced.nu

375 lines
13 KiB
Text
Raw Normal View History

2026-07-10 03:44:13 +01:00
#!/usr/bin/env nu
# Enhanced Content Build Script (Nushell)
# Uses the Rust content_processor with library functions for modularity
# Import modular library functions
use lib/frontmatter.nu *
# Load environment variables from .env file
def load_env_from_file [] {
let env_file = ".env"
if ($env_file | path exists) {
let env_content = (open $env_file | lines)
for line in $env_content {
# Skip comments and empty lines
if not ($line | str trim | str starts-with "#") and not ($line | str trim | is-empty) {
# Parse KEY=VALUE format with variable expansion
if ($line | str contains "=") {
let parts = ($line | split column "=" key value)
if ($parts | length) >= 2 {
let key = ($parts | first | get key | str trim)
let value = ($parts | first | get value | str trim)
# Remove quotes and expand ${VARIABLE} patterns
let clean_value = ($value | str replace -a '"' '' | str replace -a "'" '')
let expanded_value = expand_env_variables $clean_value
# Set environment variable
load-env {($key): $expanded_value}
}
}
}
}
}
}
# Expand ${VARIABLE} patterns in environment values
def expand_env_variables [value: string] {
# Simplified expansion for common patterns
mut result = $value
# Replace ${SITE_ROOT_PATH} with actual value
if ($result | str contains '${SITE_ROOT_PATH}') {
let site_root = try { $env.SITE_ROOT_PATH } catch { "." }
$result = ($result | str replace -a '${SITE_ROOT_PATH}' $site_root)
}
$result
}
# Get environment variable with default
def get_env_var [var_name: string, default_value: string] {
try {
$env | get $var_name
} catch {
$default_value
}
}
# Get enabled content types from content-kinds.toml
def get_enabled_content_types [content_dir: string] {
let content_kinds_file = $"($content_dir)/content-kinds.toml"
if not ($content_kinds_file | path exists) {
print $"(ansi yellow)⚠️ Warning: content-kinds.toml not found, using defaults(ansi reset)"
return ["blog", "recipes"]
}
mut enabled_types = []
let toml_content = open $content_kinds_file
if "content_kinds" in $toml_content {
for kind in $toml_content.content_kinds {
if $kind.enabled {
$enabled_types = ($enabled_types | append $kind.name)
}
}
}
if ($enabled_types | length) == 0 {
["blog", "recipes"]
} else {
$enabled_types
}
}
# Show comprehensive help information
def show_help [] {
print $"
(ansi blue)Enhanced Content Build Script(ansi reset)
Uses the Rust content_processor for fast, reliable content generation
(ansi green)USAGE:(ansi reset)
./build-content-enhanced.nu [OPTIONS]
(ansi green)OPTIONS:(ansi reset)
-h, --help Show this help message
-t, --content-type TYPE Process specific content type only
-l, --language LANG Process specific language only
-c, --category CATEGORY Process specific category only
-f, --file FILE Process specific file with glob pattern support
-w, --watch Watch for changes and auto-regenerate
--clean Clean output directory before building
--copy-to-server Copy generated content to server runtime directory
--stats Show content statistics after build
--use-legacy Use legacy Nushell processor instead of Rust
(ansi green)EXAMPLES:(ansi reset)
# Build all content
./build-content-enhanced.nu
# Build only blog content
./build-content-enhanced.nu --content-type blog
# Build only English blog content
./build-content-enhanced.nu --content-type blog --language en
# Build only rust category posts
./build-content-enhanced.nu --content-type blog --language en --category rust
# Build specific file
./build-content-enhanced.nu --file \"blog/en/rust/rust-web-development-2024.md\"
# Build multiple files with pattern
./build-content-enhanced.nu --file \"blog/en/*/rust-*.md\"
# Clean build with server copy and stats
./build-content-enhanced.nu --clean --copy-to-server --stats
# Watch mode for development
./build-content-enhanced.nu --watch
(ansi green)ENVIRONMENT VARIABLES:(ansi reset)
SITE_CONTENT_PATH Source content directory (default: site/content)
SITE_PUBLIC_PATH Output directory (default: site/public)
SITE_SERVER_CONTENT_ROOT Server runtime directory (default: r)
(ansi green)GENERATED FILES:(ansi reset)
post-name.html Markdown content converted to HTML
post-name.json Frontmatter data in JSON format
index.json Collection index with all posts and metadata
(ansi yellow)NOTES:(ansi reset)
- Recommended replacement for build-localized-content.nu
- Uses fast Rust content_processor by default
- All processing options respect project language-agnostic architecture
- No hardcoded paths, categories, or content types
- Automatically discovers content from configuration files
- Hot reload ready for development workflows
"
}
# Build cargo command for content processor
def build_rust_processor_command [
content_type?: string
language?: string
category?: string
file?: string
watch: bool = false
] {
mut cmd = ["cargo", "run", "--features=content-static", "--package", "rustelo-htmx-server", "--bin", "content_processor", "--"]
if $content_type != null {
$cmd = ($cmd | append ["--content-type", $content_type])
}
if $language != null {
$cmd = ($cmd | append ["--language", $language])
}
if $category != null {
$cmd = ($cmd | append ["--category", $category])
}
if $file != null {
$cmd = ($cmd | append ["--file", $file])
}
if $watch {
$cmd = ($cmd | append ["--watch"])
}
$cmd
}
# Run the Rust content processor
def run_rust_processor [
content_type?: string
language?: string
category?: string
file?: string
watch: bool = false
] {
mut cmd_args = []
if $content_type != null {
$cmd_args = ($cmd_args | append ["--content-type", $content_type])
}
if $language != null {
$cmd_args = ($cmd_args | append ["--language", $language])
}
if $category != null {
$cmd_args = ($cmd_args | append ["--category", $category])
}
if $file != null {
$cmd_args = ($cmd_args | append ["--file", $file])
}
if $watch {
$cmd_args = ($cmd_args | append ["--watch"])
}
print $"(ansi blue)🔧 Running cargo with args: ($cmd_args | str join ' ')(ansi reset)"
try {
if ($cmd_args | length) > 0 {
run-external "cargo" "run" "--features=content-static" "--package" "rustelo-htmx-server" "--bin" "content_processor" "--" ...$cmd_args
} else {
run-external "cargo" "run" "--features=content-static" "--package" "rustelo-htmx-server" "--bin" "content_processor"
}
print $"(ansi green)✅ Content processing completed!(ansi reset)"
true
} catch { |err|
print $"(ansi red)❌ Content processing failed: ($err.msg)(ansi reset)"
false
}
}
# Copy generated content to server runtime directory
def copy_to_server_directory [public_dir: string, server_dir: string] {
print $"(ansi blue)📋 Copying content to server runtime directory...(ansi reset)"
print $"(ansi blue) From: ($public_dir)(ansi reset)"
print $"(ansi blue) To: ($server_dir)(ansi reset)"
# Create server directory if it doesn't exist
mkdir $server_dir
# Copy all content
if ($public_dir | path exists) {
try {
cp -r ($public_dir | path join "*") $server_dir
print $"(ansi green)✅ Content copied to server directory(ansi reset)"
} catch { |err|
print $"(ansi yellow)⚠️ Warning: Could not copy some files: ($err.msg)(ansi reset)"
}
} else {
print $"(ansi yellow)⚠️ Warning: Public directory does not exist: ($public_dir)(ansi reset)"
}
}
# Show content statistics using library functions
def show_enhanced_content_statistics [output_dir: string] {
print $"(ansi blue)📊 Enhanced Content Statistics:(ansi reset)"
if not ($output_dir | path exists) {
print $"(ansi yellow)⚠️ Output directory does not exist: ($output_dir)(ansi reset)"
return
}
# Count generated files by type
let html_files = (glob ($output_dir | path join "**/*.html") | length)
let json_files = (glob ($output_dir | path join "**/*.json") | length)
let index_files = (glob ($output_dir | path join "**/index.json") | length)
print $" HTML files: ($html_files)"
print $" JSON files: ($json_files)"
print $" Index files: ($index_files)"
# Show directory structure using library function if available
print $"(ansi blue)📁 Generated Structure:(ansi reset)"
try {
ls $output_dir | where type == "dir" | each { |item|
let dir_name = ($item.name | path basename)
print $" 📁 ($dir_name)/"
# Show subdirectories
try {
ls $item.name | where type == "dir" | each { |subitem|
let subdir_name = ($subitem.name | path basename)
let post_count = (glob ($subitem.name | path join "*.md") | length)
print $" 📂 ($subdir_name)/ - ($post_count) posts"
} | ignore
} catch {
# Ignore errors accessing subdirectories
}
} | ignore
} catch {
print $" Structure listing not available"
}
}
# Main function with comprehensive options
def main [
--help(-h) # Show help message
--content-type(-t): string # Process specific content type only
--language(-l): string # Process specific language only
--category(-c): string # Process specific category only
--file(-f): string # Process specific file with glob support
--watch(-w) # Watch for changes and auto-regenerate
--clean # Clean output directory before building
--copy-to-server # Copy generated content to server runtime directory
--stats # Show content statistics after build
--use-legacy # Use legacy Nushell processor instead of Rust
] {
# Show help if requested
if $help {
show_help
return
}
# Load environment variables using library function
load_env_from_file
# Configuration from environment using library function
let content_dir = (get_env_var "SITE_CONTENT_PATH" "site/content")
let public_dir = (get_env_var "SITE_PUBLIC_PATH" "site/public")
let server_dir = (get_env_var "SITE_SERVER_ROOT_CONTENT" "r")
let out_dir_path = ($public_dir | path join $server_dir)
print $"(ansi blue)🚀 Enhanced Content Build System(ansi reset)"
print $"(ansi blue)📁 Source: ($content_dir)(ansi reset)"
print $"(ansi blue)📂 Output: ($out_dir_path(ansi reset)"
# Clean output directory if requested
if $clean {
if ($out_dir_path | path exists) {
print $"(ansi yellow)🧹 Cleaning output directory: ($out_dir_path)(ansi reset)"
rm -rf $out_dir_path
}
mkdir $out_dir_path
}
# Use Rust content processor only
if $use_legacy {
print $"(ansi red)❌ Legacy Nushell processor is not supported(ansi reset)"
print $"(ansi yellow)💡 Please use the Rust content processor for reliable content processing(ansi reset)"
return
}
# Use the Rust content processor (only supported method)
print $"(ansi blue)🚀 Using Rust content processor...(ansi reset)"
let success = (run_rust_processor $content_type $language $category $file $watch)
if not $success {
print $"(ansi red)❌ Build failed!(ansi reset)"
return
}
# Copy to server directory if requested
if $copy_to_server {
copy_to_server_directory $public_dir $server_dir
}
# Show statistics if requested
if $stats {
show_enhanced_content_statistics $public_dir
}
# Show completion message
if $watch {
print $"(ansi yellow)👀 Watch mode active - monitoring for changes...(ansi reset)"
print $"(ansi yellow)Press Ctrl+C to stop watching(ansi reset)"
} else {
print $"(ansi green)🎉 Content build complete!(ansi reset)"
print $"(ansi green) Generated files in: ($out_dir_path)(ansi reset)"
if $copy_to_server {
print $"(ansi green) Server files in: ($server_dir)(ansi reset)"
}
}
}