freeleaps-pub/devbox/devbox.local/cli/devbox

3159 lines
100 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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
}
devbox_init_guidance() {
printf "Welcome to DevBox CLI!\n\n"
# if $1 is empty, then ask user select a choice or match user input $1 action to be product_id
if [[ -z $1 ]]; then
# Guide user to select use freeleaps env or custom repository for source code
printf "Please choose an option:\n"
printf " 1. Use Freeleaps.com repository\n"
printf " 2. Use custom repository\n"
read -p "Enter your choice (1 or 2): " choice
else
echo "Your will start with init product $1 develop environment"
product_id=$1
case "$product_id" in
freeleaps)
choice=1
;;
*)
choice=2
;;
esac
fi
case "$choice" in
1)
freeleaps_username=""
freeleaps_password=""
use_local_component=false
use_custom_repository=""
freeleaps_components=""
# Ask user for Freeleaps.com username and password
read -p "Enter your Freeleaps.com username: " freeleaps_username
read -s -p "Enter your Freeleaps.com password: " freeleaps_password
echo
read -p "Use local component dev environment? (y/n): " choose_local_component
if [[ $choose_local_component == "y" ]]; then
use_local_component=true
fi
add_arg "--freeleaps-username" "$freeleaps_username"
add_arg "--freeleaps-password" "$freeleaps_password"
add_arg "--use-local-component" "$use_local_component"
add_arg "--use-custom-repository" "$use_custom_repository"
;;
2)
# Ask user for Freeleaps.com username and password
read -p "Enter your Freeleaps.com username: " freeleaps_username
read -s -p "Enter your Freeleaps.com password: " freeleaps_password
echo
add_arg "--freeleaps-username" "$freeleaps_username"
add_arg "--freeleaps-password" "$freeleaps_password"
ENCODING_FREELEAPS_USERNAME=$(url_encode "$freeleaps_username")
ENCODEING_FREELEAPS_PASSWORD=$(url_encode "$freeleaps_password")
use_custom_repository="https://$ENCODING_FREELEAPS_USERNAME:$ENCODEING_FREELEAPS_PASSWORD@freeleaps.com:3443/products/$product_id.git"
# Test the repository connection
if ! git ls-remote "$use_custom_repository"; then
printf "Failed to connect to the repository. Please check your username and password.\n"
exit 1
fi
printf "Repository connection successful.\n"
add_arg "--use-custom-repository" "$use_custom_repository"
;;
*)
printf "Invalid choice. Exiting.\n"
exit 1
;;
esac
}
# :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 -l [Optional] : Check if using local component or online dev environment. Default: false.\n"
printf " --use-custom-repository -c [Optional] : Specifies the custom git repository for source code.\n"
printf " --freeleaps-components -m [Optional] : Specifies the Freeleaps.com components to start in the DevBox container.\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 " --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"
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"
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
}
# :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, devsvc, content, central_storage, notification, chat, authentication).\n\n"
printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint backend & frontend 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, notification, chat, 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, content, central_storage, notification, chat, authentication).\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., devbox, devsvc, content, central_storage, notification, chat, authentication).\n"
printf " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com backend & frontend to restart in the DevBox container.\n"
printf " --force -f [Optional] : 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
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 =~ $regex ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ $regex2 ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ $regex3 ]]; 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 "==> Installing Docker..."
# Check if Docker is already installed
if command -v docker &>/dev/null; then
echo "==> Docker is already installed."
return 0
fi
# Install Docker using the official script
if command -v curl &>/dev/null || command -v wget &>/dev/null; then
if command -v curl &>/dev/null; then
curl -fsSL https://get.docker.com -o get-docker.sh
elif command -v wget &>/dev/null; then
wget -qO get-docker.sh https://get.docker.com
fi
if [ -f get-docker.sh ]; then
sudo sh get-docker.sh
rm -f get-docker.sh
return 0
fi
fi
# Install Docker using package manager
if command -v apt-get &>/dev/null; then
sudo apt-get update
sudo apt-get install -y docker.io
return 0
fi
if command -v yum &>/dev/null; then
sudo yum install -y docker
sudo systemctl start docker
sudo systemctl enable docker
return 0
fi
if command -v dnf &>/dev/null; then
sudo dnf install -y docker
sudo systemctl start docker
sudo systemctl enable docker
return 0
fi
if command -v zypper &>/dev/null; then
sudo zypper install -y docker
sudo systemctl start docker
sudo systemctl enable docker
return 0
fi
if command -v apk &>/dev/null; then
sudo apk add docker
sudo rc-update add docker boot
sudo service docker start
return 0
fi
if command -v pacman &>/dev/null; then
sudo pacman -S --noconfirm docker
sudo systemctl start docker
sudo systemctl enable docker
return 0
fi
if command -v brew &>/dev/null; then
brew install docker
return 0
fi
if command -v snap &>/dev/null; then
sudo snap install docker
return 0
fi
echo "ERROR: Unable to install Docker automatically. Please install Docker manually."
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
}
build_local_image() {
local dockerfile_path="$1"
echo "==> [Build] use Dockerfile: $(grep '^FROM' "$dockerfile_path")"
# Check if the image already exists
docker rmi -f $devbox_full_image 2>/dev/null || true
# Build the image
if ! docker buildx build \
--platform linux/amd64 \
--build-arg BUILDARCH="x86-64-v3" \
--no-cache \
-t $devbox_full_image \
-f "$dockerfile_path" . 2>&1 | tee "$WORKING_HOME/build.log"; then
echo "ERROR: Image build failed: $WORKING_HOME/build.log"
exit 1
fi
# Check if the image is built successfully
if ! docker inspect $devbox_full_image | grep -q 'amd64'; then
echo "ERROR:"
exit 1
fi
}
# Define the local components and their corresponding ports
local_components_ports_keys=("devsvc" "notification" "content" "central_storage" "chat" "authentication")
local_components_ports_values=("8007" "8003" "8013" "8005" "8012" "8004")
# used for repository username and password encoding
url_encode() {
echo "$1" | sed 's/@/%40/g'
}
# 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"
}
# Build the local image
build_local_image() {
local dockerfile_path="$1"
echo "==> [BUILD] Building local image..."
docker buildx build \
--platform linux/amd64 \
--build-arg BUILDARCH="x86-64-v3" \
-t $devbox_full_image \
-f "$dockerfile_path" .
}
# :command.command_functions
# :command.function
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 FREELEAPS_COMPONENTS="$args_freeleaps_components" # --freeleaps-components
local USE_CUSTOM_REPOSITORY="$args_use_custom_repository" # --use-custom-repository
# --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 FREELEAPS_COMPONENTS="$(get_arg '--freeleaps-components')"
local USE_CUSTOM_REPOSITORY="$(get_arg '--use-custom-repository')"
local FORCE_INIT="$(get_arg '--force')"
local is_pull_all_components=true
local components=("devsvc" "notification" "content" "central_storage" "chat" "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
# split FREELEAPS_COMPONENTS
freeleaps_components=()
if [[ -n "$FREELEAPS_COMPONENTS" ]]; then
freeleaps_components=($(echo "$FREELEAPS_COMPONENTS" | tr ',' ' '))
fi
# Check if freeleaps_components is not empty, then check if freeleaps_components is valid component
if [ ${#freeleaps_components[@]} -gt 0 ]; then
for component in "${freeleaps_components[@]}"; do
found=false
for valid_component in "${components[@]}"; do
if [ "$component" = "$valid_component" ]; then
found=true
break
fi
done
if [ "$found" = false ]; then
echo "ERROR: Invalid component: $component"
exit 1
fi
done
start_components=("${freeleaps_components[@]}")
else
start_components=("${components[@]}")
fi
echo "init arch value is : $ARCH "
# If is_pull_all_components is true, then pull all components
if [[ "$is_pull_all_components" == true ]]; then
start_components=("${components[@]}")
echo "==> Pulling all components..."
echo "==> start components: ${start_components[@]}"
fi
# Remove duplicated components
start_components=($(echo "${start_components[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
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 " FREELEAPS_COMPONENTS= ${start_components[@]}"
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
ARCH_MICRO=""
if [[ "$ARCH" == "auto" ]]; then
ARCH="$(uname -m)"
if [[ "$ARCH" == "x86_64" ]]; then
# Check if the CPU supports AVX2
if grep -q avx2 /proc/cpuinfo; then
ARCH="amd64"
ARCH_MICRO="v3"
echo "==> Detected AMD64 architecture."
else
ARCH="amd64"
fi
elif [[ "$ARCH" == "aarch64" ]]; then
ARCH="arm64"
fi
fi
component_tag="latest-linux-arm64"
if [[ "$ARCH" == "amd64" ]]; then
component_tag="latest-linux-amd64"
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
# -------------------------------------------------------------------
# 3.1.1.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
sudo usermod -aG docker $USER
sudo apt-get update -y
sudo apt-get install docker-compose -y
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(sampleping docker.com)
if ! ping -c 1 docker.com &>/dev/null; then
echo "ERROR: Network unreachable."
exit 1
fi
# 3.5 Check if the user has permission to write to WORKING_HOME
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
local devbox_full_image="${DEVBOX_REPO}/${DEVBOX_IMAGE}:${DEVBOX_TAG}"
# Check local and remote version. User doesnt 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
# 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"
# Check if use custom repository
if [[ -n "$USE_CUSTOM_REPOSITORY" ]]; then
echo "==> [INIT] Using custom repository."
elif [[ -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
DOVBOX_CLI_DIR=$(pwd)
ECHO_USE_CUSTOM_REPOSITORY=""
# 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
fi
popd > /dev/null
fi
else
if ! echo "$USE_CUSTOM_REPOSITORY" | grep -Eq '^(https:\/\/|git@|git:\/\/|file:\/\/\/)[^ ]+\.git$'; then
echo "ERROR: Invalid custom repository URL. Please provide a valid URL."
exit 1
fi
# Check if the custom repository is a git repository
# 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
ECHO_USE_CUSTOM_REPOSITORY=$(echo "$USE_CUSTOM_REPOSITORY" | sed 's/\(https:\/\/[^:]*\):[^@]*@/\1:****@/')
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: $ECHO_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: $ECHO_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
# -------------------------------------------------------------------
# 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"
# 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
# Remove the ':' and password from USE_CUSTOM_REPOSITORY
echo
echo "==========================================================="
echo "==> [INIT] Custom repository initialization completed."
echo "==> Custom repository is located at: ${WORKING_HOME}/${CUSTOM_FOLDER_NAME}"
echo "==> Custom repository URL: $ECHO_USE_CUSTOM_REPOSITORY"
echo "==> Custom repository is ready for use."
echo "==========================================================="
echo
exit 0
fi
# If USE_LOCAL_COMPONENT is true, then use local components
if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then
echo ' ===> Using local components for Freeleaps services.'
export DEVSVC_IMAGE_TAG="$component_tag"
export CONTENT_IMAGE_TAG="$component_tag"
export CENTRAL_STORAGE_IMAGE_TAG="$component_tag"
export AUTHENTICATION_IMAGE_TAG="$component_tag"
export NOTIFICATION_IMAGE_TAG="$component_tag"
export CHAT_IMAGE_TAG="$component_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
# Echo OWNER_GROUP
echo "OWNER_GROUP: $OWNER_GROUP"
# Copy gitea data to the gitea container
GITEA_HOST_DIR="${WORKING_HOME}/freeleaps2-gitea"
# Remove existing data directories
sudo rm -rf ${GITEA_HOST_DIR}/git
sudo rm -rf ${GITEA_HOST_DIR}/gitea
sudo rm -rf ${GITEA_HOST_DIR}/ssh
# Move data directories to the gitea container
sudo mv data/git ${GITEA_HOST_DIR}/
sudo mv data/gitea ${GITEA_HOST_DIR}/
sudo mv data/ssh ${GITEA_HOST_DIR}/
# Change the owner group of the gitea data directories
sudo chown -R "${OWNER_GROUP}" ${GITEA_HOST_DIR}
echo "Gitea data copying is done"
# Check if gitea data directories exist in the gitea container
if [[ ! -d "${GITEA_HOST_DIR}/gitea" ]]; then
echo "ERROR: Failed to copy gitea data."
exit 1
fi
mkdir -p ${WORKING_HOME}/logs
# for each component create log directory
for component in "${start_components[@]}"; do
if [[ ! -d "${WORKING_HOME}/logs/${component}" ]]; then
mkdir -p "${WORKING_HOME}/logs/${component}"
fi
done
# Start Gitea, MongoDB, RabbitMQ and other components containers
echo "===> start Gitea, MongoDB, RabbitMQ and other components containers"
docker-compose -f docker-compose.dev.arm64.new.yaml up -d mongodb rabbitmq gitea redis "${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"
redis_container_id=$(docker ps --no-trunc -a --filter "name=^freeleaps2-redis$" --format "{{.ID}}")
echo "$redis_container_id" > "$WORKING_HOME/.redis-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"
# Get the owner group of the WORKING_HOME
if [[ "$(uname)" == "Darwin" ]]; then
OWNER_GROUP=$(stat -f "%Su:%Sg" "${WORKING_HOME}")
else
OWNER_GROUP=$(stat -c "%U:%G" "${WORKING_HOME}")
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
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 redis
# 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"
redis_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-redis\$")
echo "$redis_container_id" > "$WORKING_HOME/.redis-instance"
fi
# 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
# Run banckend service and frontend service in the container
docker exec -i "$DEVBOX_NAME" bash <<EOF
# Set environment variables
export FREELEAPS_USERNAME="${FREELEAPS_USERNAME}"
export FREELEAPS_PASSWORD="${FREELEAPS_PASSWORD}"
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
DEFAULT_IP=\$(ip route | grep default | sed -n 's/.*default via \([^ ]*\).*/\1/p')
if [[ \$USE_LOCAL_COMPONENT_VAL == true ]]; then
echo "==> 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_CHAT_ENDPOINT=http://freeleaps-chat:8012/api/chat/
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 backend service locally'
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
rm -rf /home/devbox/freeleaps/apps/backend_env.sh || true
echo "WebAPI service started successfully"
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
pushd /home/devbox/freeleaps
git config --global --add safe.directory /home/devbox/freeleaps
git reset --hard
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 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 " CLEAR_ALL = $CLEAR_ALL"
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
if [[ -f "$WORKING_HOME/.redis-instance" ]]; then
local redis_container_id
redis_container_id=$(cat "$WORKING_HOME/.redis-instance")
echo "==> Stopping and removing Redis container: $redis_container_id"
docker stop "$redis_container_id" &>/dev/null || true
docker rm "$redis_container_id" &>/dev/null || true
rm -f "$WORKING_HOME/.redis-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" "chat" "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
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"
if [[ -d "$WORKING_HOME" ]]; then
sudo chown -R $(whoami):$(whoami) "$WORKING_HOME"
rm -rf "$WORKING_HOME" 2>/dev/null || true
rmdir "$WORKING_HOME" 2>/dev/null || true
fi
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 "="
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')"
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"
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" "chat" "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" == "chat" || "$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" | "chat" | "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
# 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
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 <<EOF
# Check if start backend service
if [[ "${START_BACKEND}" == "true" ]]; then
# Start the backend service
echo '============================================'
echo ' Start backend service locally'
echo '============================================'
pushd /home/devbox/freeleaps/apps
# 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
# 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 "==> Starting frontend service..."
baseline_file=\$(mktemp)
echo "==> Creating a baseline file for the frontend service..."
git status -s > "\$baseline_file"
echo "==> Baseline file created: \$baseline_file"
# 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 || {
echo "ERROR: Failed to install dependencies"
exit 1
}
fi
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... 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
current_file=\$(mktemp)
git status -s > "\$current_file"
echo "==> Checking for modified files in the frontend service..."
while read -r line; do
# Print the file name
echo "\$line"
file=\$(echo "\$line" | awk '{print \$2}')
echo "File: \$file"
# Check if the file is not in the baseline file
if ! grep -q "[[:space:]]\$file\$" "\$baseline_file"; then
echo "==> File \$file has been modified. Resetting..."
git reset HEAD "\$file"
git checkout -- "\$file"
fi
done < \$current_file
# Remove the temporary files
rm "\$baseline_file" "\$current_file"
fi
echo "Freeleaps 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" "chat" "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" | "chat" | "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" "chat" "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" | "chat" | "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')"
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
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" "chat" "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" == "chat" || "$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" | "chat" | "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" | "chat" | "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
# 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
break
fi
echo -n "-"
sleep 1
done
# Start the backend and frontend services
docker exec -i "$devbox_container_id" bash <<EOF
if [[ "${START_BACKEND}" == "true" ]]; then
# Start the backend service
echo '============================================'
echo ' Start backend service locally'
echo '============================================'
pushd /home/devbox/freeleaps/apps
# 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
# 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 "==> Starting frontend service..."
baseline_file=\$(mktemp)
echo "==> Creating a baseline file for the frontend service..."
git status -s > "\$baseline_file"
echo "==> Baseline file created: \$baseline_file"
# 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 || {
echo "ERROR: Failed to install dependencies"
exit 1
}
fi
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... 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/")
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
current_file=\$(mktemp)
git status -s > "\$current_file"
echo "==> Checking for modified files in the frontend service..."
while read -r line; do
# Print the file name
echo "\$line"
file=\$(echo "\$line" | awk '{print \$2}')
echo "File: \$file"
# Check if the file is not in the baseline file
if ! grep -q "[[:space:]]\$file\$" "\$baseline_file"; then
echo "==> File \$file has been modified. Resetting..."
git reset HEAD "\$file"
git checkout -- "\$file"
fi
done < \$current_file
# Remove the temporary files
rm "\$baseline_file" "\$current_file"
fi
echo "Freeleaps 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 $#
;;
"")
devbox_init_guidance >&2
action="init"
shift
devbox_init_parse_requirements "$@"
shift $#
;;
*)
# pass * parameter to devbox_init_guidance
devbox_init_guidance $action >&2
action="init"
shift
devbox_init_parse_requirements "$@"
shift $#
;;
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
;;
--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 | -l)
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
;;
--freeleaps-components | -m)
if [[ -n ${2+x} ]]; then
add_arg '--freeleaps-components' "$2"
shift 2
else
printf "%s\n" "--freeleaps-components requires an argument: --freeleaps-components FREELEAPS_COMPONENTS" >&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
# :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
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
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
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
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
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
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
;;
--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
;;
*)
# :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
if [ -z "$(get_arg '--clear-all')" ]; then
add_arg '--clear-all' "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' ""
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 all/backend/frontend" >&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' ""
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 "$@"