diff --git a/devbox/devbox.local/devbox b/devbox/devbox.local/devbox new file mode 100644 index 0000000..ad4d899 --- /dev/null +++ b/devbox/devbox.local/devbox @@ -0,0 +1,1653 @@ +#!/usr/bin/env bash +# This script was generated by bashly 1.2.7 (https://bashly.dannyb.co) +# Modifying it manually is not recommended + +# :wrapper.bash3_bouncer +if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then + printf "bash version 4 or higher is required\n" >&2 + exit 1 +fi + +# :command.master_script + +# :command.version_command +version_command() { + echo "$version" +} + +# :command.usage +devbox_usage() { + printf "devbox - DevBox Command Line Tool\n\n" + + printf "%s\n" "Usage:" + printf " devbox COMMAND\n" + printf " devbox [COMMAND] --help | -h\n" + printf " devbox --version | -v\n" + echo + # :command.usage_commands + printf "%s\n" "Commands:" + printf " %s Initialize the local development environment based on DevBox container.\n" "init" + echo + + # :command.long_usage + if [[ -n "$long_usage" ]]; then + printf "%s\n" "Options:" + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + printf " %s\n" "--version, -v" + printf " Show version number\n" + echo + + # :command.usage_environment_variables + printf "%s\n" "Environment Variables:" + + # :environment_variable.usage + printf " %s\n" "FREELEAPS_USERNAME" + printf " Set the Freeleaps username for cloning the source repository.\n" + echo + + # :environment_variable.usage + printf " %s\n" "FREELEAPS_PASSWORD" + printf " Set the Freeleaps password for cloning the source repository.\n" + echo + + # :environment_variable.usage + printf " %s\n" "WORKING_HOME" + printf " Set the working home directory for DevBox.\n" + echo + + fi +} + +# :command.usage +devbox_init_usage() { + if [[ -n $long_usage ]]; then + printf "devbox init\n\n" + printf " Initialize the local development environment based on DevBox container.\n This command will pull the DevBox container image, create containers for \n various Freeleaps components, clone the source code repository, and \n persist relevant container/process information under WORKING_HOME.\n \n Sub-command \`init\` uses Docker (or another container runtime) to set \n up a local DevBox environment for Freeleaps development. \n It follows these major steps:\n 1. Validate flags and environment.\n 2. Pull DevBox base image and create container.\n 3. Pull each required component image, create containers.\n 4. Clone remote source repository using FREELEAPS_USERNAME/PASSWORD.\n 5. Start back-end and front-end services.\n 6. Persist container IDs, logs, etc. into WORKING_HOME.\n\n" + else + printf "devbox init - Initialize the local development environment based on DevBox container.\n\n" + fi + printf "Alias: i\n" + echo + + printf "%s\n" "Usage:" + printf " devbox init [OPTIONS]\n" + printf " devbox init --help | -h\n" + echo + + # :command.long_usage + if [[ -n "$long_usage" ]]; then + printf "%s\n" "Options:" + + # :command.usage_flags + # :flag.usage + printf " %s\n" "--os OS" + printf " Specifies the operating system (auto, linux, darwin, wsl2). Default is auto.\n" + printf " %s\n" "Default: auto" + echo + + # :flag.usage + printf " %s\n" "--arch ARCH" + printf " Specifies the architecture (auto, amd64, arm64). Default is auto.\n" + printf " %s\n" "Default: auto" + echo + + # :flag.usage + printf " %s\n" "--devbox-container-name DEVBOX_CONTAINER_NAME" + printf " Specifies the DevBox container name. Default is devbox.\n" + printf " %s\n" "Default: devbox" + echo + + # :flag.usage + printf " %s\n" "--devbox-container-port DEVBOX_CONTAINER_PORT" + printf " Specifies the container port for DevBox SSH access. Default is 22222.\n" + printf " %s\n" "Default: 22222" + echo + + # :flag.usage + printf " %s\n" "--devbox-image-repo DEVBOX_IMAGE_REPO" + printf " Specifies the DevBox container image repository. Default is\n docker.io/freeleaps.\n" + printf " %s\n" "Default: docker.io/freeleaps" + echo + + # :flag.usage + printf " %s\n" "--devbox-image-name DEVBOX_IMAGE_NAME" + printf " Specifies the DevBox container image name. Default is devbox.\n" + printf " %s\n" "Default: devbox" + echo + + # :flag.usage + printf " %s\n" "--devbox-image-tag DEVBOX_IMAGE_TAG" + printf " Specifies the DevBox container image tag. Default is latest.\n" + printf " %s\n" "Default: latest" + echo + + # :flag.usage + printf " %s\n" "--working-home WORKING_HOME" + printf " Specifies the working home of DevBox CLI. Default is ${HOME}/.devbox.\n" + echo + + # :flag.usage + printf " %s\n" "--freeleaps-username FREELEAPS_USERNAME (required)" + printf " Specifies the Freeleaps.com username (Required).\n" + echo + + # :flag.usage + printf " %s\n" "--freeleaps-password FREELEAPS_PASSWORD (required)" + printf " Specifies the Freeleaps.com password (Required).\n" + echo + + # :flag.usage + printf " %s\n" "--use-local-component IS_USE_LOCAL_COMPONENT" + printf " Check if use local component or use online dev environment. (Default: false, use online service) (Optional)\n" + echo + + # :flag.usage + printf " %s\n" "--devsvc-image-repo DEVSVC_IMAGE_REPO" + printf " Specifies the repository for devsvc component. (Optional)\n" + echo + + # :flag.usage + printf " %s\n" "--devsvc-image-name DEVSVC_IMAGE_NAME" + printf " Specifies the image name for devsvc component. (Optional)\n" + echo + + # :flag.usage + printf " %s\n" "--devsvc-image-tag DEVSVC_IMAGE_TAG" + printf " Specifies the image tag for devsvc component. (Optional, default=latest)\n" + printf " %s\n" "Default: latest" + echo + + # 用于 notification 组件的 usage 说明 + printf " %s\n" "--notification-image-repo NOTIFICATION_IMAGE_REPO" + printf " Specifies the repository for notification component. (Optional)\n" + echo + + printf " %s\n" "--notification-image-name NOTIFICATION_IMAGE_NAME" + printf " Specifies the image name for notification component. (Optional)\n" + echo + + printf " %s\n" "--notification-image-tag NOTIFICATION_IMAGE_TAG" + printf " Specifies the image tag for notification component. (Optional, default=latest)\n" + printf " %s\n" "Default: latest" + echo + + # 用于 content 组件的 usage 说明 + printf " %s\n" "--content-image-repo CONTENT_IMAGE_REPO" + printf " Specifies the repository for content component. (Optional)\n" + echo + + printf " %s\n" "--content-image-name CONTENT_IMAGE_NAME" + printf " Specifies the image name for content component. (Optional)\n" + echo + + printf " %s\n" "--content-image-tag CONTENT_IMAGE_TAG" + printf " Specifies the image tag for content component. (Optional, default=latest)\n" + printf " %s\n" "Default: latest" + echo + + # 用于 central_storage 组件的 usage 说明 + printf " %s\n" "--central_storage-image-repo CENTRAL_STORAGE_IMAGE_REPO" + printf " Specifies the repository for central_storage component. (Optional)\n" + echo + + printf " %s\n" "--central_storage-image-name CENTRAL_STORAGE_IMAGE_NAME" + printf " Specifies the image name for central_storage component. (Optional)\n" + echo + + printf " %s\n" "--central_storage-image-tag CENTRAL_STORAGE_IMAGE_TAG" + printf " Specifies the image tag for central_storage component. (Optional, default=latest)\n" + printf " %s\n" "Default: latest" + echo + + # 用于 authentication 组件的 usage 说明 + printf " %s\n" "--authentication-image-repo AUTHENTICATION_IMAGE_REPO" + printf " Specifies the repository for authentication component. (Optional)\n" + echo + + printf " %s\n" "--authentication-image-name AUTHENTICATION_IMAGE_NAME" + printf " Specifies the image name for authentication component. (Optional)\n" + echo + + printf " %s\n" "--authentication-image-tag AUTHENTICATION_IMAGE_TAG" + printf " Specifies the image tag for authentication component. (Optional, default=latest)\n" + printf " %s\n" "Default: latest" + echo + + # :flag.usage + printf " %s\n" "--force, -f" + printf " Force initialization even if resources already exist.\n" + echo + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + + # :command.usage_examples + printf "%s\n" "Examples:" + printf " devbox init --os=linux --arch=amd64 --freeleaps-username alice\n --freeleaps-password secret\n" + printf " devbox init \ --devbox-container-name custom-devbox \ --devbox-container-port\n 22222 \ --freeleaps-username alice \ --freeleaps-password secret\n" + echo + + fi +} + +# :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() { + if ((${#args[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort) + echo args: + for k in "${sorted_keys[@]}"; do + echo "- \${args[$k]} = ${args[$k]}" + done + else + echo args: none + fi + + if ((${#deps[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort) + echo + echo deps: + for k in "${sorted_keys[@]}"; do + echo "- \${deps[$k]} = ${deps[$k]}" + done + fi + + if ((${#env_var_names[@]})); then + readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | sort) + echo + echo "environment variables:" + for k in "${sorted_names[@]}"; do + echo "- \$$k = ${!k:-}" + 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 +} + +# :command.command_functions +# :command.function +devbox_init_command() { + + # src/init_command.sh + #!/usr/bin/env bash + # + # File: src/init_command.sh + # This file implements the `devbox init` command logic. + + # Make sure the function name is `devbox_init_command`. + + 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 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 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 + + # --force flag to overwrite existing resources + local FORCE_INIT="${args_force}" + local OS="${args['--os']}" + local ARCH="${args['--arch']}" + local DEVBOX_NAME="${args['--devbox-container-name']}" + local DEVBOX_PORT="${args['--devbox-container-port']}" + local DEVBOX_FRONTEND_PORT="${args['--devbox-frontend-port']}" + local DEVBOX_BACKEND_PORT="${args['--devbox-backend-port']}" + local DEVBOX_REPO="${args['--devbox-image-repo']}" + local DEVBOX_IMAGE="${args['--devbox-image-name']}" + local DEVBOX_TAG="${args['--devbox-image-tag']}" + local WORKING_HOME="${args['--working-home']:-${WORKING_HOME:-${HOME}/.devbox}}" + local FREELEAPS_USERNAME="${args['--freeleaps-username']}" + local FREELEAPS_PASSWORD="${args['--freeleaps-password']}" + local USE_LOCAL_COMPONENT="${args['--use-local-component']:-false}" + local DEVSVC_REPO="${args['--devsvc-image-repo']}" + local DEVSVC_IMAGE="${args['--devsvc-image-name']}" + local DEVSVC_TAG="${args['--devsvc-image-tag']}" + local NOTIFICATION_REPO="${args['--notification-image-repo']}" + local NOTIFICATION_IMAGE="${args['--notification-image-name']}" + local NOTIFICATION_TAG="${args['--notification-image-tag']}" + local CONTENT_REPO="${args['--content-image-repo']}" + local CONTENT_IMAGE="${args['--content-image-name']}" + local CONTENT_TAG="${args['--content-image-tag']}" + local CENTRAL_STORAGE_REPO="${args['--central_storage-image-repo']}" + local CENTRAL_STORAGE_IMAGE="${args['--central_storage-image-name']}" + local CENTRAL_STORAGE_TAG="${args['--central_storage-image-tag']}" + local AUTHENTICATION_REPO="${args['--authentication-image-repo']}" + local AUTHENTICATION_IMAGE="${args['--authentication-image-name']}" + local AUTHENTICATION_TAG="${args['--authentication-image-tag']}" + + local FORCE_INIT="${args['--force']}" + + local is_pull_all_components=true + + for component in "${components[@]}"; do + if [[ -z "${args["${component}_image_repo"]}" ]]; then + is_pull_all_components=false + break + fi + done + + + 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 " NOTIFICATION_REPO = $NOTIFICATION_REPO" + echo " NOTIFICATION_IMAGE= $NOTIFICATION_IMAGE" + echo " NOTIFICATION_TAG = $NOTIFICATION_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 " 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 + + # ------------------------------------------------------------------- + # 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}')" + # 若无法获取或小于 1GB (1048576 KB),报错 + if [[ -z "$free_space_kb" || $free_space_kb -lt 1048576 ]]; then + echo "ERROR: Insufficient disk space (need >1GB)." + 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 + + # ------------------------------------------------------------------- + # 4. If .devbox-instance exists, --force,use it + # ------------------------------------------------------------------- + if [[ -f "$WORKING_HOME/.devbox-instance" && -z "$FORCE_INIT" ]]; then + echo "ERROR: DevBox already initialized. Use --force to overwrite." + exit 1 + 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 + + + # 如有 --force 且存在旧容器,则可在此删除旧容器/文件(也可在下面先检查容器再删) + # ... + + # ------------------------------------------------------------------- + # 5. 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 + else + echo "ERROR: Container named $DEVBOX_NAME already exists. Use --force to remove it." + exit 1 + fi + fi + + + # 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 /var/run/docker.sock:/var/run/docker.sock \ + "$devbox_full_image" 2>/dev/null + )" + + if [[ -z "$container_id" ]]; then + echo "ERROR: Failed to create DevBox container." + exit 1 + fi + echo "DevBox container created: $container_id" + + # record container id + echo "$container_id" > "${WORKING_HOME}/.devbox-instance" + + # ------------------------------------------------------------------- + # 6. linbwang: pull and start other components + # ------------------------------------------------------------------- + +echo "==> [INIT] Starting Freeleaps services... $USE_LOCAL_COMPONENT" + +if [[ "${USE_LOCAL_COMPONENT,,}" == "true" ]]; then + echo ' ===> Using local components for Freeleaps services.' + # Local components for Freeleaps services (devsvc, notification, content, central_storage, authentication) + + for component in "${components[@]}"; do + local COMPONENT_REPO="${component^^}_REPO" + COMPONENT_REPO="${COMPONENT_REPO//-/_}" + local COMPONENT_IMAGE="${component^^}_IMAGE" + COMPONENT_IMAGE="${COMPONENT_IMAGE//-/_}" + local COMPONENT_TAG="${component^^}_TAG" + COMPONENT_TAG="${COMPONENT_TAG//-/_}" + + # check if is_pull_all_components is false and component repo and component image parameter not empty + if [[ "$is_pull_all_components" == false && -n "${!COMPONENT_REPO}" && -n "${!COMPONENT_IMAGE}" ]]; then + continue + fi + + # Pull the component image + local component_full_image="${!COMPONENT_REPO}/${!COMPONENT_IMAGE}:${!COMPONENT_TAG}" + echo "==> Pulling ${component} image: $component_full_image" + if ! docker pull "$component_full_image"; then + echo "WARNING: Failed to pull ${component} image: $component_full_image, please Check the image and specify it to initialize the component." + fi + + # if container with same name exists, remove it + if docker ps -a --format '{{.Names}}' | grep -q "^${component}\$"; then + if [[ -n "$FORCE_INIT" ]]; then + echo "==> Removing existing container named $component ..." + docker stop "$component" &>/dev/null || true + docker rm "$component" &>/dev/null || true + else + echo "WARNING: Container named $component already exists. Use --force to remove it." + fi + fi + + echo "==> Creating and starting ${component} container..." + local component_container_id + component_container_id="$( + docker run -d \ + --name "$component" \ + --link "$DEVBOX_NAME" \ + -v /var/run/docker.sock:/var/run/docker.sock \ + "$component_full_image" 2>/dev/null + )" + if [[ -z "$component_container_id" ]]; then + echo "WARNING: Failed to create ${component} container. please Check the image and specify it to initialize the component." + fi + echo "$component_container_id" > "${WORKING_HOME}/.${component}-instance" + echo "${component} container created: $component_container_id" + done +else + echo ' ===> Using online components for Freeleaps services.' +fi + +docker exec -i "$DEVBOX_NAME" bash < Using local components" + + cat << 'EOFinner' > ~/freeleaps_home/freeleaps/.dev.env + # Online endpoint info + export MONGODB_NAME=freeleaps2 + export MONGODB_URI=mongodb://172.18.0.1:27017/ + export SITE_ACCESS_PORT=80 + export FREELEAPS_ENV=dev + export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd + export STRIPE_WEBHOOK_SECRET= + export SITE_URL_ROOT=http://localhost/ + export BLOB_STORE_CONNECTION_STR="DefaultEndpointsProtocol=https;AccountName=freeleaps1static;AccountKey=SIk7S3RviJxl1XhGiDZKA3cvzfxNrSbsBMfJ3EbKTsKPeMwhy8FTLpJliRLzQVE6uaSX8giDYw2h+ASt5MmHxQ==;EndpointSuffix=core.windows.net" + export RABBITMQ_HOST=172.18.0.1 + export RABBITMQ_PORT=5672 + export FREELEAPS_DEVSVC_ENDPOINT=http://localhost:8007/api/devsvc/ + export FREELEAPS_CONTENT_ENDPOINT=http://localhost:8013/api/content/ + export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://localhost:8005/api/central_storage/ + export JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + export FREELEAPS_AUTHENTICATION_ENDPOINT=http://localhost:8004/api/auth/ + export EMAIL_FROM=freeleaps@freeleaps.com +EOFinner +else + cat << 'EOFinner' > ~/freeleaps_home/freeleaps/.dev.env + # Online endpoint info + export MONGODB_NAME=freeleaps2-mongo + export MONGODB_URI=mongodb://172.18.0.1:27017/ + export SITE_ACCESS_PORT=80 + export FREELEAPS_ENV=dev + export STRIPE_API_KEY=sk_test_51Ogsw5B0IyqaSJBrwczlr820jnmvA1qQQGoLZ2XxOsIzikpmXo4pRLjw4XVMTEBR8DdVTYySiAv1XX53Zv5xqynF00GfMqttFd + export STRIPE_WEBHOOK_SECRET= + export SITE_URL_ROOT=http://localhost/ + export BLOB_STORE_CONNECTION_STR="DefaultEndpointsProtocol=https;AccountName=freeleaps1static;AccountKey=SIk7S3RviJxl1XhGiDZKA3cvzfxNrSbsBMfJ3EbKTsKPeMwhy8FTLpJliRLzQVE6uaSX8giDYw2h+ASt5MmHxQ==;EndpointSuffix=core.windows.net" + export RABBITMQ_HOST=172.18.0.1 + export RABBITMQ_PORT=5672 + export FREELEAPS_DEVSVC_ENDPOINT=http://localhost:8007/api/devsvc/ + export FREELEAPS_CONTENT_ENDPOINT=http://localhost:8013/api/content/ + export FREELEAPS_CENTRAL_STORAGE_ENDPOINT=http://localhost:8005/api/central_storage/ + export JWT_SECRET_KEY=8f87ca8c3c9c3df09a9c78e0adb0927855568f6072d9efc892534aee35f5867b + export FREELEAPS_AUTHENTICATION_ENDPOINT=http://localhost:8004/api/auth/ + export EMAIL_FROM=freeleaps@freeleaps.com +EOFinner +fi + +source ~/freeleaps_home/freeleaps/.dev.env +cp ~/freeleaps_home/freeleaps/.dev.env ~/freeleaps_home/freeleaps/apps/.env + +cp ~/freeleaps_home/freeleaps/.dev.env ~/freeleaps_home/freeleaps/.env +source ~/freeleaps_home/freeleaps/.dev.env +source ~/freeleaps_home/freeleaps/apps/.env + +echo "Step 3. [INFO] Checking Docker installation..." + + # 1. Check docker CLI installted + if ! command -v docker >/dev/null 2>&1; then + echo "[ERROR] Docker CLI is not installed." + exit 1 + fi + + echo "[INFO] Docker CLI is installed. Checking daemon..." + + # 2. Check if Docker Daemon running + if docker info >/dev/null 2>&1; then + echo '============================================' + echo "[OK] Docker daemon is running." + echo '============================================' + else + + if grep -qi microsoft /proc/version; then + echo "[INFO] Detected WSL environment. Verifying Docker socket..." + if [ -S /var/run/docker.sock ]; then + echo "[OK] Docker socket found." + else + # WSL 2 with Docker Desktop + 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." + else + echo "[ERROR] Failed to start Docker using systemctl." + exit 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." + else + echo "[ERROR] Failed to start Docker using service command." + exit 1 + fi + else + echo "[ERROR] Neither systemctl nor service command found. Please start Docker manually." + exit 1 + fi + fi + + fi + fi + fi + + + +# 3.Create and start MongoDB container +echo "Step 4=2. [INFO] Starting MongoDB container..." + +MONGO_CONTAINER_NAME="freeleaps2-mongo" +MONGO_IMAGE="mongo:latest" + +# if a container with the same name exists, remove it +if docker ps -a --format '{{.Names}}' | grep -q "^\${MONGO_CONTAINER_NAME}\$"; then + echo "==> Removing existing MongoDB container..." + docker stop "\$MONGO_CONTAINER_NAME" &>/dev/null || true + docker rm "\$MONGO_CONTAINER_NAME" &>/dev/null || true +fi + +echo "==> Pulling MongoDB image: \$MONGO_IMAGE" +if ! docker pull "\$MONGO_IMAGE"; then + echo "ERROR: Failed to pull MongoDB image: \$MONGO_IMAGE" + exit 1 +fi + +echo "==> Starting MongoDB container..." +mongo_container_id=\$(docker run -d --name "\$MONGO_CONTAINER_NAME" -p 27017:27017 "\$MONGO_IMAGE") +if [[ -z "\$mongo_container_id" ]]; then + echo "ERROR: Failed to start MongoDB container." + exit 1 +fi +echo "MongoDB container started successfully: \$mongo_container_id" + +sleep 10 + + +echo '============================================' + +MAX_ATTEMPTS=10 +ATTEMPT=0 +while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do + if docker exec "\$MONGO_CONTAINER_NAME" mongosh --eval "db.adminCommand('ping')" 2>/dev/null | grep -q '{ ok: 1 }'; then + echo "MongoDB health check passed." + break + fi + echo "Waiting for MongoDB to be ready... (Attempt \$((ATTEMPT+1)))" + sleep 10 + ATTEMPT=\$((ATTEMPT+1)) +done + +if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then + echo "ERROR: MongoDB health check failed." + exit 1 +fi + +echo "Step 4. [INFO] Starting MongoDB container..." + + +pushd ~/freeleaps_home/freeleaps + +# 4. 安装RABBITMQ_HOST=localhost, RABBITMQ_PORT=5672 docker 容器镜像,并检查是否成功启动 +echo "Step 4. [INFO] Starting RabbitMQ container..." + +RABBITMQ_CONTAINER_NAME="freeleaps2-rabbitmq" +RABBITMQ_IMAGE="rabbitmq:latest" + +# If a container with the same name exists, remove it +if docker ps -a --format '{{.Names}}' | grep -q "^\${RABBITMQ_CONTAINER_NAME}\$"; then + echo "==> Removing existing RabbitMQ container..." + docker stop "\${RABBITMQ_CONTAINER_NAME}" &>/dev/null || true + docker rm "\${RABBITMQ_CONTAINER_NAME}" &>/dev/null || true +fi + +# Pull the RabbitMQ image +echo "==> Pulling RabbitMQ image: \${RABBITMQ_IMAGE}" +if ! docker pull "\${RABBITMQ_IMAGE}"; then + echo "ERROR: Failed to pull RabbitMQ image: \${RABBITMQ_IMAGE}" + exit 1 +fi + +# Run the RabbitMQ container mapping port 5672 +echo "==> Starting RabbitMQ container..." +rabbitmq_container_id=\$(docker run -d --name "\${RABBITMQ_CONTAINER_NAME}" -p 5672:5672 "\${RABBITMQ_IMAGE}") + +if [[ -z "\${rabbitmq_container_id}" ]]; then + echo "ERROR: Failed to start RabbitMQ container." + exit 1 +fi +echo "RabbitMQ container started successfully: \${rabbitmq_container_id}" + +# Allow RabbitMQ some time to initialize +sleep 20 + +# Check RabbitMQ health via rabbitmqctl +if docker exec "\${RABBITMQ_CONTAINER_NAME}" rabbitmqctl status &>/dev/null; then + echo "RabbitMQ health check passed." +else + echo "ERROR: RabbitMQ health check failed." + exit 1 +fi +echo "Step 5. [INFO] Starting RabbitMQ container..." + +echo '============================================' + +# Run start_webapi.sh and check if success started +echo "Step 4: Run start_webapi.sh and check if success started" + +# Start WebAPI service +echo "Starting WebAPI service..." +# Make sure the logs directory exists +mkdir -p ~/freeleaps_home/logs +pushd ~/freeleaps_home/freeleaps/apps +cp ~/freeleaps_home/freeleaps/backend_env.sh ~/freeleaps_home/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 + +echo '============================================1' +dpkg -l | grep python3.10-venv + +echo '============================================1' +# make sore python3.10 is installed +if ! command -v python3.10 &>/dev/null; then + echo "ERROR: Python3.10 is not installed." + exit 1 +fi + +# Set python3.10 as default python3 +echo "6.1. Set Python3.10 as default Python3" +sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1 +sudo update-alternatives --config python3 + +# Check if the ladvei +echo "7. Upgrade pip and install virtualenv" +python3.10 -m ensurepip --upgrade +python3.10 -m pip install --upgrade pip + + +echo '============================================' + +echo 'Current path: ' +pwd + +echo '============================================' + +# 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: 虚拟环境没有创建成功" + exit 1 +fi + +echo '============================================' + +echo ' Start to activate virtual environment' +echo '============================================' + +source venv_t/bin/activate + + +# 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 ~/freeleaps_home/freeleaps/apps/requirements.txt + +echo '============================================' +echo 'Start to run start_webapi.sh' +echo '============================================' +./start_webapi.sh > /tmp/webapi.logs 2>&1 & +WEBAPI_PID=\$! + + +echo '============================================' +echo 'Check if the WebAPI service started successfully' +echo '============================================' + +sleep 30 + +MAX_ATTEMPTS=30 # 30次尝试,每次10秒,总等待5分钟 +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") + # 判断返回的状态码是否为 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 # 等待 5 秒后重试 + 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 ~/freeleaps_home/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' +npm install + +npm update + +npm install -g pnpm +pnpm install +npm run build +npm run format +npm run dev + +# Wait for the frontend service to start +sleep 120 + +# 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 + # ------------------------------------------------------------------- + echo + echo "===========================================================" + echo "DevBox init completed successfully!" + echo " DevBox container ID: $container_id" + [[ -f "${WORKING_HOME}/.devsvc-instance" ]] && echo " devsvc container ID: $(cat "${WORKING_HOME}/.devsvc-instance")" + echo " Repository cloned to: $repo_dir" + echo " Back-end logs: $WORKING_HOME/logs/back-end.logs" + echo " Front-end logs: $WORKING_HOME/logs/front-end.logs" + echo "===========================================================" + echo + +} + +# :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 $# + ;; + + # :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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--os']="$2" + shift + shift + else + printf "%s\n" "--os requires an argument: --os OS" >&2 + exit 1 + fi + ;; + + # :flag.case + --arch) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--arch']="$2" + shift + shift + else + printf "%s\n" "--arch requires an argument: --arch ARCH" >&2 + exit 1 + fi + ;; + + # :flag.case + --devbox-container-name) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devbox-container-name']="$2" + shift + shift + 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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devbox-container-port']="$2" + shift + shift + else + printf "%s\n" "--devbox-container-port requires an argument: --devbox-container-port DEVBOX_CONTAINER_PORT" >&2 + exit 1 + fi + ;; + + # :flag.case + --devbox-image-repo) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devbox-image-repo']="$2" + shift + shift + 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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devbox-image-name']="$2" + shift + shift + 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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devbox-image-tag']="$2" + shift + shift + else + printf "%s\n" "--devbox-image-tag requires an argument: --devbox-image-tag DEVBOX_IMAGE_TAG" >&2 + exit 1 + fi + ;; + + # :flag.case + --working-home) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--working-home']="$2" + shift + shift + else + printf "%s\n" "--working-home requires an argument: --working-home WORKING_HOME" >&2 + exit 1 + fi + ;; + + # :flag.case + --freeleaps-username) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--freeleaps-username']="$2" + shift + shift + else + printf "%s\n" "--freeleaps-username requires an argument: --freeleaps-username FREELEAPS_USERNAME" >&2 + exit 1 + fi + ;; + + # :flag.case + --freeleaps-password) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--freeleaps-password']="$2" + shift + shift + else + printf "%s\n" "--freeleaps-password requires an argument: --freeleaps-password FREELEAPS_PASSWORD" >&2 + exit 1 + fi + ;; + + # :flag.case + --use-local-component) + if [[ -n ${2+x} ]]; then + args['--devsvc-image-repo']="$2" + shift 2 + else + printf "%s\n" "--use-local-component requires an argument: --use-local-component IS_USING_LOCAL_COMPONENT" >&2 + exit 1 + fi + ;; + + # :flag.case + --devsvc-image-repo) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devsvc-image-repo']="$2" + shift + shift + 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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devsvc-image-name']="$2" + shift + shift + 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) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--devsvc-image-tag']="$2" + shift + shift + 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) + if [[ -n ${2+x} ]]; then + args['--notification-image-repo']="$2" + shift 2 + else + printf "%s\n" "--notification-image-repo requires an argument: --notification-image-repo FREELEAPS_NOTIFICATION_IMAGE_REPO" >&2 + exit 1 + fi + ;; + + # :flag.case + --notification-image-name) + if [[ -n ${2+x} ]]; then + args['--notification-image-name']="$2" + shift 2 + else + printf "%s\n" "--notification-image-name requires an argument: --notification-image-name FREELEAPS_NOTIFICATION_IMAGE_NAME" >&2 + exit 1 + fi + ;; + + # :flag.case + --notification-image-tag) + if [[ -n ${2+x} ]]; then + args['--notification-image-tag']="$2" + shift 2 + else + printf "%s\n" "--notification-image-tag requires an argument: --notification-image-tag FREELEAPS_NOTIFICATION_IMAGE_TAG" >&2 + exit 1 + fi + ;; + + # :flag.case + --content-image-repo) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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) + if [[ -n ${2+x} ]]; then + args['--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 + args['--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.required_flags_filter + if [[ -z ${args['--freeleaps-username']+x} ]]; then + printf "missing required flag: --freeleaps-username FREELEAPS_USERNAME\n" >&2 + exit 1 + fi + if [[ -z ${args['--freeleaps-password']+x} ]]; then + printf "missing required flag: --freeleaps-password FREELEAPS_PASSWORD\n" >&2 + exit 1 + fi + + # :command.default_assignments + [[ -n ${args['--os']:-} ]] || args['--os']="auto" + [[ -n ${args['--arch']:-} ]] || args['--arch']="auto" + [[ -n ${args['--devbox-container-name']:-} ]] || args['--devbox-container-name']="devbox" + [[ -n ${args['--devbox-container-port']:-} ]] || args['--devbox-container-port']="22222" + [[ -n ${args['--devbox-frontend-port']:-} ]] || args['--devbox-frontend-port']="5173" + [[ -n ${args['--devbox-backend-port']:-} ]] || args['--devbox-backend-port']="8002" + + [[ -n ${args['--devbox-image-repo']:-} ]] || args['--devbox-image-repo']="docker.io/freeleaps" + [[ -n ${args['--devbox-image-name']:-} ]] || args['--devbox-image-name']="devbox_v1" + [[ -n ${args['--devbox-image-tag']:-} ]] || args['--devbox-image-tag']="devbox_local" + [[ -n ${args['--devsvc-image-tag']:-} ]] || args['--devsvc-image-tag']="latest-linux-amd64" + [[ -n ${args['--notification-image-tag']:-} ]] || args['--notification-image-tag']="latest-linux-amd64" + [[ -n ${args['--content-image-tag']:-} ]] || args['--content-image-tag']="latest-linux-amd64" + [[ -n ${args['--central_storage-image-tag']:-} ]] || args['--central_storage-image-tag']="latest-linux-amd64" + [[ -n ${args['--authentication-image-tag']:-} ]] || args['--authentication-image-tag']="latest-linux-amd64" + [[ -n ${args['--working-home']:-} ]] || args['--working-home']="${HOME}/.devbox" + [[ -n ${args['--use-local-component']:-} ]] || args['--use-local-component']="false" + + +} + +# :command.initialize +initialize() { + version="1.0.0" + long_usage='' + set -e + + # :command.globals + declare -g -A args=() + declare -g -A deps=() + declare -g -a env_var_names=() + declare -g -a input=() + +} + +# :command.run +run() { + normalize_input "$@" + parse_requirements "${input[@]}" + + case "$action" in + "init") devbox_init_command ;; + esac +} + +initialize +run "$@"