Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
This commit is contained in:
132
scripts/lib/README.md
Normal file
132
scripts/lib/README.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Scripts Library
|
||||
|
||||
Common libraries for all scripts in the project. This modularizes and consolidates shared functionality.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
lib/
|
||||
├── common/ # Common utilities
|
||||
│ ├── colors.sh # Color definitions and functions
|
||||
│ ├── logging.sh # Logging functions (info, warn, error, etc.)
|
||||
│ ├── paths.sh # Path definitions (SCRIPT_DIR, PROJECT_ROOT, etc.)
|
||||
│ └── utils.sh # Utility functions (confirm, require_command, etc.)
|
||||
├── config/ # Configuration
|
||||
│ ├── env.sh # Environment variable loading
|
||||
│ └── regions.sh # Region code mapping (single source of truth)
|
||||
├── azure/ # Azure-specific functions
|
||||
│ └── cli.sh # Azure CLI wrapper functions
|
||||
└── init.sh # Initialize all libraries (main entry point)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Quick Start
|
||||
|
||||
Most scripts should source `init.sh` to load all libraries:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
|
||||
# Now you can use all functions from the libraries
|
||||
log_info "Starting script"
|
||||
ensure_azure_cli || exit 1
|
||||
```
|
||||
|
||||
### Individual Libraries
|
||||
|
||||
You can also source individual libraries if you only need specific functionality:
|
||||
|
||||
```bash
|
||||
source "$SCRIPT_DIR/lib/common/colors.sh"
|
||||
source "$SCRIPT_DIR/lib/common/logging.sh"
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
#### Using Logging
|
||||
|
||||
```bash
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
|
||||
log_info "Processing regions..."
|
||||
log_warn "This might take a while"
|
||||
log_error "Failed to connect"
|
||||
log_success "Completed successfully"
|
||||
log_section "Deployment Status"
|
||||
```
|
||||
|
||||
#### Using Colors
|
||||
|
||||
```bash
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
|
||||
color_red "Error message"
|
||||
color_green "Success message"
|
||||
color_yellow "Warning message"
|
||||
```
|
||||
|
||||
#### Using Region Codes
|
||||
|
||||
```bash
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
|
||||
# Get all regions
|
||||
get_all_regions
|
||||
|
||||
# Get region code
|
||||
CODE=$(get_region_code "westeurope") # Returns "wst"
|
||||
|
||||
# Get region name from code
|
||||
REGION=$(get_region_name "wst") # Returns "westeurope"
|
||||
```
|
||||
|
||||
#### Using Azure CLI Functions
|
||||
|
||||
```bash
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
|
||||
# Ensure Azure CLI is ready
|
||||
ensure_azure_cli || exit 1
|
||||
|
||||
# Get subscription info
|
||||
SUB_ID=$(get_current_subscription)
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
To migrate existing scripts to use the library:
|
||||
|
||||
1. **Remove duplicate code**:
|
||||
- Remove color definitions (use `lib/common/colors.sh`)
|
||||
- Remove SCRIPT_DIR/PROJECT_ROOT definitions (use `lib/common/paths.sh`)
|
||||
- Remove region code mappings (use `lib/config/regions.sh`)
|
||||
|
||||
2. **Replace with library calls**:
|
||||
```bash
|
||||
# Old
|
||||
RED='\033[0;31m'
|
||||
echo -e "${RED}Error${NC}"
|
||||
|
||||
# New
|
||||
source "$SCRIPT_DIR/lib/init.sh"
|
||||
log_error "Error"
|
||||
```
|
||||
|
||||
3. **Use standardized functions**:
|
||||
- Replace `az account show` checks with `ensure_azure_cli`
|
||||
- Replace manual color codes with logging functions
|
||||
- Replace duplicate region mappings with `get_region_code()`
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Single Source of Truth**: Region codes defined once
|
||||
2. **Consistency**: All scripts use the same colors, logging, and utilities
|
||||
3. **Maintainability**: Update once, applies everywhere
|
||||
4. **Reduced Duplication**: Eliminates repetitive code
|
||||
5. **Better Error Handling**: Standardized error messages and checks
|
||||
|
||||
55
scripts/lib/azure/cli.sh
Executable file
55
scripts/lib/azure/cli.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
# Azure CLI wrapper functions
|
||||
# Usage: source "$SCRIPT_DIR/lib/azure/cli.sh"
|
||||
|
||||
# Source logging if not already sourced
|
||||
[ -z "${log_error:-}" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../common/logging.sh"
|
||||
|
||||
# Check if Azure CLI is installed
|
||||
check_azure_cli() {
|
||||
if ! command -v az &> /dev/null; then
|
||||
log_error "Azure CLI not found. Please install Azure CLI."
|
||||
log_info "Visit: https://docs.microsoft.com/cli/azure/install-azure-cli"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check if logged in to Azure
|
||||
check_azure_login() {
|
||||
if ! az account show &> /dev/null; then
|
||||
log_error "Not logged in to Azure. Run 'az login' first."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Ensure Azure CLI is ready (checks installation and login)
|
||||
ensure_azure_cli() {
|
||||
check_azure_cli || return 1
|
||||
check_azure_login || return 1
|
||||
|
||||
# Set subscription if configured
|
||||
local subscription_id="${AZURE_SUBSCRIPTION_ID:-}"
|
||||
if [ -n "$subscription_id" ]; then
|
||||
az account set --subscription "$subscription_id" &> /dev/null || true
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get current subscription ID
|
||||
get_current_subscription() {
|
||||
az account show --query id -o tsv 2>/dev/null
|
||||
}
|
||||
|
||||
# Get current subscription name
|
||||
get_current_subscription_name() {
|
||||
az account show --query name -o tsv 2>/dev/null
|
||||
}
|
||||
|
||||
# List all subscriptions
|
||||
list_subscriptions() {
|
||||
az account list --query "[].{Name:name, ID:id, IsDefault:isDefault}" -o table
|
||||
}
|
||||
|
||||
23
scripts/lib/common/colors.sh
Executable file
23
scripts/lib/common/colors.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common color definitions for scripts
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/colors.sh"
|
||||
|
||||
# Color codes
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly MAGENTA='\033[0;35m'
|
||||
readonly CYAN='\033[0;36m'
|
||||
readonly WHITE='\033[1;37m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
|
||||
# Color functions for output
|
||||
color_red() { echo -e "${RED}$*${NC}"; }
|
||||
color_green() { echo -e "${GREEN}$*${NC}"; }
|
||||
color_yellow() { echo -e "${YELLOW}$*${NC}"; }
|
||||
color_blue() { echo -e "${BLUE}$*${NC}"; }
|
||||
color_cyan() { echo -e "${CYAN}$*${NC}"; }
|
||||
color_bold() { echo -e "${BOLD}$*${NC}"; }
|
||||
|
||||
45
scripts/lib/common/env.sh
Executable file
45
scripts/lib/common/env.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Environment loader and profile support
|
||||
# Provides: load_env [--profile <name>] [--file <path>] and helpers
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DEFAULT_ENV_FILE="${DEFAULT_ENV_FILE:-.env}"
|
||||
|
||||
load_env() {
|
||||
local profile=""; local file="$DEFAULT_ENV_FILE"; local opt
|
||||
while [[ $# -gt 0 ]]; do
|
||||
opt="$1"
|
||||
case "$opt" in
|
||||
--profile)
|
||||
profile="$2"; shift 2;;
|
||||
--file)
|
||||
file="$2"; shift 2;;
|
||||
*)
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
if [ -f "$file" ]; then
|
||||
# shellcheck disable=SC2046
|
||||
set -a; . "$file"; set +a
|
||||
fi
|
||||
if [ -n "$profile" ]; then
|
||||
local pf="${file}.${profile}"
|
||||
if [ -f "$pf" ]; then
|
||||
# shellcheck disable=SC2046
|
||||
set -a; . "$pf"; set +a
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
require_env() {
|
||||
local name="$1"
|
||||
if [ -z "${!name:-}" ]; then
|
||||
echo "Missing required env: $name" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
current_profile() {
|
||||
echo "${ENV_PROFILE:-}"
|
||||
}
|
||||
58
scripts/lib/common/error-handling.sh
Executable file
58
scripts/lib/common/error-handling.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# Error handling functions
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/error-handling.sh"
|
||||
|
||||
# Source logging if not already sourced
|
||||
[ -z "$(type -t log_error)" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/logging.sh"
|
||||
|
||||
# Error exit function
|
||||
error_exit() {
|
||||
local message="$1"
|
||||
local exit_code="${2:-1}"
|
||||
|
||||
log_error "$message"
|
||||
exit "$exit_code"
|
||||
}
|
||||
|
||||
# Cleanup function registry
|
||||
declare -a CLEANUP_FUNCTIONS=()
|
||||
|
||||
# Register cleanup function
|
||||
register_cleanup() {
|
||||
local func="$1"
|
||||
CLEANUP_FUNCTIONS+=("$func")
|
||||
}
|
||||
|
||||
# Execute cleanup functions
|
||||
cleanup_on_exit() {
|
||||
local exit_code=$?
|
||||
|
||||
for func in "${CLEANUP_FUNCTIONS[@]}"; do
|
||||
if type -t "$func" >/dev/null; then
|
||||
"$func" || true
|
||||
fi
|
||||
done
|
||||
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Setup error traps
|
||||
setup_error_traps() {
|
||||
# Trap ERR - command failures
|
||||
trap 'error_exit "Line $LINENO: Command failed: $BASH_COMMAND" $?' ERR
|
||||
|
||||
# Trap EXIT - cleanup
|
||||
trap 'cleanup_on_exit' EXIT
|
||||
|
||||
# Trap INT - Ctrl+C
|
||||
trap 'log_warn "Interrupted by user"; exit 130' INT
|
||||
|
||||
# Trap TERM - termination
|
||||
trap 'log_warn "Terminated"; exit 143' TERM
|
||||
}
|
||||
|
||||
# Check if error handling is enabled
|
||||
is_error_handling_enabled() {
|
||||
[[ $- == *e* ]]
|
||||
}
|
||||
|
||||
71
scripts/lib/common/logging.sh
Executable file
71
scripts/lib/common/logging.sh
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common logging functions for scripts
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/logging.sh"
|
||||
|
||||
# Source colors if not already sourced
|
||||
[ -z "${RED:-}" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/colors.sh"
|
||||
|
||||
# Logging levels (idempotent & safe to re-source)
|
||||
: "${LOG_LEVEL_DEBUG:=0}"
|
||||
: "${LOG_LEVEL_INFO:=1}"
|
||||
: "${LOG_LEVEL_WARN:=2}"
|
||||
: "${LOG_LEVEL_ERROR:=0}"
|
||||
# Mark as readonly if not already
|
||||
readonly LOG_LEVEL_DEBUG 2>/dev/null || true
|
||||
readonly LOG_LEVEL_INFO 2>/dev/null || true
|
||||
readonly LOG_LEVEL_WARN 2>/dev/null || true
|
||||
readonly LOG_LEVEL_ERROR 2>/dev/null || true
|
||||
|
||||
# Default log level
|
||||
: "${LOG_LEVEL:=$LOG_LEVEL_INFO}"
|
||||
|
||||
# Logging functions
|
||||
log_debug() {
|
||||
[ "$LOG_LEVEL" -le "$LOG_LEVEL_DEBUG" ] && echo -e "${CYAN}[DEBUG]${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_info() {
|
||||
[ "$LOG_LEVEL" -le "$LOG_LEVEL_INFO" ] && echo -e "${GREEN}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
[ "$LOG_LEVEL" -le "$LOG_LEVEL_WARN" ] && echo -e "${YELLOW}[WARN]${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_error() {
|
||||
[ "$LOG_LEVEL" -le "$LOG_LEVEL_ERROR" ] && echo -e "${RED}[ERROR]${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✓${NC} $*"
|
||||
}
|
||||
|
||||
log_failure() {
|
||||
echo -e "${RED}✗${NC} $*"
|
||||
}
|
||||
|
||||
log_section() {
|
||||
local title="$1"
|
||||
echo ""
|
||||
echo -e "${BOLD}${BLUE}════════════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${BOLD}${BLUE} ${title}${NC}"
|
||||
echo -e "${BOLD}${BLUE}════════════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
log_subsection() {
|
||||
local title="$1"
|
||||
echo ""
|
||||
echo -e "${CYAN}${title}${NC}"
|
||||
echo "$(printf '─%.0s' {1..60})"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Print separator line
|
||||
print_separator() {
|
||||
local char="${1:-=}"
|
||||
local width="${2:-80}"
|
||||
printf "%.0s${char}" $(seq 1 "$width")
|
||||
echo
|
||||
}
|
||||
|
||||
48
scripts/lib/common/metadata.sh
Executable file
48
scripts/lib/common/metadata.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
# Metadata and help utilities for scripts
|
||||
# Provides simple helpers to print script usage and header information.
|
||||
|
||||
# Print a standardized usage/help message using optional variables:
|
||||
# SCRIPT_NAME, SCRIPT_DESC, SCRIPT_USAGE, SCRIPT_OPTIONS, SCRIPT_ENVVARS, SCRIPT_REQUIREMENTS, SCRIPT_EXAMPLE
|
||||
script_usage() {
|
||||
local name="${SCRIPT_NAME:-${0##*/}}"
|
||||
echo "${name}"
|
||||
[ -n "${SCRIPT_DESC:-}" ] && echo "Description: ${SCRIPT_DESC}"
|
||||
if [ -n "${SCRIPT_USAGE:-}" ]; then
|
||||
echo "Usage: ${SCRIPT_USAGE}"
|
||||
else
|
||||
echo "Usage: ${name} [options]"
|
||||
fi
|
||||
if [ -n "${SCRIPT_OPTIONS:-}" ]; then
|
||||
echo
|
||||
echo "Options:"
|
||||
# shellcheck disable=SC2001
|
||||
echo "${SCRIPT_OPTIONS}" | sed 's/^/ /'
|
||||
fi
|
||||
if [ -n "${SCRIPT_ENVVARS:-}" ]; then
|
||||
echo
|
||||
echo "Environment:"
|
||||
# shellcheck disable=SC2001
|
||||
echo "${SCRIPT_ENVVARS}" | sed 's/^/ /'
|
||||
fi
|
||||
if [ -n "${SCRIPT_REQUIREMENTS:-}" ]; then
|
||||
echo
|
||||
echo "Requires: ${SCRIPT_REQUIREMENTS}"
|
||||
fi
|
||||
if [ -n "${SCRIPT_EXAMPLE:-}" ]; then
|
||||
echo
|
||||
echo "Example:"
|
||||
# shellcheck disable=SC2001
|
||||
echo "${SCRIPT_EXAMPLE}" | sed 's/^/ /'
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle -h/--help; call after sourcing init and setting metadata vars
|
||||
handle_help() {
|
||||
case "${1:-}" in
|
||||
-h|--help)
|
||||
script_usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
25
scripts/lib/common/paths.sh
Executable file
25
scripts/lib/common/paths.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common path definitions for scripts
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/paths.sh"
|
||||
|
||||
# Get script directory (works even when sourced)
|
||||
if [ -z "${SCRIPT_DIR:-}" ]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-}")" && pwd)"
|
||||
# If sourced from another script, try to get the calling script's directory
|
||||
if [ "${BASH_SOURCE[0]:-}" = "${BASH_SOURCE[1]:-}" ]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]:-}")" && pwd)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Project root (two levels up from scripts/)
|
||||
if [ -z "${PROJECT_ROOT:-}" ]; then
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
fi
|
||||
|
||||
# Common directories
|
||||
readonly CONFIG_DIR="${PROJECT_ROOT}/config"
|
||||
readonly KEYS_DIR="${PROJECT_ROOT}/keys"
|
||||
readonly SCRIPTS_DIR="${PROJECT_ROOT}/scripts"
|
||||
readonly TERRAFORM_DIR="${PROJECT_ROOT}/terraform"
|
||||
readonly DOCS_DIR="${PROJECT_ROOT}/docs"
|
||||
|
||||
113
scripts/lib/common/retry.sh
Executable file
113
scripts/lib/common/retry.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
# Retry functions with exponential backoff
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/retry.sh"
|
||||
|
||||
# Source logging if not already sourced
|
||||
[ -z "$(type -t log_info)" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/logging.sh"
|
||||
|
||||
# Retry a command with exponential backoff
|
||||
# Usage: retry_command <max_attempts> <delay> <command> [args...]
|
||||
retry_command() {
|
||||
local max_attempts="$1"
|
||||
local base_delay="$2"
|
||||
shift 2
|
||||
local command=("$@")
|
||||
|
||||
local attempt=1
|
||||
local delay="$base_delay"
|
||||
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
log_info "Attempt $attempt/$max_attempts: ${command[*]}"
|
||||
|
||||
if "${command[@]}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ $attempt -lt $max_attempts ]; then
|
||||
log_warn "Command failed, retrying in ${delay}s..."
|
||||
sleep "$delay"
|
||||
delay=$((delay * 2)) # Exponential backoff
|
||||
fi
|
||||
|
||||
((attempt++)) || true
|
||||
done
|
||||
|
||||
log_error "Command failed after $max_attempts attempts: ${command[*]}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Retry a function with exponential backoff
|
||||
# Usage: retry_function <max_attempts> <delay> <function_name> [args...]
|
||||
retry_function() {
|
||||
local max_attempts="$1"
|
||||
local base_delay="$2"
|
||||
local func_name="$3"
|
||||
shift 3
|
||||
local args=("$@")
|
||||
|
||||
local attempt=1
|
||||
local delay="$base_delay"
|
||||
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
log_info "Attempt $attempt/$max_attempts: $func_name"
|
||||
|
||||
if "$func_name" "${args[@]}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ $attempt -lt $max_attempts ]; then
|
||||
log_warn "Function failed, retrying in ${delay}s..."
|
||||
sleep "$delay"
|
||||
delay=$((delay * 2)) # Exponential backoff
|
||||
fi
|
||||
|
||||
((attempt++)) || true
|
||||
done
|
||||
|
||||
log_error "Function failed after $max_attempts attempts: $func_name"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for a condition to be true
|
||||
# Usage: wait_for_condition <timeout> <interval> <condition_command>
|
||||
wait_for_condition() {
|
||||
local timeout="$1"
|
||||
local interval="$2"
|
||||
shift 2
|
||||
local condition=("$@")
|
||||
|
||||
local elapsed=0
|
||||
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if "${condition[@]}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep "$interval"
|
||||
elapsed=$((elapsed + interval))
|
||||
done
|
||||
|
||||
log_error "Condition not met within ${timeout}s: ${condition[*]}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for a service to be ready
|
||||
# Usage: wait_for_service <url> <timeout> <interval>
|
||||
wait_for_service() {
|
||||
local url="$1"
|
||||
local timeout="${2:-60}"
|
||||
local interval="${3:-5}"
|
||||
|
||||
wait_for_condition "$timeout" "$interval" curl -sf "$url" >/dev/null
|
||||
}
|
||||
|
||||
# Wait for a file to exist
|
||||
# Usage: wait_for_file <file_path> <timeout> <interval>
|
||||
wait_for_file() {
|
||||
local file_path="$1"
|
||||
local timeout="${2:-60}"
|
||||
local interval="${3:-5}"
|
||||
|
||||
wait_for_condition "$timeout" "$interval" test -f "$file_path"
|
||||
}
|
||||
|
||||
81
scripts/lib/common/utils.sh
Executable file
81
scripts/lib/common/utils.sh
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common utility functions
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/utils.sh"
|
||||
|
||||
# Source colors if not already sourced
|
||||
[ -z "${RED:-}" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/colors.sh"
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" &> /dev/null
|
||||
}
|
||||
|
||||
# Require command (exits if not found)
|
||||
require_command() {
|
||||
local cmd="$1"
|
||||
local install_hint="${2:-}"
|
||||
|
||||
if ! command_exists "$cmd"; then
|
||||
echo -e "${RED}Error: $cmd not found${NC}" >&2
|
||||
[ -n "$install_hint" ] && echo -e "${YELLOW}Hint: $install_hint${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Confirm action
|
||||
confirm() {
|
||||
local prompt="${1:-Are you sure?}"
|
||||
local default="${2:-n}"
|
||||
|
||||
if [ "$default" = "y" ]; then
|
||||
local options="[Y/n]"
|
||||
else
|
||||
local options="[y/N]"
|
||||
fi
|
||||
|
||||
read -p "$(echo -e "${YELLOW}${prompt} ${options}: ${NC}")" -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]] || ([ "$default" = "y" ] && [[ -z $REPLY ]]); then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for user input
|
||||
press_enter_to_continue() {
|
||||
read -p "$(echo -e "${CYAN}Press Enter to continue...${NC}")"
|
||||
}
|
||||
|
||||
# Print header box
|
||||
print_header() {
|
||||
local title="$1"
|
||||
local width="${2:-80}"
|
||||
|
||||
echo "╔$(printf '═%.0s' $(seq 1 $((width-2))))╗"
|
||||
printf "║ %-${width-4}s ║\n" "$title"
|
||||
echo "╚$(printf '═%.0s' $(seq 1 $((width-2))))╝"
|
||||
echo
|
||||
}
|
||||
|
||||
# Print centered text
|
||||
print_centered() {
|
||||
local text="$1"
|
||||
local width="${2:-80}"
|
||||
printf "%*s\n" $(((${#text} + width) / 2)) "$text"
|
||||
}
|
||||
|
||||
# Trim whitespace
|
||||
trim() {
|
||||
local var="$*"
|
||||
var="${var#"${var%%[![:space:]]*}"}" # Remove leading whitespace
|
||||
var="${var%"${var##*[![:space:]]}"}" # Remove trailing whitespace
|
||||
echo "$var"
|
||||
}
|
||||
|
||||
# Check if running in dry-run mode
|
||||
is_dry_run() {
|
||||
[ "${DRY_RUN:-0}" = "1" ] || [ "${DRY_RUN:-0}" = "true" ]
|
||||
}
|
||||
|
||||
211
scripts/lib/common/validation.sh
Executable file
211
scripts/lib/common/validation.sh
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validation functions for scripts
|
||||
# Usage: source "$SCRIPT_DIR/lib/common/validation.sh"
|
||||
|
||||
# Source colors and logging if not already sourced
|
||||
[ -z "${RED:-}" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/colors.sh"
|
||||
[ -z "$(type -t log_error)" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/logging.sh"
|
||||
|
||||
# Validate required environment variable
|
||||
validate_required() {
|
||||
local var_name="$1"
|
||||
local var_value="${!var_name:-}"
|
||||
|
||||
if [ -z "$var_value" ]; then
|
||||
log_error "$var_name is required but not set"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate file exists
|
||||
validate_file_exists() {
|
||||
local file_path="$1"
|
||||
local description="${2:-File}"
|
||||
|
||||
if [ ! -f "$file_path" ]; then
|
||||
log_error "$description not found: $file_path"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate directory exists
|
||||
validate_directory_exists() {
|
||||
local dir_path="$1"
|
||||
local description="${2:-Directory}"
|
||||
|
||||
if [ ! -d "$dir_path" ]; then
|
||||
log_error "$description not found: $dir_path"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate JSON file
|
||||
validate_json() {
|
||||
local json_file="$1"
|
||||
|
||||
if ! python3 -m json.tool "$json_file" >/dev/null 2>&1; then
|
||||
log_error "Invalid JSON file: $json_file"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate YAML file
|
||||
validate_yaml() {
|
||||
local yaml_file="$1"
|
||||
|
||||
if ! command -v yamllint &>/dev/null; then
|
||||
log_warn "yamllint not installed, skipping YAML validation"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! yamllint "$yaml_file" >/dev/null 2>&1; then
|
||||
log_error "Invalid YAML file: $yaml_file"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate TOML file
|
||||
validate_toml() {
|
||||
local toml_file="$1"
|
||||
|
||||
if ! python3 -c "import tomllib; open('$toml_file', 'rb').read()" 2>/dev/null; then
|
||||
log_error "Invalid TOML file: $toml_file"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate URL format
|
||||
validate_url() {
|
||||
local url="$1"
|
||||
|
||||
if [[ ! "$url" =~ ^https?:// ]]; then
|
||||
log_error "Invalid URL format: $url"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate IP address
|
||||
validate_ip() {
|
||||
local ip="$1"
|
||||
|
||||
if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
log_error "Invalid IP address format: $ip"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check each octet is 0-255
|
||||
IFS='.' read -ra ADDR <<< "$ip"
|
||||
for i in "${ADDR[@]}"; do
|
||||
if [ "$i" -gt 255 ] || [ "$i" -lt 0 ]; then
|
||||
log_error "Invalid IP address: $ip (octet out of range)"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate port number
|
||||
validate_port() {
|
||||
local port="$1"
|
||||
|
||||
if [[ ! "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
|
||||
log_error "Invalid port number: $port (must be 1-65535)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate Ethereum address
|
||||
validate_eth_address() {
|
||||
local address="$1"
|
||||
|
||||
if [[ ! "$address" =~ ^0x[0-9a-fA-F]{40}$ ]]; then
|
||||
log_error "Invalid Ethereum address format: $address"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate chain ID
|
||||
validate_chain_id() {
|
||||
local chain_id="$1"
|
||||
|
||||
if [[ ! "$chain_id" =~ ^[0-9]+$ ]] || [ "$chain_id" -lt 1 ]; then
|
||||
log_error "Invalid chain ID: $chain_id"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate non-empty string
|
||||
validate_non_empty() {
|
||||
local value="$1"
|
||||
local name="${2:-Value}"
|
||||
|
||||
if [ -z "$value" ]; then
|
||||
log_error "$name cannot be empty"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate numeric value
|
||||
validate_numeric() {
|
||||
local value="$1"
|
||||
local name="${2:-Value}"
|
||||
|
||||
if [[ ! "$value" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
|
||||
log_error "$name must be numeric: $value"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate positive number
|
||||
validate_positive() {
|
||||
local value="$1"
|
||||
local name="${2:-Value}"
|
||||
|
||||
if ! validate_numeric "$value" "$name"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if (( $(echo "$value <= 0" | bc -l) )); then
|
||||
log_error "$name must be positive: $value"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate command exists
|
||||
validate_command() {
|
||||
local cmd="$1"
|
||||
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
log_error "Command not found: $cmd"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate multiple requirements
|
||||
validate_all() {
|
||||
local failed=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
if ! "$@"; then
|
||||
failed=1
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
36
scripts/lib/config/env.sh
Executable file
36
scripts/lib/config/env.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Environment configuration loader
|
||||
# Usage: source "$SCRIPT_DIR/lib/config/env.sh"
|
||||
|
||||
# Source paths if not already sourced
|
||||
[ -z "${PROJECT_ROOT:-}" ] && source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../common/paths.sh"
|
||||
|
||||
# Default subscription ID
|
||||
DEFAULT_SUBSCRIPTION_ID="${DEFAULT_SUBSCRIPTION_ID:-fc08d829-4f14-413d-ab27-ce024425db0b}"
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_env() {
|
||||
local env_file="${1:-${PROJECT_ROOT}/.env}"
|
||||
|
||||
if [ -f "$env_file" ]; then
|
||||
# Export variables, ignoring comments and empty lines
|
||||
set -a
|
||||
source <(grep -v '^#' "$env_file" | grep -v '^$' | sed 's/^/export /')
|
||||
set +a
|
||||
fi
|
||||
}
|
||||
|
||||
# Get Azure subscription ID
|
||||
get_subscription_id() {
|
||||
echo "${AZURE_SUBSCRIPTION_ID:-${DEFAULT_SUBSCRIPTION_ID}}"
|
||||
}
|
||||
|
||||
# Set Azure subscription
|
||||
set_subscription() {
|
||||
local subscription_id="${1:-$(get_subscription_id)}"
|
||||
az account set --subscription "$subscription_id" &> /dev/null || return 1
|
||||
}
|
||||
|
||||
# Auto-load env if PROJECT_ROOT is set
|
||||
[ -n "${PROJECT_ROOT:-}" ] && load_env
|
||||
|
||||
121
scripts/lib/config/regions.sh
Executable file
121
scripts/lib/config/regions.sh
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env bash
|
||||
# Region code mapping - Single source of truth
|
||||
# All region codes are standardized to exactly 3 characters
|
||||
# Usage: source "$SCRIPT_DIR/lib/config/regions.sh"
|
||||
|
||||
# Region codes mapping (standardized to exactly 3 characters)
|
||||
declare -A REGION_CODES=(
|
||||
["northeurope"]="nor"
|
||||
["uksouth"]="uks"
|
||||
["ukwest"]="ukw"
|
||||
["westeurope"]="wst"
|
||||
["francecentral"]="frc"
|
||||
["germanywestcentral"]="gwc"
|
||||
["switzerlandnorth"]="swn"
|
||||
["switzerlandwest"]="swt"
|
||||
["swedencentral"]="swc"
|
||||
["norwayeast"]="noe"
|
||||
["polandcentral"]="pol"
|
||||
["spaincentral"]="spa"
|
||||
["italynorth"]="ita"
|
||||
["southindia"]="sin"
|
||||
["centralindia"]="cin"
|
||||
["westindia"]="win"
|
||||
["belgiumcentral"]="bel"
|
||||
["eastasia"]="eas"
|
||||
["southeastasia"]="sea"
|
||||
["japaneast"]="jpe"
|
||||
["japanwest"]="jpw"
|
||||
["koreacentral"]="kor"
|
||||
["koreasouth"]="kos"
|
||||
["australiaeast"]="aus"
|
||||
["australiasoutheast"]="ase"
|
||||
["newzealandnorth"]="nzl"
|
||||
["indonesiacentral"]="idn"
|
||||
["malaysiawest"]="mys"
|
||||
["uaenorth"]="uae"
|
||||
["qatarcentral"]="qat"
|
||||
["israelcentral"]="ilc"
|
||||
["canadacentral"]="can"
|
||||
["canadaeast"]="cae"
|
||||
["brazilsouth"]="bra"
|
||||
["chilecentral"]="chl"
|
||||
["mexicocentral"]="mex"
|
||||
["southafricanorth"]="zaf"
|
||||
["austriaeast"]="aut"
|
||||
)
|
||||
|
||||
# Reverse mapping (code -> region name)
|
||||
declare -A REGION_CODE_TO_NAME=()
|
||||
for region_name in "${!REGION_CODES[@]}"; do
|
||||
REGION_CODE_TO_NAME["${REGION_CODES[$region_name]}"]="$region_name"
|
||||
done
|
||||
|
||||
# Old code mappings (for backward compatibility with existing resources)
|
||||
declare -A OLD_CODE_TO_REGION=(
|
||||
["ne"]="northeurope"
|
||||
["we"]="westeurope"
|
||||
["fc"]="francecentral"
|
||||
["sn"]="switzerlandnorth"
|
||||
["sw"]="switzerlandwest"
|
||||
["in"]="italynorth"
|
||||
["pc"]="polandcentral"
|
||||
["sc"]="spaincentral"
|
||||
["bc"]="belgiumcentral"
|
||||
["ae"]="australiaeast" # Note: conflicts with austriaeast (old), prefer australiaeast
|
||||
["ea"]="eastasia"
|
||||
["ci"]="centralindia"
|
||||
["si"]="southindia"
|
||||
["wi"]="westindia"
|
||||
["je"]="japaneast"
|
||||
["jw"]="japanwest"
|
||||
["kc"]="koreacentral"
|
||||
["ks"]="koreasouth"
|
||||
["cc"]="canadacentral"
|
||||
["ce"]="canadaeast"
|
||||
["bs"]="brazilsouth"
|
||||
["mc"]="mexicocentral"
|
||||
["qc"]="qatarcentral"
|
||||
["ic"]="indonesiacentral"
|
||||
["mw"]="malaysiawest"
|
||||
["nzn"]="newzealandnorth"
|
||||
["san"]="southafricanorth"
|
||||
["uan"]="uaenorth"
|
||||
["chc"]="chilecentral"
|
||||
)
|
||||
|
||||
# Get all regions as array (region_name:code format)
|
||||
get_all_regions() {
|
||||
for region_name in "${!REGION_CODES[@]}"; do
|
||||
echo "${region_name}:${REGION_CODES[$region_name]}"
|
||||
done | sort
|
||||
}
|
||||
|
||||
# Get region code by region name
|
||||
get_region_code() {
|
||||
local region_name="$1"
|
||||
echo "${REGION_CODES[$region_name]:-}"
|
||||
}
|
||||
|
||||
# Get region name by code (tries new codes first, then old codes)
|
||||
get_region_name() {
|
||||
local code="$1"
|
||||
# Try new codes first
|
||||
if [ -n "${REGION_CODE_TO_NAME[$code]:-}" ]; then
|
||||
echo "${REGION_CODE_TO_NAME[$code]}"
|
||||
return 0
|
||||
fi
|
||||
# Try old codes for backward compatibility
|
||||
if [ -n "${OLD_CODE_TO_REGION[$code]:-}" ]; then
|
||||
echo "${OLD_CODE_TO_REGION[$code]}"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Validate region code (must be 3 characters)
|
||||
is_valid_region_code() {
|
||||
local code="$1"
|
||||
[[ "$code" =~ ^[a-z]{3}$ ]] && [ -n "${REGION_CODE_TO_NAME[$code]:-}" ]
|
||||
}
|
||||
|
||||
150
scripts/lib/deployment/costs.sh
Executable file
150
scripts/lib/deployment/costs.sh
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env bash
|
||||
# Cost calculation library
|
||||
# Usage: source "$SCRIPT_DIR/lib/deployment/costs.sh"
|
||||
|
||||
# Source libraries (use absolute path resolution)
|
||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
[ -z "${PROJECT_ROOT:-}" ] && source "${LIB_DIR}/../common/paths.sh"
|
||||
[ -z "${log_info:-}" ] && source "${LIB_DIR}/../common/logging.sh"
|
||||
|
||||
# Check for required commands
|
||||
command_exists() {
|
||||
command -v "$1" &> /dev/null
|
||||
}
|
||||
|
||||
# Default gas requirements (in wei units, can be overridden)
|
||||
DEFAULT_CCIPWETH9_BRIDGE_GAS="${CCIPWETH9_BRIDGE_GAS:-263000}"
|
||||
DEFAULT_CCIPWETH10_BRIDGE_GAS="${CCIPWETH10_BRIDGE_GAS:-263000}"
|
||||
DEFAULT_CONFIGURATION_GAS="${CONFIGURATION_GAS:-200000}"
|
||||
|
||||
# Load environment variables
|
||||
load_env_file() {
|
||||
local env_file="${PROJECT_ROOT}/.env"
|
||||
if [ -f "$env_file" ]; then
|
||||
set -a
|
||||
source "$env_file"
|
||||
set +a
|
||||
fi
|
||||
}
|
||||
|
||||
# Get gas price from multiple sources
|
||||
get_gas_price() {
|
||||
local source_type="${1:-auto}" # auto, rpc, infura, default, conservative
|
||||
|
||||
load_env_file
|
||||
|
||||
local gas_price_wei=""
|
||||
local gas_price_gwei=""
|
||||
local source_name=""
|
||||
|
||||
case "$source_type" in
|
||||
rpc|auto)
|
||||
# Try ETHEREUM_MAINNET_RPC
|
||||
if [ -n "${ETHEREUM_MAINNET_RPC:-}" ]; then
|
||||
if command_exists cast; then
|
||||
gas_price_wei=$(cast gas-price --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null || echo "")
|
||||
if [ -n "$gas_price_wei" ] && [ "$gas_price_wei" != "0" ]; then
|
||||
gas_price_gwei=$(cast --to-unit "$gas_price_wei" gwei 2>/dev/null || echo "")
|
||||
source_name="ETHEREUM_MAINNET_RPC"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
infura|auto)
|
||||
# Try Infura Gas API
|
||||
if [ -z "$gas_price_wei" ] && [ -n "${INFURA_GAS_API:-}" ]; then
|
||||
local api_key="$INFURA_GAS_API"
|
||||
# Extract API key from URL if needed
|
||||
if [[ "$INFURA_GAS_API" == *"infura.io"* ]]; then
|
||||
api_key=$(echo "$INFURA_GAS_API" | sed -n 's|.*/v3/\(.*\)|\1|p')
|
||||
fi
|
||||
|
||||
if [ -n "$api_key" ] && command_exists curl && command_exists jq; then
|
||||
local response=$(curl -s "https://gas.api.infura.io/networks/1/suggestedGasFees" \
|
||||
-H "Authorization: Basic $(echo -n :$api_key | base64)" 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$response" ]; then
|
||||
local standard_gas=$(echo "$response" | jq -r '.standard.maxFeePerGas' 2>/dev/null || echo "")
|
||||
if [ -n "$standard_gas" ] && [ "$standard_gas" != "null" ] && [ "$standard_gas" != "" ]; then
|
||||
gas_price_wei="$standard_gas"
|
||||
if command_exists cast; then
|
||||
gas_price_gwei=$(cast --to-unit "$gas_price_wei" gwei 2>/dev/null || echo "")
|
||||
else
|
||||
gas_price_gwei=$(echo "scale=2; $gas_price_wei / 1000000000" | bc 2>/dev/null || echo "")
|
||||
fi
|
||||
source_name="Infura Gas API"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
default|auto)
|
||||
# Fallback to default RPC
|
||||
if [ -z "$gas_price_wei" ] && command_exists cast; then
|
||||
gas_price_wei=$(cast gas-price --rpc-url "https://eth.llamarpc.com" 2>/dev/null || echo "")
|
||||
if [ -n "$gas_price_wei" ] && [ "$gas_price_wei" != "0" ]; then
|
||||
gas_price_gwei=$(cast --to-unit "$gas_price_wei" gwei 2>/dev/null || echo "")
|
||||
source_name="Default RPC"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
conservative)
|
||||
# Use conservative estimate (50% above current)
|
||||
gas_price_wei=$(get_gas_price "auto")
|
||||
if [ -n "$gas_price_wei" ] && [ "$gas_price_wei" != "0" ]; then
|
||||
gas_price_wei=$(echo "$gas_price_wei * 1.5" | bc 2>/dev/null || echo "$gas_price_wei")
|
||||
if command_exists cast; then
|
||||
gas_price_gwei=$(cast --to-unit "$gas_price_wei" gwei 2>/dev/null || echo "")
|
||||
else
|
||||
gas_price_gwei=$(echo "scale=2; $gas_price_wei / 1000000000" | bc 2>/dev/null || echo "")
|
||||
fi
|
||||
source_name="Conservative Estimate"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Final fallback
|
||||
if [ -z "$gas_price_wei" ] || [ "$gas_price_wei" = "0" ]; then
|
||||
gas_price_gwei="${DEFAULT_GAS_PRICE_GWEI:-30}"
|
||||
gas_price_wei=$(echo "$gas_price_gwei * 1000000000" | bc 2>/dev/null || echo "30000000000")
|
||||
source_name="Fallback Default"
|
||||
fi
|
||||
|
||||
echo "$gas_price_wei|$gas_price_gwei|$source_name"
|
||||
}
|
||||
|
||||
# Calculate cost in ETH
|
||||
calculate_cost_eth() {
|
||||
local gas=$1
|
||||
local gas_price_wei=$2
|
||||
|
||||
local cost_wei=$(echo "$gas * $gas_price_wei" | bc 2>/dev/null || echo "0")
|
||||
local cost_eth=$(echo "scale=10; $cost_wei / 1000000000000000000" | bc 2>/dev/null || echo "0")
|
||||
|
||||
echo "$cost_eth"
|
||||
}
|
||||
|
||||
# Calculate cost in USD
|
||||
calculate_cost_usd() {
|
||||
local cost_eth=$1
|
||||
local eth_price_usd="${2:-${ETH_PRICE_USD:-2500}}"
|
||||
|
||||
local cost_usd=$(echo "scale=2; $cost_eth * $eth_price_usd" | bc 2>/dev/null || echo "0")
|
||||
echo "$cost_usd"
|
||||
}
|
||||
|
||||
# Format cost output
|
||||
format_cost_output() {
|
||||
local item_name="$1"
|
||||
local cost_eth="$2"
|
||||
local cost_usd="$3"
|
||||
|
||||
printf "%-30s %18.8f ETH $%15.2f\n" "$item_name" "$cost_eth" "$cost_usd"
|
||||
}
|
||||
|
||||
# Get ETH price (simple version, can be enhanced)
|
||||
get_eth_price() {
|
||||
local eth_price="${ETH_PRICE_USD:-2500}"
|
||||
echo "$eth_price"
|
||||
}
|
||||
|
||||
37
scripts/lib/init.sh
Executable file
37
scripts/lib/init.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# Initialize common libraries
|
||||
# Usage: source "$SCRIPT_DIR/lib/init.sh"
|
||||
#
|
||||
# This script loads all common libraries in the correct order.
|
||||
# Individual scripts can source this instead of sourcing each library separately.
|
||||
|
||||
# Get lib directory (this file's directory)
|
||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Get script directory if not set (try to get from calling script)
|
||||
if [ -z "${SCRIPT_DIR:-}" ]; then
|
||||
# Try to get from calling script (BASH_SOURCE[2] because init.sh adds one level)
|
||||
if [ -n "${BASH_SOURCE[2]:-}" ]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[2]}")" && pwd)"
|
||||
elif [ -n "${BASH_SOURCE[1]:-}" ]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Source libraries in order
|
||||
source "${LIB_DIR}/common/paths.sh"
|
||||
source "${LIB_DIR}/common/colors.sh"
|
||||
source "${LIB_DIR}/common/logging.sh"
|
||||
source "${LIB_DIR}/common/utils.sh"
|
||||
source "${LIB_DIR}/common/env.sh"
|
||||
source "${LIB_DIR}/common/metadata.sh"
|
||||
source "${LIB_DIR}/common/validation.sh" 2>/dev/null || true
|
||||
source "${LIB_DIR}/common/retry.sh" 2>/dev/null || true
|
||||
source "${LIB_DIR}/common/error-handling.sh" 2>/dev/null || true
|
||||
source "${LIB_DIR}/config/env.sh"
|
||||
source "${LIB_DIR}/config/regions.sh"
|
||||
source "${LIB_DIR}/azure/cli.sh" 2>/dev/null || true
|
||||
|
||||
# Log that libraries are loaded (only in debug mode)
|
||||
[ "${LOG_LEVEL:-1}" -le 0 ] && log_debug "Common libraries loaded from ${LIB_DIR}"
|
||||
|
||||
Reference in New Issue
Block a user