#!/bin/bash # Enable strict error handling set -e # Function to show usage instructions show_usage() { echo "Usage: $0 [file extensions] [environment] [--dry-run]" echo " file extensions: A space-separated list of file extensions (e.g. .yml .json .conf)." echo " environment: The target environment (e.g., development or production)." echo " --dry-run : Simulate changes without modifying files." } # Parse command-line arguments DRY_RUN=false ENV=$1 if [[ -z "$ENV" ]]; then show_usage exit 1 fi if [[ "$2" == "--dry-run" ]]; then DRY_RUN=true fi shift # Shift arguments so we can get the file extensions after the environment EXTENSIONS=("$@") if [[ ${#EXTENSIONS[@]} -eq 0 ]]; then echo "Error: You must specify at least one file extension." show_usage exit 1 fi echo "Arguments passed correctly!" # Load the appropriate .env file if [ -f ".env.$ENV" ]; then set -a source ".env.$ENV" set +a else echo "Environment file .env.$ENV not found!" exit 1 fi # Function to escape all special characters that might affect sed escape_sed_special_chars() { printf '%s' "$1" | sed 's|[&/\$]|\&|g; s|[[:space:]]|\\ |g; s|\\|\\\\|g' } # Process files for each extension for EXT in "${EXTENSIONS[@]}"; do # Find and process all *.template files with the current extension, including subdirectories find . -name "*.template$EXT" | while read -r TEMPLATE_FILE; do # Derive output file name by removing ".template" OUTPUT_FILE="${TEMPLATE_FILE%.template$EXT}$EXT" # Dry-run reporting or actual processing if $DRY_RUN; then echo "Dry run: would generate $OUTPUT_FILE from $TEMPLATE_FILE" LINE_NUMBER=0 while IFS= read -r line || [[ -n "$line" ]]; do LINE_NUMBER=$((LINE_NUMBER + 1)) while [[ "$line" =~ (\$\{([A-Za-z_][A-Za-z0-9_]*)\}) ]]; do PLACEHOLDER="${BASH_REMATCH[1]}" VAR_NAME="${BASH_REMATCH[2]}" VAR_VALUE="${!VAR_NAME:-}" echo " Would have inputted '$VAR_VALUE' in place of '$VAR_NAME' in $OUTPUT_FILE at line $LINE_NUMBER" if [[ "$VAR_VALUE" == "" ]]; then echo " Warning: Variable '$VAR_NAME' is undefined and will cause an error in actual mode." fi line="${line/$PLACEHOLDER/}" done done < "$TEMPLATE_FILE" else # Validate unresolved placeholders UNRESOLVED=$(grep -oP '\${\K[A-Za-z_][A-Za-z0-9_]*(?=})' "$TEMPLATE_FILE" | while read -r var; do if [ -z "${!var}" ]; then echo "$var" fi done) if [ -n "$UNRESOLVED" ]; then echo "Error: Unresolved variable placeholders detected in $TEMPLATE_FILE!" echo "Ensure all variables are defined in .env.$ENV. Missing: $UNRESOLVED" exit 1 fi # Backup existing output file if it exists if [ -f "$OUTPUT_FILE" ]; then mv "$OUTPUT_FILE" "${OUTPUT_FILE}.bak" echo "Backup created for $OUTPUT_FILE as ${OUTPUT_FILE}.bak" fi # Replace placeholders with environment variables sed_script="" while IFS='=' read -r key value; do # Skip invalid variable names if [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then # Escape special characters in the key and value for sed escaped_key=$(escape_sed_special_chars "${key}") escaped_value=$(escape_sed_special_chars "${!key}") sed_script+="s|\${${escaped_key}}|${escaped_value}|g;" fi done < <(env) # Generate the output file sed -e "$sed_script" "$TEMPLATE_FILE" > "$OUTPUT_FILE" echo "Generated $OUTPUT_FILE from $TEMPLATE_FILE" fi done done # Keep the terminal open at the end echo "Script completed. Press any key to exit..." read -n 1 -s