86 lines
2.0 KiB
Bash
Executable File
86 lines
2.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# Safe .env updater with atomic writes
|
|
# Usage: ./scripts/update-env.sh KEY1=value1 KEY2=value2 ...
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
ENV_FILE="${ENV_FILE:-.env}"
|
|
BACKUP_DIR="${BACKUP_DIR:-.}"
|
|
|
|
# Validate arguments
|
|
if [ $# -eq 0 ]; then
|
|
echo "Usage: $0 KEY=value [KEY2=value2 ...]"
|
|
echo "Example: $0 PANGOLIN_SITE_ID=abc123 PANGOLIN_NEWT_ID=xyz789"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate .env file exists
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
echo "Error: $ENV_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Create backup with timestamp
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
BACKUP_FILE="${BACKUP_DIR}/.env.backup.${TIMESTAMP}"
|
|
cp "$ENV_FILE" "$BACKUP_FILE"
|
|
echo "Backup created: $BACKUP_FILE"
|
|
|
|
# Create temporary file
|
|
TMP_FILE="${ENV_FILE}.tmp"
|
|
cp "$ENV_FILE" "$TMP_FILE"
|
|
|
|
# Process each KEY=value argument
|
|
for arg in "$@"; do
|
|
# Validate format
|
|
if [[ ! "$arg" =~ ^[A-Z_][A-Z0-9_]*=.*$ ]]; then
|
|
echo "Error: Invalid format '$arg'. Expected KEY=value"
|
|
rm "$TMP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
KEY="${arg%%=*}"
|
|
VALUE="${arg#*=}"
|
|
|
|
echo "Updating $KEY"
|
|
|
|
# Check if key exists
|
|
if grep -q "^${KEY}=" "$TMP_FILE"; then
|
|
# Update existing key (handles multi-line values via sed)
|
|
# Use | as delimiter to avoid conflicts with / in values
|
|
sed -i "s|^${KEY}=.*|${KEY}=${VALUE}|" "$TMP_FILE"
|
|
else
|
|
# Append new key
|
|
echo "" >> "$TMP_FILE"
|
|
echo "${KEY}=${VALUE}" >> "$TMP_FILE"
|
|
fi
|
|
done
|
|
|
|
# Validate updated file (basic format check)
|
|
if ! grep -qE '^[A-Z_][A-Z0-9_]*=' "$TMP_FILE"; then
|
|
echo "Error: Updated file has invalid format"
|
|
rm "$TMP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# Atomic move (overwrites original)
|
|
mv "$TMP_FILE" "$ENV_FILE"
|
|
echo "✓ $ENV_FILE updated successfully"
|
|
echo "Backup available at: $BACKUP_FILE"
|
|
|
|
# Show updated values
|
|
echo ""
|
|
echo "Updated environment variables:"
|
|
for arg in "$@"; do
|
|
KEY="${arg%%=*}"
|
|
VALUE="${arg#*=}"
|
|
# Mask secrets (show first 8 chars only)
|
|
if [[ "$KEY" == *"SECRET"* ]] || [[ "$KEY" == *"PASSWORD"* ]] || [[ "$KEY" == *"TOKEN"* ]]; then
|
|
MASKED="${VALUE:0:8}..."
|
|
echo " $KEY=$MASKED"
|
|
else
|
|
echo " $KEY=$VALUE"
|
|
fi
|
|
done
|