#!/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)" } } }