diff --git a/composer.sh b/composer.sh new file mode 100644 index 0000000..4a1622f --- /dev/null +++ b/composer.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash + +# Exit on error, undefined variables, and pipe failures +set -euo pipefail + +# Script constants +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly CONFIG_FILE="docker-composer.conf" +readonly DOCKER_COMPOSE_FILE="docker-compose.yml" + +# Color definitions +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" >&2 +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +# Validation functions +validate_dependencies() { + local missing_deps=() + + if ! command -v docker &> /dev/null; then + missing_deps+=("docker") + fi + + if ! command -v awk &> /dev/null; then + missing_deps+=("awk") + fi + + if [ ${#missing_deps[@]} -ne 0 ]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + exit 1 + fi +} + +validate_config_file() { + if [ ! -f "$CONFIG_FILE" ]; then + log_error "Configuration file '$CONFIG_FILE' not found!" + exit 1 + fi +} + +validate_compose_path() { + local compose_path="$1" + + if [ ! -d "$compose_path" ]; then + log_error "Compose path '$compose_path' does not exist or is not a directory!" + exit 1 + fi +} + +# Function to read and parse configuration +parse_config() { + local working_dir="$PWD" + + # Read compose_path + compose_path=$(awk -F "=" ' + /^compose_path/ { + gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2) # Trim whitespace + gsub(/\/$/, "", $2) # Remove trailing slash + if ($2 ~ /^\//) { + print $2 + } else { + print "'"$working_dir"'/"$2 + } + } + ' "$CONFIG_FILE") + + if [ -z "$compose_path" ]; then + log_error "compose_path not found in configuration" + exit 1 + fi + + # Read exclude_containers + exclude_containers=$(awk -F "=" ' + /^exclude_containers/ { + gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2) # Trim whitespace + gsub(/ /, "", $2) # Remove spaces + print $2 + } + ' "$CONFIG_FILE") + + # Convert exclude_containers to array + IFS=',' read -ra EXCLUDE_ARRAY <<< "$exclude_containers" +} + +# Function to check if a container should be excluded +is_excluded() { + local container_name="$1" + for excluded in "${EXCLUDE_ARRAY[@]}"; do + if [ "$container_name" = "$excluded" ]; then + return 0 + fi + done + return 1 +} + +# Function to compose a single container +compose_container() { + local dir="$1" + local container="$2" + local compose_file="${dir%/}/$DOCKER_COMPOSE_FILE" + + if [ ! -f "$compose_file" ]; then + log_warn "Skipping $container: $DOCKER_COMPOSE_FILE not found" + return 1 + } + + log_info "Composing ${container}..." + if docker compose -f "$compose_file" up -d; then + log_info "Successfully composed ${container}" + return 0 + else + log_error "Failed to compose ${container}" + return 1 + fi +} + +main() { + # Validate environment and configuration + validate_dependencies + validate_config_file + + # Parse configuration + parse_config + validate_compose_path "$compose_path" + + # Initialize arrays for directories and containers + local compose_dirs=() + local containers=() + local failed_containers=() + + # Collect valid directories and container names + while IFS= read -r dir; do + base_name=$(basename "$dir") + if [[ -d "$dir" && ! "$base_name" =~ ^\. && ! $(is_excluded "$base_name") ]]; then + compose_dirs+=("$dir/") + containers+=("$base_name") + fi + done < <(find "$compose_path" -maxdepth 1 -mindepth 1 -type d) + + if [ ${#compose_dirs[@]} -eq 0 ]; then + log_warn "No valid containers found to compose" + exit 0 + fi + + log_info "Found ${#containers[@]} containers to compose" + + # Compose containers + for i in "${!compose_dirs[@]}"; do + if ! compose_container "${compose_dirs[i]}" "${containers[i]}"; then + failed_containers+=("${containers[i]}") + fi + done + + # Report results + if [ ${#failed_containers[@]} -eq 0 ]; then + log_info "All containers composed successfully" + else + log_error "Failed to compose the following containers: ${failed_containers[*]}" + exit 1 + fi +} + +# Execute main function +main "$@" \ No newline at end of file