diff --git a/devbox/devbox.local/cli/devbox b/devbox/devbox.local/cli/devbox index d13f5b1..f061d0a 100644 --- a/devbox/devbox.local/cli/devbox +++ b/devbox/devbox.local/cli/devbox @@ -80,8 +80,8 @@ devbox_init_usage() { 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-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" @@ -105,9 +105,10 @@ devbox_init_usage() { 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 " --chat-image-repo -B [Optional] : Specifies the repository for chat component.\n" + printf " --use-custom-repository -C [Optional] : Specifies the custom git repository for source code.\n" + printf " --chat-image-repo -M [Optional] : Specifies the repository for chat component.\n" printf " --chat-image-name -N [Optional] : Specifies the image name for chat component.\n" - printf " --chat-image-tag -T [Optional] : Specifies the image tag for chat component. Default: latest.\n" + printf " --chat-image-tag -O [Optional] : Specifies the image tag for chat component. Default: latest.\n" printf " --force -f [Optional] : Force initialization even if resources already exist.\n\n" @@ -134,6 +135,7 @@ devbox_deinit_usage() { 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 " --clear-all -a [Optional] : Specifies whether to clear all resources. Default: false\n\n" printf "Global Arguments\n" printf " --help, -h : Show this help message and exit.\n\n" @@ -143,6 +145,8 @@ devbox_deinit_usage() { 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" + printf " Clear all resources.\n" + printf " devbox deinit --clear-all=true\n" else printf "devbox deinit - De-initialize the local development environment based on DevBox container.\n\n" fi @@ -244,17 +248,21 @@ normalize_input() { local arg passthru flags passthru=false + regex='^--([a-zA-Z0-9_\-]+)=(.+)$' + regex2='^(-[a-zA-Z0-9])=(.+)$' + regex3='^-([a-zA-Z0-9][a-zA-Z0-9]+)$' + while [[ $# -gt 0 ]]; do arg="$1" if [[ $passthru == true ]]; then input+=("$arg") - elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then + elif [[ $arg =~ $regex ]]; then input+=("${BASH_REMATCH[1]}") input+=("${BASH_REMATCH[2]}") - elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then + elif [[ $arg =~ $regex2 ]]; then input+=("${BASH_REMATCH[1]}") input+=("${BASH_REMATCH[2]}") - elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then + elif [[ $arg =~ $regex3 ]]; then flags="${BASH_REMATCH[1]}" for ((i = 0; i < ${#flags}; i++)); do input+=("-${flags:i:1}") @@ -450,9 +458,7 @@ check_docker_running() { } # Define the local components and their corresponding ports -# local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "chat" "authentication") - -declare -g local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "chat" "authentication") +local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "chat" "authentication") local_components_ports_values=("8007" "8003" "8013" "8005" "8012" "8004") @@ -527,7 +533,7 @@ devbox_init_command() { local CHAT_IMAGE="$args_chat_image_image" # --chat-image-image local CHAT_TAG="$args_chat_image_tag" # --chat-image-tag - local CUSTOM_GIT_REPO="$args_custom_git_repo" # --custom-git-repo + local USE_CUSTOM_REPOSITORY="$args_use_custom_repository" # --use-custom-repository # --force flag to overwrite existing resources local FORCE_INIT="${args_force}" @@ -563,8 +569,7 @@ devbox_init_command() { local CHAT_REPO="$(get_arg '--chat-image-repo')" local CHAT_IMAGE="$(get_arg '--chat-image-name')" local CHAT_TAG="$(get_arg '--chat-image-tag')" - - local CUSTOM_GIT_REPO="$(get_arg '--custom-git-repo')" + local USE_CUSTOM_REPOSITORY="$(get_arg '--use-custom-repository')" local FORCE_INIT="$(get_arg '--force')" @@ -767,9 +772,17 @@ devbox_init_command() { # 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" + + # Check local and remote version. User doesn’t need to rebuild devbox if local version is consistent with remote version + if [[ -n "$DEVBOX_REPO" && -n "$DEVBOX_IMAGE" && -n "$DEVBOX_TAG" ]]; then + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${DEVBOX_REPO}/${DEVBOX_IMAGE}:${DEVBOX_TAG}\$"; then + echo "==> DevBox image $devbox_full_image already exists." + else + echo "==> Pulling DevBox image $devbox_full_image..." + docker pull "$devbox_full_image" + fi + else + echo "ERROR: DevBox image repository, name, or tag is not specified." exit 1 fi @@ -829,7 +842,7 @@ devbox_init_command() { # 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"] + echo "$DEVBOX_BACKEND_PORT" > "$WORKING_HOME/.devbox-backend-port" # Check if username and password are set if [[ -z "$FREELEAPS_USERNAME" || -z "$FREELEAPS_PASSWORD" ]]; then @@ -838,46 +851,91 @@ devbox_init_command() { exit 1 fi - ENCODEING_FREELEAPS_USERNAME=$(url_encode "$FREELEAPS_USERNAME") - ENCODEING_FREELEAPS_PASSWORD=$(url_encode "$FREELEAPS_PASSWORD") - # Test if the user can access the freeleaps.com repository - echo "==> Testing access to freeleaps.com repository..." - if ! git ls-remote "https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_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 DOVBOX_CLI_DIR=$(pwd) + + # Check if USE_CUSTOM_REPOSITORY is empty + if [[ -z "$USE_CUSTOM_REPOSITORY" ]]; then + ENCODEING_FREELEAPS_USERNAME=$(url_encode "$FREELEAPS_USERNAME") + ENCODEING_FREELEAPS_PASSWORD=$(url_encode "$FREELEAPS_PASSWORD") + # Test if the user can access the freeleaps.com repository + echo "==> Testing access to freeleaps.com repository..." + if ! git ls-remote "https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_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 - FREELEAPS_DIR="$WORKING_HOME/freeleaps" - FRONTEND_GIT_URL="https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" - # Check if freeleaps2-frontend exists, if not git clone it - if [ ! -d "$FREELEAPS_DIR" ]; then - pushd "$WORKING_HOME" > /dev/null - echo "Git cloning freeleaps.com:3443/products/freeleaps.git 1" - git clone --depth 5 $FRONTEND_GIT_URL - else - echo "Git pulling 2" - pushd "$FREELEAPS_DIR" > /dev/null - # 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 - popd > /dev/null # Exit from $FREELEAPS_DIR - rm -rf "$FREELEAPS_DIR" # Remove $FREELEAPS_DIR - rmdir "$FREELEAPS_DIR" # Remove $FREELEAPS_DIR - # Git clone freeleaps.com:3443/products/freeleaps.git - echo "Cloning repository again: $FRONTEND_GIT_URL" - sudo chown -R "$OWNER_GROUP" "$WORKING_HOME" - git clone --depth 5 "$FRONTEND_GIT_URL" - else - echo "Git pulling freeleaps.com:3443/products/freeleaps.git" - git pull + FREELEAPS_DIR="$WORKING_HOME/freeleaps" + FRONTEND_GIT_URL="https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_FREELEAPS_PASSWORD@freeleaps.com:3443/products/freeleaps.git" + # Check if freeleaps2-frontend exists, if not git clone it + if [ ! -d "$FREELEAPS_DIR" ]; then + pushd "$WORKING_HOME" > /dev/null + echo "Git cloning freeleaps.com:3443/products/freeleaps.git 1" + git clone --depth 5 $FRONTEND_GIT_URL + else + echo "Git pulling 2" + pushd "$FREELEAPS_DIR" > /dev/null + # 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 + popd > /dev/null # Exit from $FREELEAPS_DIR + rm -rf "$FREELEAPS_DIR" # Remove $FREELEAPS_DIR + rmdir "$FREELEAPS_DIR" # Remove $FREELEAPS_DIR + + # Git clone freeleaps.com:3443/products/freeleaps.git + echo "Cloning repository again: $FRONTEND_GIT_URL" + sudo chown -R "$OWNER_GROUP" "$WORKING_HOME" + git clone --depth 5 "$FRONTEND_GIT_URL" + else + echo "Git pulling freeleaps.com:3443/products/freeleaps.git" + git pull + fi + + popd > /dev/null + fi + else + if [[ ! $USE_CUSTOM_REPOSITORY =~ ^(https:\/\/|git@|git:\/\/|file:\/\/\/)[^ ]+\.git$ ]]; then + echo "ERROR: Invalid custom repository URL. Please provide a valid URL." + echo "==> [INIT] DevBox environment initialization completed successfully, but access to the custom repository failed." + exit 1 fi - popd > /dev/null - fi + # Test if the user can access the custom repository + echo "==> Testing access to custom repository..." + if ! git ls-remote "$USE_CUSTOM_REPOSITORY" &>/dev/null; then + echo "ERROR: Failed to access custom repository. Please check the repository URL." + echo "==> [INIT] DevBox environment initialization completed successfully, but access to the custom repository failed." + exit 1 + fi + CUSTOM_FOLDER_NAME=$(basename "$USE_CUSTOM_REPOSITORY" .git) + CUSTOM_DIR="$WORKING_HOME/$CUSTOM_FOLDER_NAME" + if [ ! -d "$CUSTOM_DIR" ]; then + pushd "$WORKING_HOME" > /dev/null + echo "Git cloning custom repository: $USE_CUSTOM_REPOSITORY" + git clone --depth 5 "$USE_CUSTOM_REPOSITORY" + else + pushd "$CUSTOM_DIR" > /dev/null + # Check $WORKING_HOME/custom exists and it is a git repository, if not git clone it + if ! git rev-parse --is-inside-work-tree &>/dev/null; then + popd > /dev/null # Exit from $CUSTOM_DIR + rm -rf "$CUSTOM_DIR" # Remove $CUSTOM_DIR + rmdir "$CUSTOM_DIR" # Remove $CUSTOM_DIR + + # Git clone custom repository + echo "Cloning repository again: $USE_CUSTOM_REPOSITORY" + sudo chown -R "$OWNER_GROUP" "$WORKING_HOME" + git clone --depth 5 "$USE_CUSTOM_REPOSITORY" + else + echo "Git pulling custom repository" + git pull + fi + + popd > /dev/null + fi + fi + pushd $DOVBOX_CLI_DIR > /dev/null # ------------------------------------------------------------------- @@ -889,8 +947,24 @@ echo "==> [INIT] Starting Freeleaps services... Use Local component $USE_LOCAL_C export ARCH="$ARCH" export WORKING_HOME="$WORKING_HOME" +# Save $USE_CUSTOM_REPOSITORY url to .custom-repository file +echo "$USE_CUSTOM_REPOSITORY" > "$WORKING_HOME/.custom-repository" +# If USE_CUSTOM_REPOSITORY is not empty, initialize the custom repository completed +if [[ -n "$USE_CUSTOM_REPOSITORY" ]]; then + echo + echo "===========================================================" + echo "==> [INIT] Custom repository initialization completed." + echo "==> Custom repository is located at: ${WORKING_HOME}/${CUSTOM_FOLDER_NAME}" + echo "==> Custom repository URL: $USE_CUSTOM_REPOSITORY" + echo "==> Custom repository is ready for use." + echo "===========================================================" + echo + + exit 0 +fi + # Check if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then @@ -946,18 +1020,11 @@ if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then mkdir -p ${WORKING_HOME}/logs - mkdir -p ${WORKING_HOME}/logs/devsvc - mkdir -p ${WORKING_HOME}/logs/content - mkdir -p ${WORKING_HOME}/logs/central_storage - mkdir -p ${WORKING_HOME}/logs/authentication - mkdir -p ${WORKING_HOME}/logs/notification - mkdir -p ${WORKING_HOME}/logs/chat - # for each component create log directory for component in "${start_components[@]}"; do - if [[ ! -d "${WORKING_HOME}/log/${component}" ]]; then - mkdir -p "${WORKING_HOME}/log/${component}" + if [[ ! -d "${WORKING_HOME}/logs/${component}" ]]; then + mkdir -p "${WORKING_HOME}/logs/${component}" fi done @@ -973,7 +1040,6 @@ if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then 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 @@ -1051,7 +1117,6 @@ export USE_LOCAL_COMPONENT_VAL="${USE_LOCAL_COMPONENT_VAL}" export DEVBOX_BACKEND_PORT="${DEVBOX_BACKEND_PORT}" export DEVBOX_FRONTEND_PORT="${DEVBOX_FRONTEND_PORT}" - # Check if useing local component and update /home/devbox/freeleaps/.dev.env echo "step 2: Update /home/devbox/freeleaps/apps/.env" # Get default IP address @@ -1176,7 +1241,7 @@ pip install -r /home/devbox/freeleaps/apps/requirements.txt echo '============================================' -echo 'Start to run start_webapi.sh' +echo 'Start backend service locally' echo '============================================' ./start_webapi.sh > /home/devbox/logs/backend.logs 2>&1 & BACKEND_PID=\$! @@ -1293,8 +1358,6 @@ fi echo "Freeleaps services started successfully" EOF - - # ------------------------------------------------------------------- # 10. Final notification # ------------------------------------------------------------------- @@ -1324,15 +1387,14 @@ 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')" + local CLEAR_ALL="$(get_arg '--clear-all')" # 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 " CLEAR_ALL = $CLEAR_ALL" echo "==> Starting DevBox deinitialization..." @@ -1429,6 +1491,25 @@ devbox_deinit_command() { fi fi + if [[ "$CLEAR_ALL" == "true" ]]; then + # Check Y/N to remove the working home directory + read -p "Do you want to delete the working home directory? This will permanently remove all your local code and environment. (Y/N): " user_input + if [[ "$user_input" == "Y" || "$user_input" == "y" ]]; then + REMOVE_WORKING_HOME=true + + # Remove the working home directory + echo "==> Removing working home directory: $WORKING_HOME" + sudo chown -R $(whoami):$(whoami) "$WORKING_HOME" + rm -rf "$WORKING_HOME" 2>/dev/null || true + rmdir "$WORKING_HOME" 2>/dev/null || true + + echo "==> Working home directory removed successfully." + else + REMOVE_WORKING_HOME=false + echo "==> Skipping working home directory removal." + 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 "=" @@ -1438,7 +1519,7 @@ devbox_deinit_command() { # Remove the use-local-component file rm -f "$WORKING_HOME/.use-local-component" - echo "> DevBox deinitialization completed." + echo "==> DevBox deinitialization completed." } # :command.function @@ -1447,6 +1528,22 @@ devbox_start_command() { local COMPONENT="$(get_arg '--component')" local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" + if [[ "$FREELEAPS_ENDPOINT" == "all" ]]; then + export START_FRONTEND=true + export START_BACKEND=true + elif [[ "$FREELEAPS_ENDPOINT" == "frontend" ]]; then + export START_FRONTEND=true + export START_BACKEND=false + elif [[ "$FREELEAPS_ENDPOINT" == "backend" ]]; then + export START_FRONTEND=false + export START_BACKEND=true + else + # Default behavior can be adjusted if needed + export START_FRONTEND=false + export START_BACKEND=false + fi + + echo "FREELEAPS_ENDPOINT: $FREELEAPS_ENDPOINT, START_FRONTEND: $START_FRONTEND, START_BACKEND: $START_BACKEND" # Check if the DevBox container is running local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" @@ -1526,8 +1623,8 @@ devbox_start_command() { done - - if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then +# Check if $FREELEAPS_ENDPOINT is not empty and start the frontend and backend services +if [[ "$FREELEAPS_ENDPOINT" != "" ]]; 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 @@ -1541,119 +1638,137 @@ devbox_start_command() { 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 - -# Test backend and frontend services -echo "Testing backend and frontend services..." - -# Test the backend service -echo "Testing backend service..." -attempt=0 -max_attempts=10 -while [ \$attempt -lt \$max_attempts ]; do - http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") - if [ "\$http_code" -eq 200 ]; then - break + # 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 - attempt=\$((attempt+1)) - sleep 5 -done -if [ \$attempt -eq \$max_attempts ]; then - echo "ERROR: Backend service is not available after \$max_attempts attempts." - exit 1 + 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 + + # Check if the backend service is already running + SERVICE_API_ACCESS_PORT=\$(cat /home/devbox/.devbox-backend-port) + uvicorn freeleaps.webapi.main:app --reload --host 0.0.0.0 --port \$SERVICE_API_ACCESS_PORT > /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 + + # Test the backend service + echo "Testing backend service..." + + attempt=0 + max_attempts=10 + while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") + if [ "\$http_code" -eq 200 ]; then + break + fi + attempt=\$((attempt+1)) + sleep 5 + done + + if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Backend service is not available after \$max_attempts attempts." + exit 1 + fi + + echo "Backend service is available (HTTP \$http_code)" fi - # Start the frontend service +if [[ "${START_FRONTEND}" == "true" ]]; then -echo '============================================' -echo ' Start frontend service locally' -echo '============================================' -pushd /home/devbox/freeleaps/frontend + echo '============================================' + echo ' Start frontend service locally' + echo '============================================' + pushd /home/devbox/freeleaps/frontend -npm run dev > /home/devbox/logs/frontend.logs 2>&1 & -FRONTEND_PID=\$! + # Check if the frontend service is already running according to the package.json and pnpm-lock.yaml files timestamps + if [[ ! -d "node_modules" || "package.json" -nt "node_modules" || "pnpm-lock.yaml" -nt "node_modules" ]]; then + echo "==> Installing/Updating frontend dependencies..." -echo "\$FRONTEND_PID" > /home/devbox/.frontend.pid + # Clean up old dependencies + rm -rf node_modules -# 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 the frontend service - -WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) - -echo "Testing frontend service... PORT: \$WEB_APP_ACCESS_PORT" -attempt=0 -max_attempts=10 -while [ \$attempt -lt \$max_attempts ]; do - HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") - # Check HTTP Code 200 - if [ "\$HTTP_CODE" -eq 200 ]; then - echo "Frontend is available (HTTP \$HTTP_CODE)" - break - else - echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$HTTP_CODE). Waiting..." - attempt=\$((attempt+1)) - sleep 10 + # Install dependencies + pnpm install --prefer-offline --frozen-lockfile || { + echo "ERROR: Failed to install dependencies" + exit 1 + } fi -done -if [ \$attempt -eq \$max_attempts ]; then - echo "ERROR: Frontend service is not available after \$max_attempts attempts." - exit 1 -fi + npm run dev > /home/devbox/logs/frontend.logs 2>&1 & + FRONTEND_PID=\$! -echo "Backend and frontend services started successfully." + 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 the frontend service + WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) + + + echo "Testing frontend service... PORT: \$WEB_APP_ACCESS_PORT" + attempt=0 + max_attempts=10 + while [ \$attempt -lt \$max_attempts ]; do + HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") + echo "HTTP_CODE: \$HTTP_CODE" + # Check HTTP Code 200 + if [ "\$HTTP_CODE" -eq 200 ]; then + echo "Frontend is available (HTTP \$HTTP_CODE)" + break + else + echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$HTTP_CODE). Waiting..." + attempt=\$((attempt+1)) + sleep 10 + fi + done + + if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Frontend service is not available after \$max_attempts attempts." + exit 1 + fi + + +fi + +echo "Freeleaps services started successfully" EOF else echo "ERROR: DevBox container is not running." @@ -1831,6 +1946,21 @@ devbox_restart_command() { local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")" local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')" + if [[ "$FREELEAPS_ENDPOINT" == "all" ]]; then + export START_FRONTEND=true + export START_BACKEND=true + elif [[ "$FREELEAPS_ENDPOINT" == "frontend" ]]; then + export START_FRONTEND=true + export START_BACKEND=false + elif [[ "$FREELEAPS_ENDPOINT" == "backend" ]]; then + export START_FRONTEND=false + export START_BACKEND=true + else + # Default behavior can be adjusted if needed + export START_FRONTEND=false + export START_BACKEND=false + fi + # Check devbox container file path local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance" if [[ ! -f "$devbox_container_id_file_path" ]]; then @@ -1919,7 +2049,8 @@ devbox_restart_command() { esac done -if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then +# Check if $FREELEAPS_ENDPOINT is not empty and start the frontend and backend services +if [[ "$FREELEAPS_ENDPOINT" != "" ]]; 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 @@ -1930,119 +2061,138 @@ if [[ "$FREELEAPS_ENDPOINT" == "true" ]]; then 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 - -# Test backend and frontend services -echo "Testing backend and frontend services..." - -# Test the backend service -echo "Testing backend service..." -attempt=0 -max_attempts=10 -while [ \$attempt -lt \$max_attempts ]; do - http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") - if [ "\$http_code" -eq 200 ]; then - break + # 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 - attempt=\$((attempt+1)) - sleep 5 -done -if [ \$attempt -eq \$max_attempts ]; then - echo "ERROR: Backend service is not available after \$max_attempts attempts." - exit 1 -fi + echo '============================================' + echo ' Start to activate virtual environment' + echo '============================================' + source venv_t/bin/activate + source /home/devbox/freeleaps/apps/.env - -# 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 the frontend service -WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) - -echo "Testing frontend service..." -attempt=0 -max_attempts=10 -while [ \$attempt -lt \$max_attempts ]; do - http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") - if [ "\$http_code" -eq 200 ]; then - echo "Frontend service is available (HTTP \$http_code)" - break + # Verify the virtual environment is activated + if [[ "\$VIRTUAL_ENV" != "" ]]; then + echo "Virtual environment activate: \$VIRTUAL_ENV" else - echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$http_code). Waiting..." - attempt=\$((attempt+1)) - sleep 10 + echo "ERROR: The virtual environment cannot be startup \$VIRTUAL_ENV" + exit 1 fi -done -if [ \$attempt -eq \$max_attempts ]; then - echo "ERROR: Frontend service is not available after \$max_attempts attempts." - exit 1 + # Check if the backend service is already running + SERVICE_API_ACCESS_PORT=\$(cat /home/devbox/.devbox-backend-port) + uvicorn freeleaps.webapi.main:app --reload --host 0.0.0.0 --port \$SERVICE_API_ACCESS_PORT > /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 + + # Test backend and frontend services + echo "Testing backend and frontend services..." + + # Test the backend service + echo "Testing backend service..." + attempt=0 + max_attempts=10 + while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$SERVICE_API_ACCESS_PORT/docs") + if [ "\$http_code" -eq 200 ]; then + break + fi + attempt=\$((attempt+1)) + sleep 5 + done + + if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Backend service is not available after \$max_attempts attempts." + exit 1 + fi + +fi + + +if [[ "${START_FRONTEND}" == "true" ]]; then + # 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 the frontend service + WEB_APP_ACCESS_PORT=\$(cat /home/devbox/.devbox-frontend-port) + + # Check if the frontend service is already running according to the package.json and pnpm-lock.yaml files timestamps + if [[ ! -d "node_modules" || "package.json" -nt "node_modules" || "pnpm-lock.yaml" -nt "node_modules" ]]; then + echo "==> Installing/Updating frontend dependencies..." + + # Clean up old dependencies + rm -rf node_modules + + # Install dependencies + pnpm install --prefer-offline --frozen-lockfile || { + echo "ERROR: Failed to install dependencies" + exit 1 + } + fi + + echo "Testing frontend service..." + attempt=0 + max_attempts=10 + while [ \$attempt -lt \$max_attempts ]; do + http_code=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:\$WEB_APP_ACCESS_PORT/") + if [ "\$http_code" -eq 200 ]; then + echo "Frontend service is available (HTTP \$http_code)" + break + else + echo "Attempt \$((attempt+1)): Frontend not available (HTTP \$http_code). Waiting..." + attempt=\$((attempt+1)) + sleep 10 + fi + done + + if [ \$attempt -eq \$max_attempts ]; then + echo "ERROR: Frontend service is not available after \$max_attempts attempts." + exit 1 + fi fi -echo "Backend and frontend services started successfully." +echo "Freeleaps services started successfully" EOF fi @@ -2253,7 +2403,7 @@ devbox_init_parse_requirements() { fi ;; # :flag.case - --devbox-image-repo | -R) + --devbox-image-repo | -D) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-image-repo' "$2" @@ -2275,7 +2425,7 @@ devbox_init_parse_requirements() { fi ;; # :flag.case - --devbox-image-tag | -T) + --devbox-image-tag | -g) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devbox-image-tag' "$2" @@ -2318,6 +2468,15 @@ devbox_init_parse_requirements() { exit 1 fi ;; + --use-custom-repository | -c) + if [[ -n ${2+x} ]]; then + add_arg '--use-custom-repository' "$2" + shift 2 + else + printf "%s\n" "--use-custom-repository requires an argument: --use-custom-repository USE_CUSTOM_REPOSITORY" >&2 + exit 1 + fi + ;; # :flag.case --use-local-component | -u) if [[ -n ${2+x} ]]; then @@ -2329,7 +2488,7 @@ devbox_init_parse_requirements() { fi ;; # :flag.case - --devsvc-image-repo | -D) + --devsvc-image-repo | -t) # :flag.case_arg if [[ -n ${2+x} ]]; then add_arg '--devsvc-image-repo' "$2" @@ -2483,7 +2642,7 @@ devbox_init_parse_requirements() { fi ;; # :flag.case - --chat-image-repo | -B) + --chat-image-repo | -R) if [[ -n ${2+x} ]]; then add_arg '--chat-image-repo' "$2" shift 2 @@ -2540,6 +2699,22 @@ devbox_init_parse_requirements() { add_arg '--arch' "auto" fi + # :command.default_assignments + current_arch=$(get_arg '--arch') + if [ "$current_arch" = "auto" ]; then + detected_arch=$(uname -m) + if [ "$detected_arch" = "x86_64" ]; then + current_arch="amd64" + elif [ "$detected_arch" = "aarch64" ]; then + current_arch="arm64" + else + echo "ERROR: Unsupported architecture detected: $detected_arch" + exit 1 + fi + # Update the arch argument accordingly + add_arg '--arch' "$current_arch" + fi + if [ -z "$(get_arg '--devbox-container-name')" ]; then add_arg '--devbox-container-name' "devbox" fi @@ -2569,19 +2744,55 @@ devbox_init_parse_requirements() { fi if [ -z "$(get_arg '--devsvc-image-tag')" ]; then - add_arg '--devsvc-image-tag' "latest-linux-arm64" + if [ "$current_arch" == "arm64" ]; then + add_arg '--devsvc-image-tag' "latest-linux-arm64" + else + add_arg '--devsvc-image-tag' "latest-linux-amd64" + fi fi if [ -z "$(get_arg '--content-image-tag')" ]; then - add_arg '--content-image-tag' "latest-linux-arm64" + if [ "$current_arch" == "arm64" ]; then + add_arg '--content-image-tag' "latest-linux-arm64" + else + add_arg '--content-image-tag' "latest-linux-amd64" + fi fi if [ -z "$(get_arg '--central_storage-image-tag')" ]; then - add_arg '--central_storage-image-tag' "latest-linux-arm64" + if [ "$current_arch" == "arm64" ]; then + add_arg '--central_storage-image-tag' "latest-linux-arm64" + else + add_arg '--central_storage-image-tag' "latest-linux-amd64" + fi + fi + + if [ -z "$(get_arg '--chat-image-tag')" ]; then + if [ "$current_arch" == "arm64" ]; then + add_arg '--chat-image-tag' "latest-linux-arm64" + else + add_arg '--chat-image-tag' "latest-linux-amd64" + fi + fi + + if [ -z "$(get_arg '--notification-image-tag')" ]; then + if [ "$current_arch" == "arm64" ]; then + add_arg '--notification-image-tag' "latest-linux-arm64" + else + add_arg '--notification-image-tag' "latest-linux-amd64" + fi fi if [ -z "$(get_arg '--authentication-image-tag')" ]; then - add_arg '--authentication-image-tag' "latest-linux-arm64" + if [ "$current_arch" == "arm64" ]; then + add_arg '--authentication-image-tag' "latest-linux-arm64" + else + add_arg '--authentication-image-tag' "latest-linux-amd64" + fi + fi + + if [ -z "$(get_arg '--use-custom-repository')" ]; then + add_arg '--use-custom-repository' "" fi if [ -z "$(get_arg '--working-home')" ]; then @@ -2661,6 +2872,19 @@ devbox_deinit_parse_requirements() { fi ;; + --clear-all | -a) + # :flag.case_arg + if [[ -n ${2+x} ]]; then + add_arg '--clear-all' "$2" + + shift + shift + else + printf "%s\n" "--clear-all requires an argument: --clear-all CLEAR_ALL" >&2 + exit 1 + fi + ;; + -?*) printf "invalid option: %s\n" "$key" >&2 exit 1 @@ -2687,6 +2911,9 @@ devbox_deinit_parse_requirements() { if [ -z "$(get_arg '--clear-repo')" ]; then add_arg '--clear-repo' "false" fi + if [ -z "$(get_arg '--clear-all')" ]; then + add_arg '--clear-all' "false" + fi } @@ -2762,7 +2989,7 @@ devbox_start_parse_requirements() { # :command.default_assignments if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then - add_arg '--freeleaps-endpoint' "false" + add_arg '--freeleaps-endpoint' "" fi } @@ -2931,7 +3158,7 @@ devbox_restart_parse_requirements() { shift shift else - printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint FREELEAPS_ENDPOINT" >&2 + printf "%s\n" "--freeleaps-endpoint requires an argument: --freeleaps-endpoint all/backend/frontend" >&2 exit 1 fi ;; @@ -2954,7 +3181,7 @@ devbox_restart_parse_requirements() { # :command.default_assignments if [ -z "$(get_arg '--freeleaps-endpoint')" ]; then - add_arg '--freeleaps-endpoint' "false" + add_arg '--freeleaps-endpoint' "" fi }