#!/bin/bash # Configuration Management Script for Rustelo # Provides commands to manage, validate, and deploy configurations # Usage: ./manage-config.sh [command] [options] set -e # Script configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_DIR="$(dirname "$SCRIPT_DIR")" PROJECT_ROOT="$(dirname "$CONFIG_DIR")" BACKUP_DIR="$CONFIG_DIR/backups" ENVIRONMENTS=("dev" "prod" "example") # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_debug() { if [ "${DEBUG:-0}" = "1" ]; then echo -e "${PURPLE}[DEBUG]${NC} $1" fi } # Show help show_help() { cat << EOF Configuration Management Script for Rustelo USAGE: $0 [COMMAND] [OPTIONS] COMMANDS: build ENV [OUTPUT] Build configuration for environment validate ENV Validate configuration for environment list-features List available features list-environments List available environments backup ENV Backup existing configuration restore BACKUP_FILE Restore configuration from backup diff ENV1 ENV2 Compare configurations between environments template FEATURE Create new feature template clean Clean generated configurations status Show configuration status help Show this help message ENVIRONMENTS: dev Development environment prod Production environment example Example/template environment OPTIONS: --debug Enable debug output --dry-run Show what would be done without executing --force Force operation without confirmation --quiet Suppress non-error output --backup-dir DIR Use custom backup directory EXAMPLES: $0 build dev # Build dev configuration $0 build prod config.prod.toml # Build prod config with custom name $0 validate dev # Validate dev configuration $0 diff dev prod # Compare dev and prod configurations $0 backup prod # Backup prod configuration $0 template auth # Create new auth feature template $0 clean # Clean all generated configs $0 status # Show configuration status ENVIRONMENT VARIABLES: CONFIG_DEBUG=1 Enable debug output CONFIG_QUIET=1 Suppress non-error output CONFIG_FORCE=1 Force operations without confirmation CONFIG_BACKUP_DIR=path Custom backup directory EOF } # Parse command line arguments parse_args() { COMMAND="" ENV="" OUTPUT="" DEBUG="${DEBUG:-0}" DRY_RUN="${DRY_RUN:-0}" FORCE="${FORCE:-0}" QUIET="${QUIET:-0}" BACKUP_DIR_OVERRIDE="" while [[ $# -gt 0 ]]; do case $1 in --debug) DEBUG=1 shift ;; --dry-run) DRY_RUN=1 shift ;; --force) FORCE=1 shift ;; --quiet) QUIET=1 shift ;; --backup-dir) BACKUP_DIR_OVERRIDE="$2" shift 2 ;; build|validate|backup|restore|diff|template|clean|status|list-features|list-environments|help) COMMAND="$1" shift ;; *) if [ -z "$ENV" ]; then ENV="$1" elif [ -z "$OUTPUT" ]; then OUTPUT="$1" else log_error "Unknown argument: $1" exit 1 fi shift ;; esac done # Override backup directory if specified if [ -n "$BACKUP_DIR_OVERRIDE" ]; then BACKUP_DIR="$BACKUP_DIR_OVERRIDE" fi # Apply environment variables [ "${CONFIG_DEBUG:-0}" = "1" ] && DEBUG=1 [ "${CONFIG_QUIET:-0}" = "1" ] && QUIET=1 [ "${CONFIG_FORCE:-0}" = "1" ] && FORCE=1 [ -n "${CONFIG_BACKUP_DIR:-}" ] && BACKUP_DIR="$CONFIG_BACKUP_DIR" } # Check if environment is valid validate_environment() { local env="$1" for valid_env in "${ENVIRONMENTS[@]}"; do if [ "$env" = "$valid_env" ]; then return 0 fi done log_error "Invalid environment: $env" log_error "Valid environments: ${ENVIRONMENTS[*]}" return 1 } # Create backup directory if it doesn't exist ensure_backup_dir() { if [ ! -d "$BACKUP_DIR" ]; then mkdir -p "$BACKUP_DIR" log_debug "Created backup directory: $BACKUP_DIR" fi } # Build configuration cmd_build() { local env="$1" local output="${2:-config.toml}" if [ -z "$env" ]; then log_error "Environment required for build command" return 1 fi if ! validate_environment "$env"; then return 1 fi log_info "Building configuration for environment: $env" # Use Python script if available, otherwise use bash script if [ "$DRY_RUN" = "1" ]; then log_info "Would build configuration using shell script" return 0 fi "$SCRIPT_DIR/build-config.sh" "$env" "$output" } # Validate configuration cmd_validate() { local env="$1" if [ -z "$env" ]; then log_error "Environment required for validate command" return 1 fi if ! validate_environment "$env"; then return 1 fi log_info "Validating configuration for environment: $env" if [ "$DRY_RUN" = "1" ]; then log_info "Would validate configuration" return 0 fi # Use Python script if available CONFIG_VALIDATE_ONLY=1 "$SCRIPT_DIR/build-config.sh" "$env" } # List available features cmd_list_features() { log_info "Available features:" if [ -d "$CONFIG_DIR/features" ]; then for feature_dir in "$CONFIG_DIR/features"/*; do if [ -d "$feature_dir" ]; then local feature_name=$(basename "$feature_dir") log_info " - $feature_name" # Show available environments for this feature local envs=() for env in "${ENVIRONMENTS[@]}"; do if [ -f "$feature_dir/$env.toml" ]; then envs+=("$env") fi done if [ ${#envs[@]} -gt 0 ]; then log_info " Environments: ${envs[*]}" fi fi done else log_error "Features directory not found: $CONFIG_DIR/features" return 1 fi } # List available environments cmd_list_environments() { log_info "Available environments:" for env in "${ENVIRONMENTS[@]}"; do log_info " - $env" # Check if base configuration exists if [ -f "$CONFIG_DIR/base/$env.toml" ]; then log_info " Base config: ✓" else log_info " Base config: ✗" fi # Count available features local feature_count=0 if [ -d "$CONFIG_DIR/features" ]; then for feature_dir in "$CONFIG_DIR/features"/*; do if [ -d "$feature_dir" ] && [ -f "$feature_dir/$env.toml" ]; then ((feature_count++)) fi done fi log_info " Available features: $feature_count" done } # Compare configurations between environments cmd_diff() { local env1="$1" local env2="$2" if [ -z "$env1" ] || [ -z "$env2" ]; then log_error "Two environments required for diff command" return 1 fi if ! validate_environment "$env1" || ! validate_environment "$env2"; then return 1 fi log_info "Comparing configurations: $env1 vs $env2" # Create temporary files local temp1=$(mktemp) local temp2=$(mktemp) trap "rm -f $temp1 $temp2" EXIT # Build configurations if ! cmd_build "$env1" "$temp1"; then log_error "Failed to build configuration for $env1" return 1 fi if ! cmd_build "$env2" "$temp2"; then log_error "Failed to build configuration for $env2" return 1 fi # Compare configurations if command -v diff &> /dev/null; then diff -u "$temp1" "$temp2" || true else log_warning "diff command not available, using basic comparison" if cmp -s "$temp1" "$temp2"; then log_info "Configurations are identical" else log_info "Configurations differ" fi fi } # Create backup of configuration cmd_backup() { local env="$1" local config_file="${2:-config.toml}" if [ -z "$env" ]; then log_error "Environment required for backup command" return 1 fi if ! validate_environment "$env"; then return 1 fi ensure_backup_dir local timestamp=$(date +%Y%m%d_%H%M%S) local backup_file="$BACKUP_DIR/config_${env}_${timestamp}.toml" if [ -f "$config_file" ]; then if [ "$DRY_RUN" = "1" ]; then log_info "Would backup $config_file to $backup_file" return 0 fi cp "$config_file" "$backup_file" log_success "Configuration backed up to: $backup_file" else log_error "Configuration file not found: $config_file" return 1 fi } # Restore configuration from backup cmd_restore() { local backup_file="$1" local output_file="${2:-config.toml}" if [ -z "$backup_file" ]; then log_error "Backup file required for restore command" return 1 fi if [ ! -f "$backup_file" ]; then log_error "Backup file not found: $backup_file" return 1 fi if [ "$DRY_RUN" = "1" ]; then log_info "Would restore $backup_file to $output_file" return 0 fi # Create backup of current file if it exists if [ -f "$output_file" ]; then local timestamp=$(date +%Y%m%d_%H%M%S) local current_backup="$BACKUP_DIR/config_current_${timestamp}.toml" ensure_backup_dir cp "$output_file" "$current_backup" log_info "Current configuration backed up to: $current_backup" fi cp "$backup_file" "$output_file" log_success "Configuration restored from: $backup_file" } # Create new feature template cmd_template() { local feature_name="$1" if [ -z "$feature_name" ]; then log_error "Feature name required for template command" return 1 fi local feature_dir="$CONFIG_DIR/features/$feature_name" if [ -d "$feature_dir" ]; then if [ "$FORCE" != "1" ]; then log_error "Feature directory already exists: $feature_dir" log_error "Use --force to overwrite" return 1 fi fi if [ "$DRY_RUN" = "1" ]; then log_info "Would create feature template: $feature_name" return 0 fi # Create feature directory mkdir -p "$feature_dir" # Create template files for each environment for env in "${ENVIRONMENTS[@]}"; do local template_file="$feature_dir/$env.toml" cat > "$template_file" << EOF # $feature_name Feature Configuration - $(echo $env | sed 's/./\U&/') Environment # Settings for the $feature_name feature [features] $feature_name = true [$feature_name] enabled = true # Add your feature-specific settings here # Example configuration options: # option1 = "value1" # option2 = 42 # option3 = true EOF log_info "Created template file: $template_file" done # Create README for the feature cat > "$feature_dir/README.md" << EOF # $feature_name Feature Description of the $feature_name feature. ## Configuration Options ### Environment-Specific Settings #### Development (\`dev.toml\`) - Optimized for development and debugging - Relaxed security settings - Verbose logging enabled #### Production (\`prod.toml\`) - Optimized for production performance - Strict security settings - Minimal logging #### Example (\`example.toml\`) - Complete documentation of all options - Best practice configurations - Commented examples ## Usage Enable this feature by setting: \`\`\`toml [features] $feature_name = true \`\`\` ## Dependencies List any features that this feature depends on. ## Security Considerations Document any security implications of this feature. EOF log_success "Feature template created: $feature_name" } # Clean generated configurations cmd_clean() { log_info "Cleaning generated configurations..." if [ "$DRY_RUN" = "1" ]; then log_info "Would clean generated configuration files" return 0 fi local cleaned_count=0 # Remove generated config files for config_file in config.toml config.*.toml; do if [ -f "$config_file" ]; then rm "$config_file" log_info "Removed: $config_file" ((cleaned_count++)) fi done # Remove temporary files for temp_file in /tmp/config_*.toml /tmp/rustelo_config_*.toml; do if [ -f "$temp_file" ]; then rm "$temp_file" log_info "Removed: $temp_file" ((cleaned_count++)) fi done log_success "Cleaned $cleaned_count files" } # Show configuration status cmd_status() { log_info "Configuration system status:" # Check directories log_info "Directories:" for dir in base features scripts; do if [ -d "$CONFIG_DIR/$dir" ]; then log_info " $dir: ✓" else log_info " $dir: ✗" fi done # Check base configurations log_info "Base configurations:" for env in "${ENVIRONMENTS[@]}"; do if [ -f "$CONFIG_DIR/base/$env.toml" ]; then log_info " $env: ✓" else log_info " $env: ✗" fi done # Check features log_info "Features:" if [ -d "$CONFIG_DIR/features" ]; then for feature_dir in "$CONFIG_DIR/features"/*; do if [ -d "$feature_dir" ]; then local feature_name=$(basename "$feature_dir") local env_count=0 for env in "${ENVIRONMENTS[@]}"; do if [ -f "$feature_dir/$env.toml" ]; then ((env_count++)) fi done log_info " $feature_name: $env_count/${#ENVIRONMENTS[@]} environments" fi done fi # Check scripts log_info "Scripts:" for script in build-config.sh; do if [ -f "$SCRIPT_DIR/$script" ]; then log_info " $script: ✓" else log_error " $script: ✗" fi done # Check tools log_info "Tools:" if command -v python3 &> /dev/null; then log_info " python3: ✓" if python3 -c "import toml" 2>/dev/null; then log_info " toml (Python): ✓" else log_info " toml (Python): ✗" fi else log_info " python3: ✗" fi if command -v toml &> /dev/null; then log_info " toml (CLI): ✓" else log_info " toml (CLI): ✗" fi } # Main function main() { parse_args "$@" # Enable debug if requested if [ "$DEBUG" = "1" ]; then set -x fi # Handle quiet mode if [ "$QUIET" = "1" ]; then exec 1>/dev/null fi # Execute command case "$COMMAND" in build) cmd_build "$ENV" "$OUTPUT" ;; validate) cmd_validate "$ENV" ;; list-features) cmd_list_features ;; list-environments) cmd_list_environments ;; diff) cmd_diff "$ENV" "$OUTPUT" ;; backup) cmd_backup "$ENV" "$OUTPUT" ;; restore) cmd_restore "$ENV" "$OUTPUT" ;; template) cmd_template "$ENV" ;; clean) cmd_clean ;; status) cmd_status ;; help|"") show_help ;; *) log_error "Unknown command: $COMMAND" show_help exit 1 ;; esac } # Run main function main "$@"