#!/usr/bin/env bash # Modifying it manually is not recommended # :wrapper.bash3_bouncer if [[ "${BASH_VERSINFO:-0}" -lt 3 ]]; then printf "bash version 3 or higher is required\n" >&2 exit 1 fi # :command.master_script # :command.version_command version_command() { echo "$version" } upper() { echo "$1" | tr '[:lower:]' '[:upper:]' } lower() { echo "$1" | tr '[:upper:]' '[:lower:]' } # Add a key-value pair to the args array add_arg() { local key="$1" local value="$2" args_keys+=("$key") args_values+=("$value") } # Get the value of a key from the args array get_arg() { local key="$1" local default="${2:-}" local i for i in "${!args_keys[@]}"; do if [ "${args_keys[$i]}" = "$key" ]; then echo "${args_values[$i]}" return 0 fi done echo "$default" return 1 } # :command.usage devbox_usage() { printf "Command\n" printf " devbox : DevBox Command Line Tool for managing the local development environment.\n\n" printf "Arguments\n" printf " COMMAND [Required] : Specify the command to execute (e.g., init, deinit, start, stop, status, restart).\n\n" printf "Global Arguments\n" printf " --help, -h : Show this help message and exit.\n" printf " --version, -v : Show version number.\n\n" printf "Examples\n" printf " Display help for the 'init' command:\n" printf " devbox init --help\n\n" printf " Display version information:\n" printf " devbox --version\n" echo } # :command.usage devbox_init_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox init : Initialize the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --os -o [Optional] : Specifies the operating system. Default: auto.\n" printf " --arch -a [Optional] : Specifies the architecture. Default: auto.\n" printf " --working-home -w [Optional] : Specifies the working home of DevBox CLI. Default: %s/.devbox\n" "$HOME" printf " --devbox-container-name -N [Optional] : Specifies the DevBox container name. Default: devbox.\n" printf " --devbox-container-port -P [Optional] : Specifies the container port for DevBox SSH access. Default: 22222.\n" printf " --devbox-image-repo -R [Optional] : Specifies the DevBox container image repository. Default: docker.io/freeleaps.\n" printf " --devbox-image-name -I [Optional] : Specifies the DevBox container image name. Default: devbox.\n" printf " --devbox-image-tag -T [Optional] : Specifies the DevBox container image tag. Default: latest.\n" printf " --devbox-frontend-port -F [Optional] : Specifies the container port for DevBox frontend access. Default: 5173.\n" printf " --devbox-backend-port -B [Optional] : Specifies the container port for DevBox backend access. Default: 8002.\n" printf " --freeleaps-username -U [Optional] : Specifies the Freeleaps.com repository username.\n" printf " --freeleaps-password -X [Optional] : Specifies the Freeleaps.com repository password.\n" printf " --use-local-component -u [Optional] : Check if using local component or online dev environment. Default: false.\n" printf " --devsvc-image-repo -D [Optional] : Specifies the repository for devsvc component.\n" printf " --devsvc-image-name -M [Optional] : Specifies the image name for devsvc component.\n" printf " --devsvc-image-tag -G [Optional] : Specifies the image tag for devsvc component. Default: latest.\n" printf " --notification-image-repo -Y [Optional] : Specifies the repository for notification component.\n" printf " --notification-image-name -K [Optional] : Specifies the image name for notification component.\n" printf " --notification-image-tag -Z [Optional] : Specifies the image tag for notification component. Default: latest.\n" printf " --content-image-repo -C [Optional] : Specifies the repository for content component.\n" printf " --content-image-name -E [Optional] : Specifies the image name for content component.\n" printf " --content-image-tag -H [Optional] : Specifies the image tag for content component. Default: latest.\n" printf " --central_storage-image-repo -S [Optional] : Specifies the repository for central_storage component.\n" printf " --central_storage-image-name -J [Optional] : Specifies the image name for central_storage component.\n" printf " --central_storage-image-tag -Q [Optional] : Specifies the image tag for central_storage component. Default: latest.\n" printf " --authentication-image-repo -V [Optional] : Specifies the repository for authentication component.\n" printf " --authentication-image-name -L [Optional] : Specifies the image name for authentication component.\n" printf " --authentication-image-tag -W [Optional] : Specifies the image tag for authentication component. Default: latest.\n" printf " --force -f [Optional] : Force initialization even if resources already exist.\n\n" printf "Global Arguments\n" printf " --help -h : Show this help message and exit.\n\n" printf "Examples\n" printf " Initialize DevBox with Linux OS and ARM64 architecture:\n" printf " devbox init --os linux --arch arm64 --freeleaps-username alice --freeleaps-password secret\n" printf " Initialize with custom container settings:\n" printf " devbox init --devbox-container-name custom-devbox --devbox-container-port 22222 --freeleaps-username alice --freeleaps-password secret\n" else printf "devbox init - Initialize the local development environment based on DevBox container.\n\n" fi } # :command.usage devbox_deinit_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox deinit : De-initialize the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --working-home -w [Optional] : Specifies the working home of DevBox CLI. Default: %s/.devbox\n" "$HOME" printf " --clear-logs -l [Optional] : Specifies whether to clear log files. Default: true\n" printf " --clear-repo -r [Optional] : Specifies whether to delete the source repository. Default: false\n\n" printf "Global Arguments\n" printf " --help, -h : Show this help message and exit.\n\n" printf "Examples\n" printf " De-initialize the local development environment.\n" printf " devbox deinit\n" printf " De-initialize with custom working home and options.\n" printf " devbox deinit --working-home=/tmp/devbox --clear-logs=false --clear-repo=true\n" else printf "devbox deinit - De-initialize the local development environment based on DevBox container.\n\n" fi } # :command.usage devbox_start_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox start : Start the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --component COMPONENT [Optional] : Specifies the name of the component to start (e.g., mongodb, rabbitmq, backend, frontend, devsvc, content, central_storage, authentication).\n\n" printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint to start in the DevBox container.\n\n" printf "Global Arguments\n" printf " --help, -h : Show this help message and exit.\n\n" printf "Examples\n" printf " Start all components:\n" printf " devbox start\n" printf " Start a specific component (e.g., backend):\n" printf " devbox start --component=backend\n" else printf "devbox start - Start the local development environment based on DevBox container.\n\n" fi printf "Alias: s\n" echo } # :command.usage devbox_stop_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox stop : Stop the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --component -c [Optional] : Specifies the name of the component to stop (e.g., mongodb, rabbitmq, devbox, devsvc, content, central_storage, authentication).\n\n" printf "Global Arguments\n" printf " --help -h : Show this help message and exit.\n\n" printf "Examples\n" printf " Stop all components:\n" printf " devbox stop\n\n" printf " Stop a specific component (e.g., backend):\n" printf " devbox stop --component=backend\n" else printf "devbox stop - Stop the local development environment based on DevBox container.\n" fi echo } # :command.usage devbox_status_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox status : Display the status of the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --component -c [Optional] : Specifies the component to show status (e.g., devbox, devsvc, etc.).\n\n" printf "Global Arguments\n" printf " --help -h : Show this help message and exit.\n\n" printf "Examples\n" printf " Display status for all components:\n" printf " devbox status\n\n" printf " Display status for a specific component:\n" printf " devbox status --component=backend\n" else printf "devbox status - Display the status of the local development environment based on DevBox container.\n" fi echo } # :command.usage devbox_restart_usage() { if [[ -n $long_usage ]]; then printf "Command\n" printf " devbox restart : Restart the local development environment based on DevBox container.\n\n" printf "Arguments\n" printf " --component -c [Optional] : Specifies the component to restart (e.g., backend, frontend, etc.).\n" printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint to restart in the DevBox container.\n" printf " --force -f : Force the restart operation without prompt.\n\n" printf "Global Arguments\n" printf " --help -h : Show this help message and exit.\n" printf "Examples\n" printf " Restart all components:\n" printf " devbox restart\n\n" printf " Restart a specific component (e.g., backend):\n" printf " devbox restart --component=backend\n" else printf "devbox restart - Restart the local development environment based on DevBox container.\n\n" fi printf "Alias: r\n" echo } # :command.normalize_input # :command.normalize_input_function normalize_input() { local arg passthru flags passthru=false while [[ $# -gt 0 ]]; do arg="$1" if [[ $passthru == true ]]; then input+=("$arg") elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then input+=("${BASH_REMATCH[1]}") input+=("${BASH_REMATCH[2]}") elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then input+=("${BASH_REMATCH[1]}") input+=("${BASH_REMATCH[2]}") elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then flags="${BASH_REMATCH[1]}" for ((i = 0; i < ${#flags}; i++)); do input+=("-${flags:i:1}") done elif [[ "$arg" == "--" ]]; then passthru=true input+=("$arg") else input+=("$arg") fi shift done } # :command.inspect_args inspect_args() { # Check and output the simulated args associative array (using args_keys and args_values) if [ ${#args_keys[@]} -gt 0 ]; then # 利用 printf 和 sort 对键进行排序 sorted_keys=$(printf "%s\n" "${args_keys[@]}" | sort) echo "args:" for key in $sorted_keys; do value="" # Find the value based on the key for i in `seq 0 $((${#args_keys[@]} - 1))`; do if [ "${args_keys[$i]}" = "$key" ]; then value="${args_values[$i]}" break fi done done else echo "args: none" fi # Check and output the simulated deps associative array (using deps_keys and deps_values) if [ ${#deps_keys[@]} -gt 0 ]; then sorted_keys=$(printf "%s\n" "${deps_keys[@]}" | sort) echo echo "deps:" for key in $sorted_keys; do value="" for i in `seq 0 $((${#deps_keys[@]} - 1))`; do if [ "${deps_keys[$i]}" = "$key" ]; then value="${deps_values[$i]}" break fi done echo "- \$deps[$key] = $value" done fi # Check and output the simulated env_vars associative array (using env_var_names) if [ ${#env_var_names[@]} -gt 0 ]; then sorted_names=$(printf "%s\n" "${env_var_names[@]}" | sort) echo echo "environment variables:" for name in $sorted_names; do # Look up the value based on the name echo "- \$${name} = ${!name:-}" done fi } install_docker() { echo "[INFO] Checking Docker installation..." # Check if Docker CLI is installed if ! command -v docker >/dev/null 2>&1; then echo "[ERROR] Docker CLI is not installed." return 1 fi echo "[INFO] Docker CLI is installed. Checking daemon..." # Check if Docker daemon is running if docker info >/dev/null 2>&1; then echo "[OK] Docker daemon is running." return 0 fi # Check if running on WSL if grep -qi microsoft /proc/version; then echo "[INFO] Detected WSL environment. Skipping service startup." if [ -S /var/run/docker.sock ]; then echo "[OK] Docker socket found (/var/run/docker.sock)." return 0 else echo "[ERROR] Docker socket /var/run/docker.sock not found." echo "[SOLUTION] Please start Docker Desktop on Windows and enable WSL integration, then mount /var/run/docker.sock into the container." return 1 fi fi # Check if running on macOS if [[ "$OSTYPE" == "linux-gnu"* ]]; then echo "[INFO] Running on Linux. Attempting to start Docker service..." if command -v systemctl >/dev/null 2>&1; then echo "[INFO] Starting Docker with systemctl..." sudo systemctl start docker sleep 2 if systemctl is-active --quiet docker; then echo "[OK] Docker service started successfully via systemctl." return 0 else echo "[ERROR] Failed to start Docker using systemctl." return 1 fi elif command -v service >/dev/null 2>&1; then echo "[INFO] systemctl not found, trying to start Docker using service..." sudo service docker start sleep 2 if docker info >/dev/null 2>&1; then echo "[OK] Docker service started successfully via service command." return 0 else echo "[ERROR] Failed to start Docker using service command." return 1 fi else echo "[ERROR] Neither systemctl nor service command found. Please start Docker manually." return 1 fi fi return 1 } check_docker_running() { echo "==> Checking if Docker service is running..." # if Docker CLI is installed and Docker daemon is running if docker info >/dev/null 2>&1; then echo "==> Docker is running." return 0 fi # if running on WSL, check for Docker socket if grep -qi microsoft /proc/version; then echo "[INFO] Detected WSL environment. Verifying /var/run/docker.sock..." if [ -S /var/run/docker.sock ]; then echo "==> Docker socket found. Docker should be available via Docker Desktop." return 0 else echo "[ERROR] Docker socket not found in WSL environment." return 1 fi fi echo "==> Docker is not running. Attempting to start it..." # Start Docker service using systemctl or service command if command -v systemctl &>/dev/null; then if systemctl list-units --type=service | grep -q "docker.service"; then echo "==> Starting Docker with systemctl..." sudo systemctl start docker && echo "==> Docker started successfully." && return 0 fi fi if command -v service &>/dev/null; then if service --status-all | grep -q "docker"; then echo "==> Starting Docker with service..." sudo service docker start && echo "==> Docker started successfully." && return 0 fi fi if command -v snap &>/dev/null && snap list | grep -q "docker"; then echo "==> Starting Docker with snap..." sudo snap start docker && echo "==> Docker started successfully." && return 0 fi echo "ERROR: Unable to start Docker automatically. Please start it manually." return 1 } # Define the local components and their corresponding ports local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "authentication") local_components_ports_values=("8007" "8003" "8013" "8005" "8004") # Get the port number for a local component get_port() { local comp="$1" local port="" for i in "${!local_components_ports_keys[@]}"; do if [ "${local_components_ports_keys[i]}" = "$comp" ]; then port="${local_components_ports_values[i]}" break fi done echo "$port" } check_jq() { # 从参数中获取 OS 和 ARCH,默认值分别为 auto local target_os target_arch target_os="$(get_arg '--os' 'auto')" target_arch="$(get_arg '--arch' 'auto')" if ! command -v jq >/dev/null 2>&1; then echo "[INFO] 'jq' is not installed. Installing jq..." case "$target_os" in darwin) if command -v brew >/dev/null 2>&1; then brew install jq else echo "[ERROR] brew not found. Please install jq manually." exit 1 fi ;; linux | wsl2 | auto) if command -v apt-get >/dev/null 2>&1; then sudo apt-get update && sudo apt-get install -y jq elif command -v yum >/dev/null 2>&1; then sudo yum install -y epel-release && sudo yum install -y jq else echo "[ERROR] apt-get or yum not found. Please install jq manually." exit 1 fi ;; *) echo "[ERROR] Unsupported OS: $target_os" exit 1 ;; esac else echo "[INFO] 'jq' is already installed." fi } # :command.command_functions # :command.function devbox_init_command() { #!/usr/bin/env bash echo "==> [INIT] Starting DevBox environment initialization..." echo # ------------------------------------------------------------------- # 1. Get parameters from command line arguments # ------------------------------------------------------------------- local OS="$args_os" # --os local ARCH="$args_arch" # --arch local DEVBOX_NAME="$args_devbox_container_name" # --devbox-container-name local DEVBOX_PORT="$args_devbox_container_port" # --devbox-container-port local DEVBOX_FRONTEND_PORT="$args_devbox_frontend_port" # --devbox-frontend-port local DEVBOX_BACKEND_PORT="$args_devbox_backend_port" # --devbox-backend-port local DEVBOX_REPO="$args_devbox_image_repo" # --devbox-image-repo local DEVBOX_IMAGE="$args_devbox_image_name" # --devbox-image-name local DEVBOX_TAG="$args_devbox_image_tag" # --devbox-image-tag local WORKING_HOME="${args_working_home:-${WORKING_HOME:-${HOME}/.devbox}}" local FREELEAPS_USERNAME="$args_freeleaps_username" # --freeleaps-username local FREELEAPS_PASSWORD="$args_freeleaps_password" # --freeleaps-password local USE_LOCAL_COMPONENT="$args_use_local_component" # --use-local-component local DEVSVC_REPO="$args_devsvc_image_repo" # --devsvc-image-repo local DEVSVC_IMAGE="$args_devsvc_image_image" # --devsvc-image-image local DEVSVC_TAG="$args_devsvc_image_tag" # --devsvc-image-tag local CONTENT_REPO="$args_content_image_repo" # --content-image-repo local CONTENT_IMAGE="$args_content_image_image" # --content-image-image local CONTENT_TAG="$args_content_image_tag" # --content-image-tag local CENTRAL_STORAGE_REPO="$args_central_storage_image_repo" # --central_storage-image-repo local CENTRAL_STORAGE_IMAGE="$args_central_storage_image_image" # --central_storage-image-image local CENTRAL_STORAGE_TAG="$args_central_storage_image_tag" # --central_storage-image-tag local AUTHENTICATION_REPO="$args_authentication_image_repo" # --authentication-image-repo local AUTHENTICATION_IMAGE="$args_authentication_image_image" # --authentication-image-image local AUTHENTICATION_TAG="$args_authentication_image_tag" # --authentication-image-tag local NOTIFICATION_REPO="$args_notification_image_repo" # --notification-image-repo local NOTIFICATION_IMAGE="$args_notification_image_image" # --notification-image-image local NOTIFICATION_TAG="$args_notification_image_tag" # --notification-image-tag local CUSTOM_GIT_REPO="$args_custom_git_repo" # --custom-git-repo # --force flag to overwrite existing resources local FORCE_INIT="${args_force}" local OS="$(get_arg '--os')" local ARCH="$(get_arg '--arch')" local DEVBOX_NAME="$(get_arg '--devbox-container-name')" local DEVBOX_PORT="$(get_arg '--devbox-container-port')" local DEVBOX_FRONTEND_PORT="$(get_arg '--devbox-frontend-port')" local DEVBOX_BACKEND_PORT="$(get_arg '--devbox-backend-port')" local DEVBOX_REPO="$(get_arg '--devbox-image-repo')" local DEVBOX_IMAGE="$(get_arg '--devbox-image-name')" local DEVBOX_TAG="$(get_arg '--devbox-image-tag')" local WORKING_HOME="$(get_arg '--working-home' "${WORKING_HOME:-${HOME}/.devbox}")" local FREELEAPS_USERNAME="$(get_arg '--freeleaps-username')" local FREELEAPS_PASSWORD="$(get_arg '--freeleaps-password')" local USE_LOCAL_COMPONENT="$(get_arg '--use-local-component')" local DEVSVC_REPO="$(get_arg '--devsvc-image-repo')" local DEVSVC_IMAGE="$(get_arg '--devsvc-image-name')" local DEVSVC_TAG="$(get_arg '--devsvc-image-tag')" local CONTENT_REPO="$(get_arg '--content-image-repo')" local CONTENT_IMAGE="$(get_arg '--content-image-name')" local CONTENT_TAG="$(get_arg '--content-image-tag')" local CENTRAL_STORAGE_REPO="$(get_arg '--central_storage-image-repo')" local CENTRAL_STORAGE_IMAGE="$(get_arg '--central_storage-image-name')" local CENTRAL_STORAGE_TAG="$(get_arg '--central_storage-image-tag')" local AUTHENTICATION_REPO="$(get_arg '--authentication-image-repo')" local AUTHENTICATION_IMAGE="$(get_arg '--authentication-image-name')" local AUTHENTICATION_TAG="$(get_arg '--authentication-image-tag')" local NOTIFICATION_REPO="$(get_arg '--notification-image-repo')" local NOTIFICATION_IMAGE="$(get_arg '--notification-image-name')" local NOTIFICATION_TAG="$(get_arg '--notification-image-tag')" local CUSTOM_GIT_REPO="$(get_arg '--custom-git-repo')" local FORCE_INIT="$(get_arg '--force')" local is_pull_all_components=true local components=("devsvc" "notification" "content" "central_storage" "authentication") local start_components=() # Check if using local components USE_LOCAL_COMPONENT_VAL=false if [[ "$(lower "$USE_LOCAL_COMPONENT")" == "true" ]]; then USE_LOCAL_COMPONENT_VAL=true fi # if use online components, check if any component image repo is specified if [[ $USE_LOCAL_COMPONENT_VAL == false ]]; then is_pull_all_components=false fi echo "==> Checking parameters..." for component in "${components[@]}"; do if [[ -n "$(get_arg "--${component}-image-repo")" ]]; then is_pull_all_components=false start_components+=("${component}") fi # Check ARCH match default component tag value and justify the default Image tag value if [[ "$ARCH" == "amd64" && "$component" == "devsvc" ]]; then DEVSVC_TAG="latest-linux-amd64" elif [[ "$ARCH" == "arm64" && "$component" == "devsvc" ]]; then DEVSVC_TAG="latest-linux-arm64" fi if [[ "$ARCH" == "amd64" && "$component" == "content" ]]; then CONTENT_TAG="latest-linux-amd64" elif [[ "$ARCH" == "arm64" && "$component" == "content" ]]; then CONTENT_TAG="latest-linux-arm64" fi if [[ "$ARCH" == "amd64" && "$component" == "central_storage" ]]; then CENTRAL_STORAGE_TAG="latest-linux-amd64" elif [[ "$ARCH" == "arm64" && "$component" == "central_storage" ]]; then CENTRAL_STORAGE_TAG="latest-linux-arm64" fi if [[ "$ARCH" == "amd64" && "$component" == "authentication" ]]; then AUTHENTICATION_TAG="latest-linux-amd64" elif [[ "$ARCH" == "arm64" && "$component" == "authentication" ]]; then AUTHENTICATION_TAG="latest-linux-arm64" fi if [[ "$ARCH" == "amd64" && "$component" == "notification" ]]; then NOTIFICATION_TAG="latest-linux-amd64" elif [[ "$ARCH" == "arm64" && "$component" == "notification" ]]; then NOTIFICATION_TAG="latest-linux-arm64" fi done # If is_pull_all_components is true, then pull all components if [[ "$is_pull_all_components" == true ]]; then start_components=("${components[@]}") fi echo " ===================================================== " echo "Parameters:" echo " OS = $OS" echo " ARCH = $ARCH" echo " DEVBOX_NAME = $DEVBOX_NAME" echo " DEVBOX_PORT = $DEVBOX_PORT" echo " DEVBOX_FRONTEND_PORT = $DEVBOX_FRONTEND_PORT" echo " DEVBOX_BACKEND_PORT = $DEVBOX_BACKEND_PORT" echo " DEVBOX_REPO = $DEVBOX_REPO" echo " DEVBOX_IMAGE = $DEVBOX_IMAGE" echo " DEVBOX_TAG = $DEVBOX_TAG" echo " WORKING_HOME = $WORKING_HOME" echo " FREELEAPS_USERNAME= $FREELEAPS_USERNAME" echo " (FREELEAPS_PASSWORD is hidden for security)" echo " USE_LOCAL_COMPONENT= $USE_LOCAL_COMPONENT" echo " DEVSVC_REPO = $DEVSVC_REPO" echo " DEVSVC_IMAGE = $DEVSVC_IMAGE" echo " DEVSVC_TAG = $DEVSVC_TAG" echo " CONTENT_REPO = $CONTENT_REPO" echo " CONTENT_IMAGE = $CONTENT_IMAGE" echo " CONTENT_TAG = $CONTENT_TAG" echo " CENTRAL_STORAGE_REPO = $CENTRAL_STORAGE_REPO" echo " CENTRAL_STORAGE_IMAGE= $CENTRAL_STORAGE_IMAGE" echo " CENTRAL_STORAGE_TAG = $CENTRAL_STORAGE_TAG" echo " AUTHENTICATION_REPO = $AUTHENTICATION_REPO" echo " AUTHENTICATION_IMAGE= $AUTHENTICATION_IMAGE" echo " AUTHENTICATION_TAG = $AUTHENTICATION_TAG" echo " NOTIFICATION_REPO = $NOTIFICATION_REPO" echo " NOTIFICATION_IMAGE= $NOTIFICATION_IMAGE" echo " NOTIFICATION_TAG = $NOTIFICATION_TAG" echo " FORCE_INIT = $FORCE_INIT" echo # ------------------------------------------------------------------- # 2. Check OS/ARCH support # (if using auto, detect current system, here just show simple check) # ------------------------------------------------------------------- if [[ "$OS" != "auto" && "$OS" != "linux" && "$OS" != "darwin" && "$OS" != "wsl2" ]]; then echo "ERROR: Unsupported OS: $OS" exit 1 fi if [[ "$ARCH" != "auto" && "$ARCH" != "amd64" && "$ARCH" != "arm64" ]]; then echo "ERROR: Unsupported architecture: $ARCH" exit 1 fi # Check ARCH match current device if [[ "$ARCH" == "auto" ]]; then ARCH="$(uname -m)" if [[ "$ARCH" == "x86_64" ]]; then ARCH="amd64" elif [[ "$ARCH" == "aarch64" ]]; then ARCH="arm64" else echo "ERROR: Unsupported architecture: $ARCH" exit 1 fi fi # Default arch tag value if Arch is amd64 then latest-linux-amd64 else latest-linux-arm64 local arch_tag="latest-linux-${ARCH}" # ------------------------------------------------------------------- # 3. Check environment requirements # ------------------------------------------------------------------- # 3.1 Docker Check if ! command -v docker &>/dev/null; then echo "ERROR: docker is not installed or not in PATH." exit 1 fi # 3.2 Check disk space local free_space_kb free_space_kb="$(df -Pk "$HOME" | awk 'END{print $4}')" # 若无法获取或小于 10GB (10485760 KB),报错 if [[ -z "$free_space_kb" || $free_space_kb -lt 10485760 ]]; then echo "ERROR: Insufficient disk space (need >10GB)." exit 1 fi # 3.3 WORKING_HOME Check if ! mkdir -p "$WORKING_HOME" 2>/dev/null; then echo "ERROR: Can't create or write to WORKING_HOME: $WORKING_HOME" exit 1 fi # 3.4 Network to docker.com(sample:ping docker.com) if ! ping -c 1 docker.com &>/dev/null; then echo "ERROR: Network unreachable." exit 1 fi if [[ -f "$WORKING_HOME/.devbox-instance" && -z "$FORCE_INIT" ]]; then # Echo all start_components if [[ "${#start_components[@]}" -gt 0 ]]; then for component in "${start_components[@]}"; do if [[ -f "$WORKING_HOME/.${component}-instance" ]]; then echo "ERROR: Container named $component already exists. Use --force to remove it." exit 1 fi done else echo "ERROR: Container named $DEVBOX_NAME already exists. Use --force to remove it." exit 1 fi fi # ------------------------------------------------------------------- # 5.install docker and check docker running # ------------------------------------------------------------------- if ! install_docker; then echo "ERROR: Failed to install Docker or Docker service is not running." exit 1 fi if ! check_docker_running; then echo "ERROR: Docker service is not running." exit 1 fi # ------------------------------------------------------------------- # 5.1 pull and start DevBox container # ------------------------------------------------------------------- local devbox_full_image="${DEVBOX_REPO}/${DEVBOX_IMAGE}:${DEVBOX_TAG}" echo "==> Pulling DevBox image: $devbox_full_image" if ! docker pull "$devbox_full_image"; then echo "ERROR: Failed to pull DevBox image: $devbox_full_image" exit 1 fi # If container with same name exists, remove it if docker ps -a --format '{{.Names}}' | grep -q "^${DEVBOX_NAME}\$"; then if [[ -n "$FORCE_INIT" ]]; then echo "==> Removing existing container named $DEVBOX_NAME ..." docker stop "$DEVBOX_NAME" &>/dev/null || true docker rm "$DEVBOX_NAME" &>/dev/null || true # Remove .devbox-instance file rm -f "$WORKING_HOME/.devbox-instance" # Remove .backend.pid .frontend.pid rm -f "$WORKING_HOME/.backend.pid" rm -f "$WORKING_HOME/.frontend.pid" else echo "ERROR: Container named $DEVBOX_NAME already exists. Use --force to remove it." exit 1 fi fi # Create Docker network for DevBox container. TODO: if the network need to be configured in the docker-compose file add some logic to load it from the file DEVBOX_FREELEAPS2_NETWORK="devbox_freeleaps2-network" echo '==> [INIT] Starting DevBox environment initialization...' # Check if docker network create devbox_freeleaps2-network if ! docker network ls | grep -q "$DEVBOX_FREELEAPS2_NETWORK"; then echo "==> Creating Docker network: $DEVBOX_FREELEAPS2_NETWORK" docker network create "$DEVBOX_FREELEAPS2_NETWORK" else echo "==> Docker network devbox_freeleaps2-network already exists." fi echo '==> [INIT] Starting DevBox container...' # Create and start DevBox container local container_id container_id="$( docker run -d \ --name "$DEVBOX_NAME" \ -p "${DEVBOX_PORT}:22" \ -p "${DEVBOX_FRONTEND_PORT}:5173" \ -p "${DEVBOX_BACKEND_PORT}:8002" \ -v "$WORKING_HOME:/home/.devbox" \ -v /var/run/docker.sock:/var/run/docker.sock \ --network "$DEVBOX_FREELEAPS2_NETWORK" \ "$devbox_full_image" 2>/dev/null )" if [[ -z "$container_id" ]]; then echo "ERROR: Failed to create DevBox container." exit 1 fi # record container id, DEVBOX_FRONTEND_PORT, DEVBOX_BACKEND_PORT echo "$container_id" > "$WORKING_HOME/.devbox-instance" echo "$DEVBOX_FRONTEND_PORT" > "$WORKING_HOME/.devbox-frontend-port" echo "$DEVBOX_BACKEND_PORT" > "$WORKING_HOME/.devbox-backend-port" # ------------------------------------------------------------------- # 6. linbwang: pull and start other components # ------------------------------------------------------------------- echo "==> [INIT] Starting Freeleaps services... Use Local component $USE_LOCAL_COMPONENT_VAL" export ARCH="$ARCH" export WORKING_HOME="$WORKING_HOME" # Check if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then echo ' ===> Using local components for Freeleaps services.' export DEVSVC_IMAGE_TAG="$DEVSVC_TAG" export CONTENT_IMAGE_TAG="$CONTENT_TAG" export CENTRAL_STORAGE_IMAGE_TAG="$CENTRAL_STORAGE_TAG" export AUTHENTICATION_IMAGE_TAG="$AUTHENTICATION_TAG" export NOTIFICATION_IMAGE_TAG="$NOTIFICATION_TAG" # Check if gitea_data_backup.tar.gz exists at current script directory, if not exit if [[ ! -f "gitea_data_backup.tar.gz" ]]; then echo "ERROR: gitea_data_backup.tar.gz not found. Please make sure it exists in the current directory." exit 1 fi # Sudo force sudo tar -xzvf gitea_data_backup.tar.gz sudo tar -xzvf gitea_data_backup.tar.gz # Check if data/git, data/gitea, data/ssh directories exist after extracting gitea_data_backup.tar.gz if [[ ! -d "data/git" || ! -d "data/gitea" || ! -d "data/ssh" ]]; then echo "ERROR: Failed to extract gitea data backup." exit 1 fi # Check if jq is installed, if not install it check_jq # Get Gitea data volume mount point GITEA_DATA=$(docker volume inspect devbox_freeleaps2-gitea-data | jq -r '.[0].Mountpoint') echo "Gitea data volume mount point: $GITEA_DATA" echo "==> Starting Gitea, MongoDB, RabbitMQ containers..." # Start local components by docker compose file and start up specified services. docker compose file is in the same directory as the script (docker-compose.dev.arm64.new.yaml) docker-compose -f docker-compose.dev.arm64.new.yaml up -d mongodb rabbitmq gitea sleep 5 # start component service from start_components array docker-compose -f docker-compose.dev.arm64.new.yaml up -d "${start_components[@]}" gitea_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-gitea$" --format "{{.ID}}") echo "$gitea_container_id" > "$WORKING_HOME/.gitea-instance" mongo_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-mongodb$" --format "{{.ID}}") echo "$mongo_container_id" > "$WORKING_HOME/.mongodb-instance" rabbitmq_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-rabbitmq$" --format "{{.ID}}") echo "$rabbitmq_container_id" > "$WORKING_HOME/.rabbitmq-instance" # Get all components container ids and save to .component-instance file for component in "${start_components[@]}"; do tmp_container_id=$(docker ps --no-trunc -a --filter "name=^$component$" --format "{{.ID}}") echo "$tmp_container_id" > "$WORKING_HOME/.${component}-instance" done echo "${component} container created: $component_container_id" # Check if devbox_freeleaps2-gitea-data exists, if not create a docker volume for gitea data, if exists then remove it and create a new one if docker volume ls | grep -q "devbox_freeleaps2-gitea-data"; then docker volume rm devbox_freeleaps2-gitea-data fi docker volume create devbox_freeleaps2-gitea-data || { echo "ERROR: Failed to create volume devbox_freeleaps2-gitea-data." exit 1 } # Check volume created successfully if ! docker volume ls | grep -q "devbox_freeleaps2-gitea-data"; then echo "ERROR: Failed to create volume devbox_freeleaps2-gitea-data." exit 1 fi if [[ -d "${GITEA_DATA}/gitea" ]]; then echo "Gitea data exist, skipping..." else echo "Gitea data not exist, copying..." sudo rm -rf ${GITEA_DATA}/git sudo rm -rf ${GITEA_DATA}/gitea sudo rm -rf ${GITEA_DATA}/ssh sudo mv data/git ${GITEA_DATA}/ sudo mv data/gitea ${GITEA_DATA}/ sudo mv data/ssh ${GITEA_DATA}/ sudo chown -R freedev:freedev ${GITEA_DATA} echo "Gitea data copying is done" # Check if gitea data copied successfully if [[ ! -d "${GITEA_DATA}/gitea" ]]; then echo "ERROR: Failed to copy gitea data." exit 1 fi # restart gitea container docker-compose -f docker-compose.dev.arm64.new.yaml restart gitea fi else echo '============================================' echo ' ===> Using online components for Freeleaps services.' echo '============================================' # Start Gitea, MongoDB, RabbitMQ containers docker-compose -f docker-compose.dev.arm64.new.yaml up -d mongodb rabbitmq echo "===> start components is $start_components" # Save MongoDB and RabbitMQ container ids to .mongodb-instance and .rabbitmq-instance mongo_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-mongodb\$") echo "$mongo_container_id" > "$WORKING_HOME/.mongodb-instance" rabbitmq_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-rabbitmq\$") echo "$rabbitmq_container_id" > "$WORKING_HOME/.rabbitmq-instance" fi # Check all components are started for component in "${start_components[@]}"; do if [[ -z "$(docker ps -a --format '{{.Names}}' | grep "^$component\$")" ]]; then echo "ERROR: Failed to start $component container." exit 1 fi done # Save $USE_LOCAL_COMPONENT false/true to $WORKING_HOME/.use-local-component echo "$USE_LOCAL_COMPONENT" > "$WORKING_HOME/.use-local-component" pushd $WORKING_HOME IS_START_FRONTEND=false # Make a user input (Y/N) to continue pull freeleaps.com code and start if N then exit read -p "Do you want to continue to pull freeleaps.com code and start the services? (Y/N): " user_input if [[ "$user_input" == "N" || "$user_input" == "n" ]]; then # Echo as init job completed and exit echo echo "===========================================================" echo "DevBox init completed successfully!" echo "DevBox Environment Details:" echo " DevBox container name: $DEVBOX_NAME" echo " DevBox container ID: $WORKING_HOME/.devbox-instance" echo "===========================================================" echo exit 0 fi IS_START_FRONTEND=true # Check if username and password are set if [[ -z "$FREELEAPS_USERNAME" || -z "$FREELEAPS_PASSWORD" ]]; then echo "Warining: Username and password are required to pull freeleaps.com code." echo "==> [INIT] DevBox environment initialization completed." exit 1 fi # Test if the user can access the freeleaps.com repository echo "==> Testing access to freeleaps.com repository..." if ! git ls-remote "https://$FREELEAPS_USERNAME:$FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" &>/dev/null; then echo "ERROR: Failed to access freeleaps.com repository. Please check your username and password." echo "==> [INIT] DevBox environment initialization completed successfully, but access to the freeleaps.com repository failed." exit 1 fi FRONTEND_GIT_URL="https://$FREELEAPS_USERNAME:$FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" # Check if freeleaps2-frontend exists, if not git clone it if [ ! -d $WORKING_HOME/freeleaps ]; then echo "Git cloning freeleaps.com:3443/products/freeleaps.git" git clone --depth 5 $FRONTEND_GIT_URL else pushd $WORKING_HOME/freeleaps # Check $WORKING_HOME/freeleaps exists and it is a git repository, if not git clone it if ! git rev-parse --is-inside-work-tree &>/dev/null; then echo "Git cloning freeleaps.com:3443/products/freeleaps.git" git clone --depth 5 $FRONTEND_GIT_URL else echo "Git pulling freeleaps.com:3443/products/freeleaps.git" git pull fi fi # Run banckend service and frontend service in the container docker exec -i "$DEVBOX_NAME" bash < Using local components" # Local components for Freeleaps services (devsvc, notification, content, central_storage, authentication) cat << 'EOFinner' > /home/.devbox/freeleaps/apps/.env # Online endpoint info export MONGODB_NAME=freeleaps2 export MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ export MONGODB_PORT=27017 export BLOB_STORE_CONNECTION_STR="DefaultEndpointsProtocol=https;AccountName=freeleaps1static;AccountKey=SIk7S3RviJxl1XhGiDZKA3cvzfxNrSbsBMfJ3EbKTsKPeMwhy8FTLpJliRLzQVE6uaSX8giDYw2h+ASt5MmHxQ==;EndpointSuffix=core.windows.net" export RABBITMQ_HOSTNAME=freeleaps2 export RABBITMQ_HOST=freeleaps2-rabbitmq export RABBITMQ_PORT=5672 export FREELEAPS_ENV=dev export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd export STRIPE_WEBHOOK_SECRET=whsec_S6ZWjSAdR5Cpsn2USH6ZRBqbdBIENjTC export STRIPE_ACCOUNT_WEBHOOK_SECRET=whsec_PgPnkWGhEUiQfnV8aIb5Wmruz7XETJLm export SITE_URL_ROOT=http://localhost export FREELEAPS_DEVSVC_ENDPOINT=http://devsvc:8007/api/devsvc/ export FREELEAPS_CONTENT_ENDPOINT=http://content:8013/api/content/ export FREELEAPS_NOTIFICATION_ENDPOINT=http://notification:8003/api/notification/ export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://central_storage:8005/api/central_storage/ export FREELEAPS_AUTHENTICATION_ENDPOINT=http://authentication:8004/api/auth/ export FREELEAPS_AILAB_ENDPOINT=https://localhost:8009/api/ export KAFKA_SERVER_URL='' export JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b export EMAIL_FROM=freeleaps@freeleaps.com EOFinner else echo "==> Using online components" cat << 'EOFinner' > /home/.devbox/freeleaps/apps/.env # Online endpoint info export MONGODB_NAME=freeleaps2 export MONGODB_PORT=27017 export MONGODB_URI='mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/' export RABBITMQ_HOSTNAME=freeleaps2 export RABBITMQ_HOST=52.149.35.244 export RABBITMQ_PORT=5672 export FREELEAPS_ENV=dev export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd export STRIPE_WEBHOOK_SECRET=whsec_S6ZWjSAdR5Cpsn2USH6ZRBqbdBIENjTC export STRIPE_ACCOUNT_WEBHOOK_SECRET=whsec_PgPnkWGhEUiQfnV8aIb5Wmruz7XETJLm export SITE_URL_ROOT=http://localhost/ export FREELEAPS_DEVSVC_ENDPOINT=http://52.149.3.85:8007/api/devsvc/ export FREELEAPS_CHAT_ENDPOINT=https://freeleaps-alpha.com/api/chat/ export FREELEAPS_CONTENT_ENDPOINT=http://52.149.35.244:8013/api/content/ export FREELEAPS_NOTIFICATION_ENDPOINT=http://52.149.35.244:8003/api/notification/ export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://52.149.35.244:8005/api/central_storage/ export FREELEAPS_AUTHENTICATION_ENDPOINT=http://52.149.35.244:8004/api/auth/ export FREELEAPS_AILAB_ENDPOINT=https://as010-w2-re-vm.mathmast.com:8009/api/ export KAFKA_SERVER_URL='' export EMAIL_FROM=freeleaps@freeleaps.com export JWT_SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0 EOFinner fi # Effect the environment variables in the current shell source /home/.devbox/freeleaps/apps/.env # Ensure /home/.devbox/logs exists mkdir -p /home/.devbox/logs # Start WebAPI service echo "Starting WebAPI service..." pushd /home/.devbox/freeleaps/apps cp /home/.devbox/freeleaps/backend_env.sh /home/.devbox/freeleaps/apps/backend_env.sh # 5. Istall python3.10 and venv module echo "5. Istall python3.10 and venv module" sudo apt update sudo apt install python3.10 python3.10-venv -y # make sore python3.10 is installed if ! command -v python3.10 &>/dev/null; then echo "ERROR: Python3.10 is not installed." exit 1 fi # Upgrade pip and install virtualenv echo "7. Upgrade pip and install virtualenv" python3.10 -m ensurepip --upgrade python3.10 -m pip install --upgrade pip # 8. Create and activate a virtual environment echo "8. Create and activate a virtual environment" python3.10 -m venv venv_t sleep 5 # CHeck if the virtual environment is created if [ ! -f "venv_t/bin/activate" ]; then echo "ERROR: The virtual environment cannot be created" exit 1 fi echo '============================================' echo ' Start to activate virtual environment' echo '============================================' source venv_t/bin/activate source /home/.devbox/freeleaps/apps/.env # Verify the virtual environment is activated if [[ "\$VIRTUAL_ENV" != "" ]]; then echo "Virtual environment activate: \$VIRTUAL_ENV" else echo "ERROR: The virtual environment cannot be startup \$VIRTUAL_ENV" exit 1 fi echo '============================================' echo ' Install requirements' echo '============================================' pip install -r /home/.devbox/freeleaps/apps/requirements.txt echo '============================================' echo 'Start to run start_webapi.sh' echo '============================================' ./start_webapi.sh > /home/.devbox/logs/backend.logs 2>&1 & BACKEND_PID=\$! # Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. echo "\$BACKEND_PID" > /home/.devbox/.backend.pid echo '============================================' echo 'Check if the WebAPI service started successfully' echo '============================================' sleep 30 # 30 attempts, 5 seconds each, total wait time 2.5 minutes MAX_ATTEMPTS=30 ATTEMPT=0 echo "Waiting for WebAPI service to become healthy..." while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$DEVBOX_BACKEND_PORT/docs") # Check HTTP Code 200 if [ "\$HTTP_CODE" -eq 200 ]; then echo "Backend Swagger UI is available at \$URL (HTTP \$HTTP_CODE)" break else echo "Waiting for Swagger UI to become available... Attempt \$((ATTEMPT+1))" ATTEMPT=\$((ATTEMPT+1)) sleep 5 # Wait 5 seconds fi done if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then echo "ERROR: WebAPI failed to start after \$MAX_ATTEMPTS attempts" exit 1 fi echo '============================================' echo ' Start frontend service locally' echo '============================================' pushd /home/.devbox/freeleaps/frontend # start the frontend service export VITE_API_URL='http://127.0.0.1:8002' export VITE_WEBSOCKET_URL='http://127.0.0.1:8002' if [[ \$USE_LOCAL_COMPONENT_VAL == true ]]; then export VITE_PROXY_WEBSOCKET_CHAT_URL='ws://localhost:8012' export VITE_PROXY_API_CHAT_URL='http://localhost:8012' else export VITE_PROXY_WEBSOCKET_CHAT_URL='wss://freeleaps-alpha.com' export VITE_PROXY_API_CHAT_URL='https://freeleaps-alpha.com' fi npm update # 1️⃣ Install pnpm globally npm install -g pnpm # 2️⃣ Verify installation pnpm --version # 3️⃣ Clean up old dependencies rm -rf node_modules pnpm-lock.yaml # 4️⃣ Install dependencies (ensuring lockfile updates) pnpm install --no-frozen-lockfile # 5️⃣ Build the project npm run build # 6️⃣ Format the code (Optional) npm run format # Start the frontend service with nohup in order to keep it running after the SSH session is closed. Save the process ID of the frontend service nohup npm run dev > /home/.devbox/logs/frontend.logs 2>&1 & FRONTEND_PID=\$! echo "npm run dev has been started with PID: \$FRONTEND_PID" echo "\$FRONTEND_PID" > /home/.devbox/.frontend.pid echo '============================================' # Wait for the frontend service to start sleep 30 # 30 attempts, 10 seconds each, total wait time 5 minutes MAX_ATTEMPTS=30 ATTEMPT=0 echo "Waiting for Frontend service to start..." while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$DEVBOX_FRONTEND_PORT/") # Check HTTP Code 200 if [ "\$HTTP_CODE" -eq 200 ]; then echo "Frontend is available (HTTP \$HTTP_CODE)" break else echo "Waiting for Frontend to become available... (http://localhost:\$DEVBOX_FRONTEND_PORT), (HTTP \$HTTP_CODE) Attempt \$((ATTEMPT+1))" ATTEMPT=\$((ATTEMPT+1)) sleep 10 fi done if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then echo "ERROR: Frontend failed to start after \$MAX_ATTEMPTS attempts" exit 1 fi echo "Freeleaps services started successfully" EOF # ------------------------------------------------------------------- # 10. Final notification # ------------------------------------------------------------------- echo echo "===========================================================" echo "DevBox init completed successfully!" echo "DevBox Environment Details:" echo "1. Code repository is located at: ${WORKING_HOME}/freeleaps" echo "2. Open up the frontend by visiting: http://localhost:${DEVBOX_FRONTEND_PORT}" echo "3. Log files can be viewed at:" echo " - Backend logs: ${WORKING_HOME}/logs/backend.logs" echo " - Frontend logs: ${WORKING_HOME}/logs/frontend.logs" echo " DevBox container ID: $WORKING_HOME/.devbox-instance" echo " Backend PID: $WORKING_HOME/.backend.pid" echo " Frontend PID: $WORKING_HOME/.frontend.pid" echo "===========================================================" echo } # :command.function devbox_deinit_command() { # src/deinit_command.sh echo "# It contains the implementation for the 'devbox deinit' command." local WORKING_HOME="$(get_arg '--working-home' "${HOME}/.devbox")" local CLEAR_LOGS="$(get_arg '--clear-logs')" local CLEAR_REPO="$(get_arg '--clear-repo')" local FORCE="$(get_arg '--force')" # print the parameters echo "==> Deinitialization parameters:" echo " WORKING_HOME = $WORKING_HOME" echo " CLEAR_LOGS = $CLEAR_LOGS" echo " CLEAR_REPO = $CLEAR_REPO" echo " FORCE = $FORCE" echo "==> Starting DevBox deinitialization..." # Stop and remove DevBox container if [[ -f "$WORKING_HOME/.devbox-instance" ]]; then local container_id container_id=$(cat "$WORKING_HOME/.devbox-instance") echo "==> Stopping and removing DevBox container: $container_id" docker stop "$container_id" &>/dev/null || true docker rm "$container_id" &>/dev/null || true rm -f "$WORKING_HOME/.devbox-instance" # Remove the frontend and backend ports if the file exists rm -f "$WORKING_HOME/.devbox-frontend-port" rm -f "$WORKING_HOME/.devbox-backend-port" # Remove the backend and frontend process IDs rm -f "$WORKING_HOME/.backend.pid" rm -f "$WORKING_HOME/.frontend.pid" fi if [[ -f "$WORKING_HOME/.gitea-instance" ]]; then local gitea_container_id gitea_container_id=$(cat "$WORKING_HOME/.gitea-instance") echo "==> Stopping and removing Gitea container: $gitea_container_id" docker stop "$gitea_container_id" &>/dev/null || true docker rm "$gitea_container_id" &>/dev/null || true rm -f "$WORKING_HOME/.gitea-instance" fi # Stop and remove MongoDB container if [[ -f "$WORKING_HOME/.mongodb-instance" ]]; then local mongodb_container_id mongodb_container_id=$(cat "$WORKING_HOME/.mongodb-instance") echo "==> Stopping and removing MongoDB container: $mongodb_container_id" docker stop "$mongodb_container_id" &>/dev/null || true docker rm "$mongodb_container_id" &>/dev/null || true rm -f "$WORKING_HOME/.mongodb-instance" fi # Stop and remove RabbitMQ container if [[ -f "$WORKING_HOME/.rabbitmq-instance" ]]; then local rabbitmq_container_id rabbitmq_container_id=$(cat "$WORKING_HOME/.rabbitmq-instance") echo "==> Stopping and removing RabbitMQ container: $rabbitmq_container_id" docker stop "$rabbitmq_container_id" &>/dev/null || true docker rm "$rabbitmq_container_id" &>/dev/null || true rm -f "$WORKING_HOME/.rabbitmq-instance" fi # Stop and remove other components local components=("devsvc" "notification" "content" "central_storage" "authentication") for component in "${components[@]}"; do if [[ -f "$WORKING_HOME/.${component}-instance" ]]; then local component_container_id component_container_id=$(cat "$WORKING_HOME/.${component}-instance") echo "==> Stopping and removing ${component} container: $component_container_id" docker stop "$component_container_id" &>/dev/null || true docker rm "$component_container_id" &>/dev/null || true rm -f "$WORKING_HOME/.${component}-instance" fi done # Clear the DevBox container logs if [[ "$CLEAR_LOGS" == "true" ]]; then echo "==> Clearing logs in $WORKING_HOME/logs..." if [[ -d "$WORKING_HOME/logs" ]]; then sudo chown -R $(whoami):$(whoami) "$WORKING_HOME/logs" rm -rf "$WORKING_HOME/logs" 2>/dev/null || true mkdir -p "$WORKING_HOME/logs" 2>/dev/null || true fi else echo "==> Skipping log clearing." fi # Clear the source repository if [[ "$CLEAR_REPO" == "true" && -d "$WORKING_HOME/freeleaps" ]]; then echo "==> Deleting source repository at $WORKING_HOME/freeleaps" sudo chown -R $(whoami):$(whoami) "$WORKING_HOME/freeleaps" rm -rf "$WORKING_HOME/freeleaps" 2>/dev/null || true rmdir "$WORKING_HOME/freeleaps" 2>/dev/null || true else echo "==> Skipping repository deletion." fi if [[ "$CLEAR_LOGS" == "true" ]]; then # Check if logs directory is removed if [[ -d "$WORKING_HOME/logs" ]]; then echo "[WARNING] $WORKING_HOME/logs still exists after removal." rm -rf "$WORKING_HOME/logs" else echo "==> Logs directory removed successfully." fi fi # Sleep 5 seconds to allow the services to stop, for each second echo 5 seconds increase from 1 to 5 in each second by - for i in {1..5}; do echo -n "=" sleep 1 done # Remove the use-local-component file rm -f "$WORKING_HOME/.use-local-component" echo "> DevBox deinitialization completed." } # :command.function devbox_start_command() { local COMPONENT="$(get_arg '--component')" local WORKING_HOME="$(get_arg '--working-home' "${HOME}/.devbox")" local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" # Check if the DevBox container is running local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" if [[ ! -f "$devbox_container_id_file_path" ]]; then echo "ERROR: DevBox container is not running. Please run 'devbox init' first." exit 1 fi local devbox_container_id=$(cat "$devbox_container_id_file_path") # Check if use local component if [[ -f "$WORKING_HOME/.use-local-component" ]]; then USE_LOCAL_COMPONENT=$(cat "$WORKING_HOME/.use-local-component") else USE_LOCAL_COMPONENT="false" fi if [[ "$(lower "$USE_LOCAL_COMPONENT")" == "true" ]]; then echo "==> Using local components for Freeleaps services." USE_LOCAL_COMPONENT="true" else echo "==> Using online components for Freeleaps services." USE_LOCAL_COMPONENT="false" fi if [[ "$USE_LOCAL_COMPONENT" == "true" ]]; then # If no component is specified, start all components if [[ -z "$COMPONENT" ]]; then COMPONENTS=( "gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") else COMPONENTS=("$COMPONENT") fi else # If no component is specified, start all components if [[ -z "$COMPONENT" ]]; then COMPONENTS=("mongodb" "rabbitmq" "devbox") else if [[ "$COMPONENT" == "devsvc" || "$COMPONENT" == "notification" || "$COMPONENT" == "content" || "$COMPONENT" == "central_storage" || "$COMPONENT" == "authentication" ]]; then echo "ERROR: Remote component $COMPONENT cannot be restarted." exit 1 fi COMPONENTS=("$COMPONENT") fi fi # Start the specified components for comp in "${COMPONENTS[@]}"; do case "$comp" in "gitea" | "mongodb" | "rabbitmq" | "devbox" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") echo "==> Starting $comp service..." # Check if the component container file exists local component_container_id_file_path="${WORKING_HOME}/.${comp}-instance" if [[ ! -f "$component_container_id_file_path" ]]; then echo "ERROR: $comp container is not running. Please run 'devbox init' first." else local component_container_id=$(cat "$component_container_id_file_path") if ! docker ps --no-trunc --format '{{.ID}}' | grep -q "^${component_container_id}\$"; then echo "==> $comp container is not running, starting container..." # Start the container if ! docker start "${component_container_id}"; then echo "ERROR: Failed to start $comp container." else echo "==> $comp container started successfully." fi else echo "==> $comp container is already running." fi fi ;; *) echo "ERROR: Unknown component: $comp" exit 1 ;; esac done if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then # Sleep for 10 seconds to allow the services to start and echo 10 seconds increase from 1 to 10 in each second for i in {1..20}; do if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then break fi echo -n "-" sleep 1 done if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then echo "==> Starting Freeleaps frontend and backend services..." # Start the backend and frontend services docker exec -i "$devbox_container_id" bash < /home/.devbox/logs/backend.logs 2>&1 & BACKEND_PID=\$! # Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. echo "\$BACKEND_PID" > /home/.devbox/.backend.pid # Check if the backend service started successfully sleep 10 if ! ps -p "\$BACKEND_PID" &>/dev/null; then echo "ERROR: Backend service failed to start." exit 1 fi # Start the frontend service echo '============================================' echo ' Start frontend service locally' echo '============================================' pushd /home/.devbox/freeleaps/frontend npm run dev > /home/.devbox/logs/frontend.logs 2>&1 & FRONTEND_PID=\$! echo "\$FRONTEND_PID" > /home/.devbox/.frontend.pid # Check if the frontend service started successfully sleep 10 if ! ps -p "\$FRONTEND_PID" &>/dev/null; then echo "ERROR: Frontend service failed to start." exit 1 fi # Test backend and frontend services echo "Testing backend and frontend services..." # Test the backend service echo "Testing backend service..." curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs" if [ "\$?" -ne 0 ]; then echo "ERROR: Backend service is not available." exit 1 fi # Test the frontend service echo "Testing frontend service..." curl -s -o /dev/null -w "%{http_code}" "http://localhost:5173/" if [ "\$?" -ne 0 ]; then echo "ERROR: Frontend service is not available." exit 1 fi echo "Backend and frontend services started successfully." EOF else echo "ERROR: DevBox container is not running." exit 1 fi fi echo "==> DevBox services started successfully." } # :command.function devbox_stop_command() { echo "==> Stopping DevBox services..." local COMPONENT="$(get_arg '--component')" local WORKING_HOME="$(get_arg '--working-home' "${HOME}/.devbox")" # If the DevBox container is not running, exit if [[ -z "$COMPONENT" ]]; then COMPONENTS=("gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") else COMPONENTS=("$COMPONENT") fi # Stop the specified components for comp in "${COMPONENTS[@]}"; do case "$comp" in "devbox") if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.devbox-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "==> Stopping devbox..." docker stop "$container_id" &>/dev/null || true # Remove the frontend and backend pid files rm -f "${WORKING_HOME}/.backend.pid" rm -f "${WORKING_HOME}/.frontend.pid" else echo "==> DevBox container is not running." fi else echo "==> Backend service is not running." fi ;; "gitea"| "mongodb"| "rabbitmq" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.${comp}-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "==> Stopping $comp service..." docker stop "$container_id" &>/dev/null || true else echo "==> $comp service is not running." fi else echo "==> $comp service is not running." fi ;; *) echo "ERROR: Unknown component: $comp" exit 1 ;; esac done echo "==> All conponent services stopped successfully." } # :command.function devbox_status_command() { echo "==> Checking DevBox services status..." local COMPONENT="$(get_arg '--component')" local WORKING_HOME="$(get_arg '--working-home' "${HOME}/.devbox")" # Check if .devbox-instance file exists if [[ ! -f "${WORKING_HOME}/.devbox-instance" ]]; then echo "==> DevBox container is not running." exit 1 fi local devbox_container_id=$(cat "${WORKING_HOME}/.devbox-instance") # If the DevBox container devbox_container_id is not running, exit if ! docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then echo "==> DevBox container is not running." exit 1 fi # If no component is specified, check all components if [[ -z "$COMPONENT" ]]; then COMPONENTS=("mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") else COMPONENTS=("$COMPONENT") fi # Check the status of the specified components for comp in "${COMPONENTS[@]}"; do case "$comp" in "mongodb") echo "==> Checking MongoDB status..." if [[ -f "${WORKING_HOME}/.mongodb-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.mongodb-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "[RESULT]: MongoDB container is running." else echo "[RESULT]: MongoDB container is not running." fi else echo "[RESULT]: MongoDB container is not running." fi ;; "rabbitmq") echo "==> Checking RabbitMQ status..." if [[ -f "${WORKING_HOME}/.rabbitmq-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.rabbitmq-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "[RESULT]: RabbitMQ container is running." else echo "[RESULT]: RabbitMQ container is not running." fi else echo "[RESULT]: RabbitMQ container is not running." fi ;; "devbox") echo "==> Checking devbox service status..." if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.devbox-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "[RESULT]: devbox container is running." else echo "[RESULT]: devbox container is not running." fi else echo "[RESULT]: devbox container is not running." fi ;; "devsvc" | "notification" | "content" | "central_storage" | "authentication") echo "==> Checking $comp service status..." if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.${comp}-instance") if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${container_id}\$"; then echo "[RESULT]: $comp service is running." else echo "[RESULT]: $comp service is not running." fi else echo "[RESULT]: $comp service is not running." fi ;; *) echo "ERROR: Unknown component: $comp" exit 1 ;; esac done echo "==> DevBox services status checked successfully." } # :command.function devbox_restart_command() { echo "==> Restarting DevBox services..." local COMPONENT="$(get_arg '--component')" local WORKING_HOME="$(get_arg '--working-home' "${HOME}/.devbox")" local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" # Check devbox container file path local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" if [[ ! -f "$devbox_container_id_file_path" ]]; then echo "ERROR: DevBox container is not running. Please run 'devbox init' first." exit 1 fi local devbox_container_id=$(cat "$devbox_container_id_file_path") # Check if current environment is using local components USE_LOCAL_COMPONENT=$(cat "${WORKING_HOME}/.use-local-component" 2>/dev/null || true) if [[ "$USE_LOCAL_COMPONENT" == "true" ]]; then echo "==> Using local components..." if [[ -z "$COMPONENT" ]]; then COMPONENTS=("gitea" "mongodb" "rabbitmq" "devbox" "devsvc" "notification" "content" "central_storage" "authentication") else COMPONENTS=("$COMPONENT") fi else echo "==> Using remote components..." if [[ -z "$COMPONENT" ]]; then COMPONENTS=("mongodb" "rabbitmq" "devbox") else if [[ "$COMPONENT" == "devsvc" || "$COMPONENT" == "notification" || "$COMPONENT" == "content" || "$COMPONENT" == "central_storage" || "$COMPONENT" == "authentication" ]]; then echo "ERROR: Remote component $COMPONENT cannot be restarted." exit 1 fi COMPONENTS=("$COMPONENT") fi fi # Stop the specified components for comp in "${COMPONENTS[@]}"; do case "$comp" in "devbox") if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.devbox-instance") echo "==> Stopping devbox service..." docker stop "$container_id" &>/dev/null || true # Remove the frontend and backend pid files rm -f "${WORKING_HOME}/.backend.pid" rm -f "${WORKING_HOME}/.frontend.pid" else echo "==> Devbox is not running." fi ;; "gitea" | "mongodb" | "rabbitmq" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.${comp}-instance") echo "==> Stopping $comp service..." docker stop "$container_id" &>/dev/null || true else echo "==> $comp service is not running." fi ;; *) echo "ERROR: Unknown component: $comp" exit 1 ;; esac done # Start the specified components for comp in "${COMPONENTS[@]}"; do case "$comp" in "gitea" | "mongodb" | "rabbitmq" | "devbox" | "devsvc" | "notification" | "content" | "central_storage" | "authentication") echo "==> Restarting $comp service..." if [[ -f "${WORKING_HOME}/.${comp}-instance" ]]; then local container_id container_id=$(cat "${WORKING_HOME}/.${comp}-instance") docker start "$container_id" &>/dev/null || true else echo "==> $comp service is not running." fi ;; *) echo "ERROR: Unknown component: $comp" exit 1 ;; esac done if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then # Sleep for 10 seconds to allow the services to start and echo 10 seconds increase from 1 to 10 in each second for i in {1..20}; do if docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then break fi echo -n "-" sleep 1 done # Start the backend and frontend services docker exec -i "$devbox_container_id" bash < /home/.devbox/logs/backend.logs 2>&1 & BACKEND_PID=\$! # Save BACKEND_PID to a file \${WORKING_HOME}/.backend.pid: Stores the process id of backend process. echo "\$BACKEND_PID" > /home/.devbox/.backend.pid # Check if the backend service started successfully sleep 10 if ! ps -p "\$BACKEND_PID" &>/dev/null; then echo "ERROR: Backend service failed to start." exit 1 fi # Start the frontend service echo '============================================' echo ' Start frontend service locally' echo '============================================' pushd /home/.devbox/freeleaps/frontend npm run dev > /home/.devbox/logs/frontend.logs 2>&1 & FRONTEND_PID=\$! echo "\$FRONTEND_PID" > /home/.devbox/.frontend.pid # Check if the frontend service started successfully sleep 10 if ! ps -p "\$FRONTEND_PID" &>/dev/null; then echo "ERROR: Frontend service failed to start." exit 1 fi # Test backend and frontend services echo "Testing backend and frontend services..." # Test the backend service echo "Testing backend service..." curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs" if [ "\$?" -ne 0 ]; then echo "ERROR: Backend service is not available." exit 1 fi # Test the frontend service echo "Testing frontend service..." curl -s -o /dev/null -w "%{http_code}" "http://localhost:5173/" if [ "\$?" -ne 0 ]; then echo "ERROR: Frontend service is not available." exit 1 fi echo "Backend and frontend services started successfully." EOF fi echo "==> DevBox services restarted successfully." } # :command.parse_requirements parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --version | -v) version_command exit ;; --help | -h) long_usage=yes devbox_usage exit ;; *) break ;; esac done # :command.environment_variables_filter env_var_names+=("FREELEAPS_USERNAME") env_var_names+=("FREELEAPS_PASSWORD") env_var_names+=("WORKING_HOME") # :command.command_filter action=${1:-} case $action in -*) ;; init | i) action="init" shift devbox_init_parse_requirements "$@" shift $# ;; deinit | d) action="deinit" shift devbox_deinit_parse_requirements "$@" shift $# ;; start | s) action="start" shift devbox_start_parse_requirements "$@" shift $# ;; stop | p) action="stop" shift devbox_stop_parse_requirements "$@" shift $# ;; status | t) action="status" shift devbox_status_parse_requirements "$@" shift $# ;; restart | r) action="restart" shift devbox_restart_parse_requirements "$@" shift $# ;; # :command.command_fallback "") devbox_usage >&2 exit 1 ;; *) printf "invalid command: %s\n" "$action" >&2 exit 1 ;; esac # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done } # :command.parse_requirements devbox_init_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_init_usage exit ;; *) break ;; esac done # :command.command_filter action="init" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --os | -o) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--os' "$2" shift 2 else printf "%s\n" "--os requires an argument: --os OS" >&2 exit 1 fi ;; # :flag.case --arch | -a) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--arch' "$2" shift 2 else printf "%s\n" "--arch requires an argument: --arch ARCH" >&2 exit 1 fi ;; # :flag.case --devbox-container-name | -N) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-container-name' "$2" shift 2 else printf "%s\n" "--devbox-container-name requires an argument: --devbox-container-name DEVBOX_CONTAINER_NAME" >&2 exit 1 fi ;; # :flag.case --devbox-container-port | -P) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-container-port' "$2" shift 2 else printf "%s\n" "--devbox-container-port requires an argument: --devbox-container-port DEVBOX_CONTAINER_PORT" >&2 exit 1 fi ;; --devbox-frontend-port | -F) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-frontend-port' "$2" shift 2 else printf "%s\n" "--devbox-frontend-port requires an argument: --devbox-frontend-port DEVBOX_FRONTEND_PORT" >&2 exit 1 fi ;; --devbox-backend-port | -B) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-backend-port' "$2" shift 2 else printf "%s\n" "--devbox-backend-port requires an argument: --devbox-backend-port DEVBOX_BACKEND_PORT" >&2 exit 1 fi ;; # :flag.case --devbox-image-repo | -R) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-image-repo' "$2" shift 2 else printf "%s\n" "--devbox-image-repo requires an argument: --devbox-image-repo DEVBOX_IMAGE_REPO" >&2 exit 1 fi ;; # :flag.case --devbox-image-name | -I) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-image-name' "$2" shift 2 else printf "%s\n" "--devbox-image-name requires an argument: --devbox-image-name DEVBOX_IMAGE_NAME" >&2 exit 1 fi ;; # :flag.case --devbox-image-tag | -T) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-image-tag' "$2" shift 2 else printf "%s\n" "--devbox-image-tag requires an argument: --devbox-image-tag DEVBOX_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --working-home | -w) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--working-home' "$2" shift 2 else printf "%s\n" "--working-home requires an argument: --working-home WORKING_HOME" >&2 exit 1 fi ;; # :flag.case --freeleaps-username | -U) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--freeleaps-username' "$2" shift 2 else printf "%s\n" "--freeleaps-username requires an argument: --freeleaps-username FREELEAPS_USERNAME" >&2 exit 1 fi ;; # :flag.case --freeleaps-password | -X) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--freeleaps-password' "$2" shift 2 else printf "%s\n" "--freeleaps-password requires an argument: --freeleaps-password FREELEAPS_PASSWORD" >&2 exit 1 fi ;; # :flag.case --use-local-component | -u) if [[ -n ${2+x} ]]; then add_arg '--use-local-component' "$2" shift 2 else printf "%s\n" "--use-local-component requires an argument: --use-local-component USING_LOCAL_COMPONENT" >&2 exit 1 fi ;; # :flag.case --devsvc-image-repo | -D) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devsvc-image-repo' "$2" shift 2 else printf "%s\n" "--devsvc-image-repo requires an argument: --devsvc-image-repo DEVSVC_IMAGE_REPO" >&2 exit 1 fi ;; # :flag.case --devsvc-image-name | -M) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devsvc-image-name' "$2" shift 2 else printf "%s\n" "--devsvc-image-name requires an argument: --devsvc-image-name DEVSVC_IMAGE_NAME" >&2 exit 1 fi ;; # :flag.case --devsvc-image-tag | -G) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devsvc-image-tag' "$2" shift 2 else printf "%s\n" "--devsvc-image-tag requires an argument: --devsvc-image-tag DEVSVC_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --notification-image-repo | -Y) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--notification-image-repo' "$2" shift 2 else printf "%s\n" "--notification-image-repo requires an argument: --notification-image-repo NOTIFICATION_IMAGE_REPO" >&2 exit 1 fi ;; --notification-image-name | -K) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--notification-image-name' "$2" shift 2 else printf "%s\n" "--notification-image-name requires an argument: --notification-image-name NOTIFICATION_IMAGE_NAME" >&2 exit 1 fi ;; --notification-image-tag | -Z) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--notification-image-tag' "$2" shift 2 else printf "%s\n" "--notification-image-tag requires an argument: --notification-image-tag NOTIFICATION_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --content-image-repo | -C) if [[ -n ${2+x} ]]; then add_arg '--content-image-repo' "$2" shift 2 else printf "%s\n" "--content-image-repo requires an argument: --content-image-repo FREELEAPS_CONTENT_IMAGE_REPO" >&2 exit 1 fi ;; # :flag.case --content-image-name | -E) if [[ -n ${2+x} ]]; then add_arg '--content-image-name' "$2" shift 2 else printf "%s\n" "--content-image-name requires an argument: --content-image-name FREELEAPS_CONTENT_IMAGE_NAME" >&2 exit 1 fi ;; # :flag.case --content-image-tag | -H) if [[ -n ${2+x} ]]; then add_arg '--content-image-tag' "$2" shift 2 else printf "%s\n" "--content-image-tag requires an argument: --content-image-tag FREELEAPS_CONTENT_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --central_storage-image-repo | -S) if [[ -n ${2+x} ]]; then add_arg '--central_storage-image-repo' "$2" shift 2 else printf "%s\n" "--central_storage-image-repo requires an argument: --central_storage-image-repo FREELEAPS_CENTRAL_STORAGE_IMAGE_REPO" >&2 exit 1 fi ;; # :flag.case --central_storage-image-name | -J) if [[ -n ${2+x} ]]; then add_arg '--central_storage-image-name' "$2" shift 2 else printf "%s\n" "--central_storage-image-name requires an argument: --central_storage-image-name FREELEAPS_CENTRAL_STORAGE_IMAGE_NAME" >&2 exit 1 fi ;; # :flag.case --central_storage-image-tag | -Q) if [[ -n ${2+x} ]]; then add_arg '--central_storage-image-tag' "$2" shift 2 else printf "%s\n" "--central_storage-image-tag requires an argument: --central_storage-image-tag FREELEAPS_CENTRAL_STORAGE_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --authentication-image-repo | -V) if [[ -n ${2+x} ]]; then add_arg '--authentication-image-repo' "$2" shift 2 else printf "%s\n" "--authentication-image-repo requires an argument: --authentication-image-repo FREELEAPS_AUTHENTICATION_IMAGE_REPO" >&2 exit 1 fi ;; # :flag.case --authentication-image-name | -L) if [[ -n ${2+x} ]]; then add_arg '--authentication-image-name' "$2" shift 2 else printf "%s\n" "--authentication-image-name requires an argument: --authentication-image-name FREELEAPS_AUTHENTICATION_IMAGE_NAME" >&2 exit 1 fi ;; # :flag.case --authentication-image-tag | -W) if [[ -n ${2+x} ]]; then add_arg '--authentication-image-tag' "$2" shift 2 else printf "%s\n" "--authentication-image-tag requires an argument: --authentication-image-tag FREELEAPS_AUTHENTICATION_IMAGE_TAG" >&2 exit 1 fi ;; # :flag.case --force | -f) # :flag.case_no_arg add_arg '--force' '1' shift ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done # :command.default_assignments if [ -z "$(get_arg '--os')" ]; then add_arg '--os' "auto" fi if [ -z "$(get_arg '--arch')" ]; then add_arg '--arch' "auto" fi if [ -z "$(get_arg '--devbox-container-name')" ]; then add_arg '--devbox-container-name' "devbox" fi if [ -z "$(get_arg '--devbox-container-port')" ]; then add_arg '--devbox-container-port' "22222" fi if [ -z "$(get_arg '--devbox-frontend-port')" ]; then add_arg '--devbox-frontend-port' "5173" fi if [ -z "$(get_arg '--devbox-backend-port')" ]; then add_arg '--devbox-backend-port' "8002" fi if [ -z "$(get_arg '--devbox-image-repo')" ]; then add_arg '--devbox-image-repo' "docker.io/freeleaps" fi if [ -z "$(get_arg '--devbox-image-name')" ]; then add_arg '--devbox-image-name' "devbox_v1" fi if [ -z "$(get_arg '--devbox-image-tag')" ]; then add_arg '--devbox-image-tag' "devbox_local" fi if [ -z "$(get_arg '--devsvc-image-tag')" ]; then add_arg '--devsvc-image-tag' "latest-linux-arm64" fi if [ -z "$(get_arg '--content-image-tag')" ]; then add_arg '--content-image-tag' "latest-linux-arm64" fi if [ -z "$(get_arg '--central_storage-image-tag')" ]; then add_arg '--central_storage-image-tag' "latest-linux-arm64" fi if [ -z "$(get_arg '--authentication-image-tag')" ]; then add_arg '--authentication-image-tag' "latest-linux-arm64" fi if [ -z "$(get_arg '--working-home')" ]; then add_arg '--working-home' "${HOME}/.devbox" fi if [ -z "$(get_arg '--use-local-component')" ]; then add_arg '--use-local-component' "false" fi } # :command.parse_requirements devbox_deinit_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_deinit_usage exit ;; *) break ;; esac done # :command.command_filter action="deinit" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --working-home | -w) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--working-home' "$2" shift shift else printf "%s\n" "--working-home requires an argument: --working-home WORKING_HOME" >&2 exit 1 fi ;; # :flag.case --clear-logs | -l) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--clear-logs' "$2" shift shift else printf "%s\n" "--clear-logs requires an argument: --clear-logs CLEAR_LOGS" >&2 exit 1 fi ;; # :flag.case --clear-repo | -r) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--clear-repo' "$2" shift shift else printf "%s\n" "--clear-repo requires an argument: --clear-repo CLEAR_REPO" >&2 exit 1 fi ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done # :command.default_assignments if [ -z "$(get_arg '--working-home')" ]; then add_arg '--working-home' "${HOME}/.devbox" fi if [ -z "$(get_arg '--clear-logs')" ]; then add_arg '--clear-logs' "false" fi if [ -z "$(get_arg '--clear-repo')" ]; then add_arg '--clear-repo' "false" fi } # :command.parse_requirements devbox_start_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_start_usage exit ;; *) break ;; esac done # :command.command_filter action="start" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --component | -c) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--component' "$2" shift shift else printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 exit 1 fi ;; --freeleaps-endpoint | -e) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--freeleaps-endpoint' "$2" shift shift else printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint FREELEAPS_ENDPOINT" >&2 exit 1 fi ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done # :command.default_assignments if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then add_arg '--freeleaps-endpoint' "false" fi } # :command.parse_requirements devbox_stop_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_stop_usage exit ;; *) break ;; esac done # :command.command_filter action="stop" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --component | -c) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--component' "$2" shift shift else printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 exit 1 fi ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done } # :command.parse_requirements devbox_status_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_status_usage exit ;; *) break ;; esac done # :command.command_filter action="status" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --component | -c) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--component' "$2" shift shift else printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 exit 1 fi ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done } # :command.parse_requirements devbox_restart_parse_requirements() { # :command.fixed_flags_filter while [[ $# -gt 0 ]]; do key="$1" case "$key" in --help | -h) long_usage=yes devbox_restart_usage exit ;; *) break ;; esac done # :command.command_filter action="restart" # :command.parse_requirements_while while [[ $# -gt 0 ]]; do key="$1" case "$key" in # :flag.case --component | -c) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--component' "$2" shift shift else printf "%s\n" "--component requires an argument: --component COMPONENT" >&2 exit 1 fi ;; --freeleaps-endpoint | -e) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--freeleaps-endpoint' "$2" shift shift else printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint FREELEAPS_ENDPOINT" >&2 exit 1 fi ;; -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 ;; *) # :command.parse_requirements_case # :command.parse_requirements_case_simple printf "invalid argument: %s\n" "$key" >&2 exit 1 ;; esac done # :command.default_assignments if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then add_arg '--freeleaps-endpoint' "false" fi } initialize() { version="1.0.0" long_usage="" set -e # Use the following variables to define the environment variables and input parameters args_keys=() args_values=() deps_keys=() deps_values=() # For each environment variable, add a line like the following: env_var_names=() input=() } # :command.run run() { normalize_input "$@" parse_requirements "${input[@]}" case "$action" in "init") devbox_init_command ;; "deinit") devbox_deinit_command ;; "start") devbox_start_command ;; "stop") devbox_stop_command ;; "status") devbox_status_command ;; "restart") devbox_restart_command ;; esac } initialize run "$@"