freeleaps-pub/devbox/cli/devbox
2025-04-07 17:06:33 +08:00

3795 lines
131 KiB
Bash
Executable File
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
# All components that can be started in the DevBox container. [:COMPONENT_SETTINGS]
DEVBOX_COMPONENTS=("devsvc" "notification" "content" "central_storage" "chat" "authentication")
log_info() {
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $*"
}
log_warn() {
echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') $*"
}
log_error() {
echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2
}
# :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:]'
}
exit_with_message() {
local message="$1"
local code="${2:-1}"
echo
echo "============================================================================"
echo
if [[ $code -eq 0 ]]; then
echo "[INFO] $message"
else
echo "[ERROR] $message" >&2
fi
echo
echo "============================================================================"
echo
exit $code
}
detect_os() {
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "darwin"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
echo "linux"
elif grep -qi microsoft /proc/version; then
echo "wsl2"
else
echo "unknown"
fi
}
# 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
log_info "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)
# Check if product_id is empty
if [[ -z $product_id ]]; then
# Ask user for product_id
read -p "Enter your product_id: " product_id
if [[ -z $product_id ]]; then
exit_with_message "Product ID is required, please provide a valid product ID." 1
fi
fi
# 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@gitea.freeleaps.mathmast.com/products/$product_id.git"
# Test the repository connection
if ! git ls-remote "$use_custom_repository"; then
exit_with_message " Failed to connect to the repository. Please check your username and password." 1
fi
printf "Repository connection successfully.\n"
add_arg "--use-custom-repository" "$use_custom_repository"
;;
*)
exit_with_message "Invalid choice. Please enter 1 or 2." 1
;;
esac
}
# :command.usage
devbox_usage() {
printf "Command\n"
printf " devbox : DevBox Command Line Tool for managing the local development environment.\n\n"
printf "Usage\n"
printf " devbox : Interactive mode to initialize development environment\n"
printf " devbox freeleaps : Initialize Freeleaps.com development environment\n"
printf " devbox <product_id> : Initialize specific product development environment\n\n"
printf "Arguments\n"
printf " COMMAND [Required] : Specify the command to execute.\n"
printf " init, i : Initialize the local development environment.\n"
printf " deinit, d : De-initialize the local development environment.\n"
printf " start, s : Start services in the local development environment.\n"
printf " stop, p : Stop services in the local development environment.\n"
printf " status, t : Display status of services in the local environment.\n"
printf " restart, r : Restart services in the local environment.\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 " Initialize development environment interactively:\n"
printf " devbox\n\n"
printf " Initialize Freeleaps.com development environment:\n"
printf " devbox freeleaps\n\n"
printf " Initialize specific product development environment:\n"
printf " devbox <product_id>\n\n"
printf " Initialize development environment with command:\n"
printf " devbox init\n\n"
printf " Display help for the 'init' command:\n"
printf " devbox init --help\n\n"
printf " Start all services:\n"
printf " devbox start\n\n"
printf " Start specific service:\n"
printf " devbox start --component=backend\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 -q [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 " --freeleaps-endpoint -e [Optional] : Specifies the Freeleaps.com endpoint backend & frontend to stop 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 " stop freeleaps backend service:\n"
printf " devbox stop --freeleaps-endpoint=backend\n"
printf " stop all services:\n"
printf " devbox stop --freeleaps-endpoint=all\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=content\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)
log_info "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
log_info "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
log_info "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
log_info "- \$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
log_info "environment variables:"
for name in $sorted_names; do
# Look up the value based on the name
log_info "- \$${name} = ${!name:-}"
done
fi
}
install_docker() {
log_info "Installing Docker..."
# Check if Docker is already installed
if command -v docker &>/dev/null; then
log_info "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
log_info "ERROR: Unable to install Docker automatically. Please install Docker manually."
return 1
}
check_docker_running() {
log_info "Checking if Docker service is running..."
# if Docker CLI is installed and Docker daemon is running
if docker info >/dev/null 2>&1; then
log_info "Docker is running."
return 0
fi
# if running on WSL, check for Docker socket
if grep -qi microsoft /proc/version; then
log_info "Detected WSL environment. Verifying /var/run/docker.sock..."
if [ -S /var/run/docker.sock ]; then
log_info "Docker socket found. Docker should be available via Docker Desktop."
return 0
else
log_error "Docker socket not found in WSL environment."
return 1
fi
fi
log_info "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
log_info "Starting Docker with systemctl..."
sudo systemctl start docker && log_info "Docker started successfully." && return 0
fi
fi
if command -v service &>/dev/null; then
if service --status-all | grep -q "docker"; then
log_info "Starting Docker with service..."
sudo service docker start && log_info "Docker started successfully." && return 0
fi
fi
if command -v snap &>/dev/null && snap list | grep -q "docker"; then
log_info "Starting Docker with snap..."
sudo snap start docker && log_info "Docker started successfully." && return 0
fi
log_error "Unable to start Docker automatically. Please start it manually."
return 1
}
build_local_image() {
local dockerfile_path="$1"
log_info "[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
exit_with_message " Image build failed, please check the log file: $WORKING_HOME/build.log" 1
fi
# Check if the image is built successfully
if ! docker inspect $devbox_full_image | grep -q 'amd64'; then
exit_with_message " Image build failed, please check the log file: $WORKING_HOME/build.log" 1
fi
}
# used for repository username and password encoding
url_encode() {
echo "$1" | sed 's/@/%40/g'
}
###############################################
# Initialize the development environment
###############################################
init_compile_env() {
# Update for export environments []
docker exec -i "$DEVBOX_NAME" bash <<EOF
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Starting DevBox initialization..."
# Export environment variables
export WORKING_HOME="${WORKING_HOME}"
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}"
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') USE_LOCAL_COMPONENT_VAL: ${USE_LOCAL_COMPONENT_VAL}"
# Check if the working home directory exists, if not, create it. [:COMPONENT_SETTINGS]
if [[ "$USE_LOCAL_COMPONENT_VAL" == "true" ]]; then
# Local component environment variables
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Use local component dev environment."
cat << 'EOFinner' > /home/devbox/freeleaps/apps/.env
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 REDIS_URL=redis://freeleaps2-redis:6379/0
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://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
export VITE_PROXY_WEBSOCKET_CHAT_URL=ws://localhost:8012
export VITE_PROXY_API_CHAT_URL=http://localhost:8012
EOFinner
# Update set VITE_PROXY_WEBSOCKET_CHAT_URL and VITE_PROXY_API_CHAT_URL in frontend/.env.development
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Update VITE_PROXY_WEBSOCKET_CHAT_URL and VITE_PROXY_API_CHAT_URL in frontend/.env.development"
sed -i "s|VITE_PROXY_WEBSOCKET_CHAT_URL=.*|VITE_PROXY_WEBSOCKET_CHAT_URL=ws://chat:8012|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i "s|VITE_PROXY_API_CHAT_URL=.*|VITE_PROXY_API_CHAT_URL=http://chat:8012|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
else
# Online component environment variables
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Use online component dev environment."
cat << 'EOFinner' > /home/devbox/freeleaps/apps/.env
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
export REDIS_URL=redis://freeleaps2-redis:6379/0
export VITE_PROXY_WEBSOCKET_CHAT_URL=wss://freeleaps-alpha.com
export VITE_PROXY_API_CHAT_URL=https://freeleaps-alpha.com
EOFinner
# Update set VITE_PROXY_WEBSOCKET_CHAT_URL and VITE_PROXY_API_CHAT_URL in frontend/.env.development
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Update VITE_PROXY_WEBSOCKET_CHAT_URL and VITE_PROXY_API_CHAT_URL in frontend/.env.development"
sed -i "s|VITE_PROXY_WEBSOCKET_CHAT_URL=.*|VITE_PROXY_WEBSOCKET_CHAT_URL=wss://freeleaps-alpha.com|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i "s|VITE_PROXY_API_CHAT_URL=.*|VITE_PROXY_API_CHAT_URL=https://freeleaps-alpha.com|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Online component dev environment variables set."
fi
if true ; then
# Git configuration to skip worktree for .env file
pushd /home/devbox/freeleaps > /dev/null
git config --global core.sparseCheckout true
git config --global --add safe.directory /home/devbox/freeleaps
git update-index --skip-worktree /home/devbox/freeleaps/frontend/freeleaps/.env.development
popd > /dev/null
# Load the environment variables
source /home/devbox/freeleaps/apps/.env
# Create the logs directory if it does not exist
mkdir -p /home/devbox/logs
# Install the net-tools package for ifconfig
sudo apt install net-tools -y
#####################################
# Initialize the backend environment, including Python3.11 and venv
#####################################
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Check Python3.11 environment..."
sudo apt update
sudo apt install python3.11 python3.11-venv -y
if ! command -v python3.11 &>/dev/null; then
echo
echo "============================================"
echo
echo "[ERROR] Python3.11 is failed to install, please check the log."
echo
echo "============================================"
echo
exit 1
fi
echo " [INIT] Upgrade pip and ensurepip..."
python3.11 -m ensurepip --upgrade
python3.11 -m pip install --upgrade pip
# If the venv_t directory does not exist, create it
pushd /home/devbox/freeleaps/apps > /dev/null
if [ ! -d "venv_t" ]; then
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Create Python3.11 virtual environment..."
python3.11 -m venv venv_t || { echo "[ERROR] Python3.11 virtual environment creation failed."; exit 1; }
sleep 5
fi
popd > /dev/null
# Install pipreqs for generating requirements.txt
python3.11 -m pip install pipreqs
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Backend environment initialization completed."
#####################################
# Initialize the frontend environment, including Node.js and npm
#####################################
pushd /home/devbox/freeleaps/frontend > /dev/null
npm update
# 1⃣ Install pnpm globally
npm install -g pnpm
# 2⃣ Verify installation
pnpm --version
# 3⃣ Clean up old dependencies
if [ -f "pnpm-lock.yaml" ]; then
cp pnpm-lock.yaml /tmp/pnpm-lock.yaml.bak
fi
# Remove node_modules directory
rm -rf node_modules
# 4⃣ Install dependencies
pnpm store prune
# 4⃣ Install dependencies (ensuring lockfile updates)
pnpm install --no-frozen-lockfile \\
--shamefully-hoist \\
--link-workspace-packages false \\
--store-dir /home/tmp/.pnpm-store
# 4⃣ Build the frontend
pnpm run build
popd > /dev/null
fi
EOF
}
stop_backend_service() {
echo "[BACKEND] $(date '+%Y-%m-%d %H:%M:%S') Stopping backend service..."
devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
DEVBOX_NAME=$(cat "$devbox_container_id_file_path")
docker exec -i "$DEVBOX_NAME" bash <<EOF
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Stopping backend service..."
if [ -f /home/devbox/.backend.pid ]; then
BACKEND_PID=\$(cat /home/devbox/.backend.pid)
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Killing backend service PID: \$BACKEND_PID"
kill -9 \$BACKEND_PID
rm -f /home/devbox/.backend.pid
else
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Backend service is not running."
fi
EOF
}
stop_frontend_service() {
devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
DEVBOX_NAME=$(cat "$devbox_container_id_file_path")
docker exec -i "$DEVBOX_NAME" bash <<EOF
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Stopping frontend service..."
if [ -f /home/devbox/.frontend.pid ]; then
FRONTEND_PID=\$(cat /home/devbox/.frontend.pid)
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Killing frontend service PID: \$FRONTEND_PID"
kill -9 \$FRONTEND_PID
rm -f /home/devbox/.frontend.pid
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Frontend service is not running."
fi
EOF
}
###############################################
# Backend compilation and startup logic
###############################################
compile_backend_service() {
echo "[BACKEND] $(date '+%Y-%m-%d %H:%M:%S') Start backend service at home path $WORKING_HOME."
devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
DEVBOX_NAME=$(cat "$devbox_container_id_file_path")
devbox_backend_port_file_path="${WORKING_HOME}/.devbox-backend-port"
DEVBOX_BACKEND_PORT=$(cat "$devbox_backend_port_file_path")
echo "[BACKEND] $(date '+%Y-%m-%d %H:%M:%S') Start backend service from $DEVBOX_NAME."
docker exec -i "$DEVBOX_NAME" bash <<EOF
# Check if /home/devbox/.backend.pid exits
if [ -f /home/devbox/.backend.pid ]; then
backend_pid=\$(cat /home/devbox/.backend.pid)
if [ -n "\$backend_pid" ]; then
# Check if the backend service is running
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Backend service is running with PID: \$backend_pid"
if ps -p "\$backend_pid" > /dev/null; then
echo
echo "============================================================================================"
echo
echo "[BACKEND] [WARNING] Backend service is running with PID: \$backend_pid, if you want to restart, please stop it first or run devbox restart -e backend."
echo
echo "============================================================================================"
echo
exit 0
fi
fi
fi
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Starting backend compilation and startup..."
pushd /home/devbox/freeleaps/apps > /dev/null
# Record the git status baseline before compilation
baseline_backend=\$(mktemp)
git config --global --add safe.directory /home/devbox/freeleaps
git status -s > "\$baseline_backend"
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Recorded baseline before compilation: \$baseline_backend"
# CHeck if the virtual environment is created
if [ ! -f "venv_t/bin/activate" ]; then
echo
echo "============================================"
echo
echo "[BACKEND] [ERROR] The virtual environment cannot be created. Please check the log for more information."
echo
echo "============================================"
echo
# rm baseline_backend
rm -f "\$baseline_backend"
exit 1
fi
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Start to activate virtual environment."
source venv_t/bin/activate
source /home/devbox/freeleaps/apps/.env
# Verify the virtual environment is activated
if [[ "\$VIRTUAL_ENV" != "" ]]; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Virtual environment activate: \$VIRTUAL_ENV"
else
echo
echo "============================================"
echo
echo "[BACKEND] [ERROR] The virtual environment cannot be startup \$VIRTUAL_ENV, please check the log for more information."
echo
echo "============================================"
echo
rm -f "\$baseline_backend"
exit 1
fi
# Check if it's the first time by verifying if the backend dependencies have been installed
if [ ! -f "/home/devbox/.backend_deps_installed" ]; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Install backend dependencies..."
pip install -r /home/devbox/freeleaps/apps/requirements.txt
if ! pip show async_timeout; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') async_timeout is missing. Installing..."
pip install async_timeout
fi
# Generate /home/devbox/tmp/requirements.txt
mkdir -p /home/devbox/tmp
## Backup the requirements.txt file
cp /home/devbox/freeleaps/apps/requirements.txt /home/devbox/tmp/requirements.txt.bak
ORIGINAL_REQ="/home/devbox/freeleaps/apps/requirements.txt"
NEW_REQ="/home/devbox/tmp/requirements.txt"
# Check if /home/devbox/tmp/requirements.txt exists, if yes, remove it
if [ -f "/home/devbox/tmp/requirements.txt" ]; then
rm /home/devbox/tmp/requirements.txt
fi
# Generate /home/devbox/tmp/requirements.txt
pipreqs /home/devbox/freeleaps/apps --ignore venv_t --force --use-local --savepath /home/devbox/tmp/requirements.txt
if [ ! -f "\$ORIGINAL_REQ" ]; then
mv "\$NEW_REQ" "\$ORIGINAL_REQ"
else
IS_NEW_REQ_ADDED=0
while IFS= read -r line; do
# Revome the version number from the line
pkg=\$(echo "\$line" | cut -d '=' -f 1 | tr -d ' ')
# Check if the package is already in the requirements.txt file
if ! grep -i -E "^\${pkg}([=]|$)" "\$ORIGINAL_REQ" > /dev/null; then
echo "\$line" >> "\$ORIGINAL_REQ"
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Added package: \${pkg}"
IS_NEW_REQ_ADDED=1
else
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Package \${pkg} already exists in requirements.txt"
fi
done < "\$NEW_REQ"
fi
if [ \$IS_NEW_REQ_ADDED -eq 1 ]; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Reinstalling dependencies..."
pip install -r /home/devbox/freeleaps/apps/requirements.txt
fi
# Undo update for /home/devbox/freeleaps/apps/requirements.txt
rm /home/devbox/freeleaps/apps/requirements.txt
mv /home/devbox/tmp/requirements.txt.bak /home/devbox/freeleaps/apps/requirements.txt
touch /home/devbox/.backend_deps_installed
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Run backend service..."
./start_webapi.sh > /home/devbox/logs/backend.logs 2>&1 &
else
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Backend dependencies already installed. Skipping installation."
# Check if all dependencies are installed, if not, install them
if ! pip check; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Some dependencies are missing. Reinstalling..."
pip install -r /home/devbox/freeleaps/apps/requirements.txt
fi
# pip install async_timeout if not installed
if ! pip show async_timeout; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') async_timeout is missing. Installing..."
pip install async_timeout
fi
# Generate /home/devbox/tmp/requirements.txt
mkdir -p /home/devbox/tmp
## Backup the requirements.txt file
cp /home/devbox/freeleaps/apps/requirements.txt /home/devbox/tmp/requirements.txt.bak
ORIGINAL_REQ="/home/devbox/freeleaps/apps/requirements.txt"
NEW_REQ="/home/devbox/tmp/requirements.txt"
# Check if /home/devbox/tmp/requirements.txt exists, if yes, remove it
if [ -f "/home/devbox/tmp/requirements.txt" ]; then
rm /home/devbox/tmp/requirements.txt
fi
pipreqs /home/devbox/freeleaps/apps --ignore venv_t --force --use-local --savepath /home/devbox/tmp/requirements.txt
if [ ! -f "\$ORIGINAL_REQ" ]; then
mv "\$NEW_REQ" "\$ORIGINAL_REQ"
else
IS_NEW_REQ_ADDED=0
while IFS= read -r line; do
# Revome the version number from the line
pkg=\$(echo "\$line" | cut -d '=' -f 1 | tr -d ' ')
# Check if the package is already in the requirements.txt file
if ! grep -i -E "^\${pkg}([=]|$)" "\$ORIGINAL_REQ" > /dev/null; then
echo "\$line" >> "\$ORIGINAL_REQ"
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Added package: \${pkg}"
IS_NEW_REQ_ADDED=1
else
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Package \${pkg} already exists in requirements.txt"
fi
done < "\$NEW_REQ"
fi
if [ \$IS_NEW_REQ_ADDED -eq 1 ]; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Reinstalling dependencies..."
pip install -r /home/devbox/freeleaps/apps/requirements.txt
fi
# Undo update for /home/devbox/freeleaps/apps/requirements.txt
rm /home/devbox/freeleaps/apps/requirements.txt
mv /home/devbox/tmp/requirements.txt.bak /home/devbox/freeleaps/apps/requirements.txt
# 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 &
fi
# Remove tempory file /home/devbox/tmp/requirements.txt if it exists
if [ -f "/home/devbox/tmp/requirements.txt" ]; then
rm /home/devbox/tmp/requirements.txt
fi
# Check the health of the backend service: poll to detect HTTP status
MAX_ATTEMPTS=30
ATTEMPT=0
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking backend service startup..."
while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Backend url http://localhost:${DEVBOX_BACKEND_PORT}/docs"
HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${DEVBOX_BACKEND_PORT}/docs")
if [ "\$HTTP_CODE" -eq 200 ]; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Service started successfully (HTTP \$HTTP_CODE)"
# Get the backend service PID by checking the process port with netstat -tulnp | grep ${DEVBOX_BACKEND_PORT}
BACKEND_PID=\$(netstat -tulnp 2>/dev/null | grep "${DEVBOX_BACKEND_PORT}" | awk '{print \$7}' | awk -F'/' '{print \$1}')
echo "\$BACKEND_PID" > /home/devbox/.backend.pid
break
else
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Waiting for backend service... Attempt \$((ATTEMPT+1)) with HTTP \$HTTP_CODE"
ATTEMPT=\$((ATTEMPT+1))
sleep 10
fi
done
if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then
echo
echo "============================================================================================"
echo
echo
echo "[BACKEND] [ERROR] Backend service startup failed. Please check the logs for more information. Logs: ${WORKING_HOME}/logs/backend.logs"
echo
echo
echo "============================================================================================"
echo
exit 1
fi
# Restore git changes caused by compilation
current_backend=\$(mktemp)
git config --global --add safe.directory /home/devbox/freeleaps
git status -s > "\$current_backend"
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking git changes after compilation..."
while read -r line; do
file=\$(echo "\$line" | awk '{print \$2}')
if ! grep -q "[[:space:]]\${file}$" "\$baseline_backend"; then
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Restore file \$file"
git reset HEAD "\$file"
git checkout -- "\$file"
fi
done < "\$current_backend"
rm "\$baseline_backend" "\$current_backend"
popd > /dev/null
echo "[BACKEND] \$(date '+%Y-%m-%d %H:%M:%S') Backend compilation and startup completed."
EOF
}
###############################################
# Frontend compilation and startup logic
###############################################
compile_frontend_service() {
echo "[FRONTEND] $(date '+%Y-%m-%d %H:%M:%S') start frontend service at home path $WORKING_HOME."
devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
if [ ! -f "$devbox_container_id_file_path" ]; then
# Check if devbox container exists by checking the container name of devbox
if ! docker ps -a --format "{{.Names}}" | grep -q "devbox"; then
exit_with_message "DevBox container is not running. Please start the DevBox container first." 1
fi
fi
DEVBOX_NAME=$(cat "$devbox_container_id_file_path")
DEVBOX_FRONTEND_PORT=$(cat "$WORKING_HOME/.devbox-frontend-port")
docker exec -i "$DEVBOX_NAME" bash <<EOF
# Check if /home/devbox/.frontend.pid exits
if [ -f /home/devbox/.frontend.pid ]; then
frontend_pid=\$(cat /home/devbox/.frontend.pid)
if [ -n "\$frontend_pid" ]; then
# Check if the frontend service is running
if ps -p "\$frontend_pid" > /dev/null; then
echo
echo "============================================================================================"
echo
echo "[FRONTEND] [WARNING] Frontend service is running with PID: \$frontend_pid, if you want to restart, please stop it first or run devbox restart -e frontend."
echo
echo "============================================================================================"
echo
exit 1
fi
fi
fi
USE_LOCAL_COMPONENT_FLAG="/home/devbox/.use-local-component"
USE_LOCAL_COMPONENT_VAL="false"
if [ -f "\$USE_LOCAL_COMPONENT_FLAG" ]; then
# Read the value from the file
USE_LOCAL_COMPONENT_VAL=\$(cat "\$USE_LOCAL_COMPONENT_FLAG")
fi
pushd /home/devbox/freeleaps/frontend > /dev/null
# Record the git status baseline before compilation
baseline_frontend=\$(mktemp)
git config --global --add safe.directory /home/devbox/freeleaps
git status -s > "\$baseline_frontend"
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Recorded baseline before compilation: \$baseline_frontend"
# Check if the frontend service is already running according to the package.json and pnpm-lock.yaml files timestamps
# Get the timestamps of the package.json and pnpm-lock.yaml files
lock_time=\$(stat -c "%Y" pnpm-lock.yaml)
modules_time=\$(stat -c "%Y" node_modules)
# Calculate the absolute value of the time difference between the lock file and the modules file
time_diff=\$(( lock_time - modules_time ))
if [ \$time_diff -lt 0 ]; then
time_diff=\$(( -time_diff ))
fi
# Set the threshold for the time difference
threshold=150
# Frontend environment variable settings. [:COMPONENT_SETTINGS]
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') USE_LOCAL_COMPONENT_VAL: \$USE_LOCAL_COMPONENT_VAL"
if [[ "\$USE_LOCAL_COMPONENT_VAL" == "true" ]]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use local component dev environment."
sed -i 's#VITE_PROXY_WEBSOCKET_CHAT_URL=ws://localhost:8012#VITE_PROXY_WEBSOCKET_CHAT_URL=ws://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i 's#VITE_PROXY_API_CHAT_URL=http://localhost:8012#VITE_PROXY_API_CHAT_URL=http://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use online component dev environment."
sed -i 's#VITE_PROXY_WEBSOCKET_CHAT_URL=wss://localhost:8012#VITE_PROXY_WEBSOCKET_CHAT_URL=wss://freeleaps-alpha.com#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i 's#VITE_PROXY_API_CHAT_URL=http://localhost:8012#VITE_PROXY_API_CHAT_URL=https://freeleaps-alpha.com#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
fi
pushd /home/devbox/freeleaps > /dev/null
git update-index --skip-worktree /home/devbox/freeleaps/frontend/freeleaps/.env.development
popd > /dev/null
if [[ ! -d "node_modules" || "package.json" -nt "node_modules" || \$time_diff -gt \$threshold ]]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Installing/Updating frontend dependencies..."
# Clean up old dependencies
rm -rf node_modules
# Clean up old pnpm store
pnpm store prune
# Backup the pnpm-lock.yaml file
if [ -f "pnpm-lock.yaml" ]; then
mv pnpm-lock.yaml /tmp/pnpm-lock.yaml.bak
fi
# if /home/tmp/.pnpm-store exists, remove it
if [ -d "/home/tmp/.pnpm-store" ]; then
rm -rf /home/tmp/.pnpm-store
fi
# Install dependencies
pnpm install --no-frozen-lockfile \\
--shamefully-hoist \\
--link-workspace-packages false \\
--store-dir /home/tmp/.pnpm-store || {
echo
echo "============================================================================================"
echo
echo "[FRONTEND] [ERROR] Failed to install dependencies. Please check the logs for more information."
echo
echo "============================================================================================"
echo
# rm baseline_frontend if it exists
if [ -f "\$baseline_frontend" ]; then
rm "\$baseline_frontend"
fi
exit 1
}
fi
# Check pnpm result if node_modules exists or if node_modules has not file inside and contains the required dependencies
if [[ ! -d "node_modules" || ! -f "node_modules/.bin/vite" ]]; then
# Check if the frontend dependencies are installed correctly
pnpm install --no-frozen-lockfile || {
echo
echo "============================================================================================"
echo
echo "[FRONTEND] [ERROR] Frontend dependencies are not installed correctly. Please check the logs for more information."
echo
echo "============================================================================================"
echo
if [ -f "\$baseline_frontend" ]; then
rm "\$baseline_frontend"
fi
exit 1
}
# Check if the frontend dependencies are installed correctly
if [[ ! -d "node_modules" || ! -f "node_modules/.bin/vite" ]]; then
echo
echo "============================================================================================"
echo
echo "[FRONTEND] [ERROR] Frontend dependencies are not installed correctly. Please check the logs for more information."
echo
echo "============================================================================================"
echo
if [ -f "\$baseline_frontend" ]; then
rm "\$baseline_frontend"
fi
exit 1
fi
fi
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Starting frontend compilation and startup..."
# Start the frontend service
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Start frontend service..."
nohup pnpm run dev > /home/devbox/logs/frontend.logs 2>&1 &
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Frontend service started. Logs: /home/devbox/logs/frontend.logs"
# Check the health of the frontend service: poll to detect HTTP status
MAX_ATTEMPTS=30
ATTEMPT=0
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking frontend service startup..."
while [ \$ATTEMPT -lt \$MAX_ATTEMPTS ]; do
HTTP_CODE=\$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${DEVBOX_FRONTEND_PORT}/")
if [ "\$HTTP_CODE" -eq 200 ]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Service started successfully (HTTP \$HTTP_CODE)"
# Get the backend service PID by checking the process port with netstat -tulnp | grep ${DEVBOX_FRONTEND_PORT}
FRONTEND_PID=\$(netstat -tulnp 2>/dev/null | grep "${DEVBOX_FRONTEND_PORT}" | awk '{print \$7}' | awk -F'/' '{print \$1}')
echo "\$FRONTEND_PID" > /home/devbox/.frontend.pid
break
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Waiting for frontend service... Attempt \$((ATTEMPT+1))"
ATTEMPT=\$((ATTEMPT+1))
sleep 10
fi
done
# if /tmp/pnpm-lock.yaml.bak exists, restore it
if [ -f "/tmp/pnpm-lock.yaml.bak" ];
then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Restore pnpm-lock.yaml..."
rm -rf pnpm-lock.yaml
mv /tmp/pnpm-lock.yaml.bak pnpm-lock.yaml
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') pnpm-lock.yaml restored."
fi
# Restore git changes caused by compilation
current_frontend=\$(mktemp)
git config --global --add safe.directory /home/devbox/freeleaps
git status -s > "\$current_frontend"
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking git changes after compilation..."
while read -r line; do
file=\$(echo "\$line" | awk '{print \$2}')
if ! grep -q "[[:space:]]\${file}$" "\$baseline_frontend"; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Restore file \$file"
git reset HEAD "\$file"
git checkout -- "\$file"
fi
done < "\$current_frontend"
rm "\$baseline_frontend" "\$current_frontend"
popd > /dev/null
if [ \$ATTEMPT -eq \$MAX_ATTEMPTS ]; then
echo
echo "============================================================================================"
echo
echo "[FRONTEND] [ERROR] Frontend service startup failed. Please check the logs for more information. Logs: ${WORKING_HOME}/logs/frontend.logs"
echo
echo "============================================================================================"
echo
exit 1
fi
# Frontend environment variable settings. [:COMPONENT_SETTINGS]
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') USE_LOCAL_COMPONENT_VAL: \$USE_LOCAL_COMPONENT_VAL"
if [[ "\$USE_LOCAL_COMPONENT_VAL" == "true" ]]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use local component dev environment."
sed -i 's#VITE_PROXY_WEBSOCKET_CHAT_URL=.*#VITE_PROXY_WEBSOCKET_CHAT_URL=ws://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i 's#VITE_PROXY_API_CHAT_URL=.*#VITE_PROXY_API_CHAT_URL=http://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use online component dev environment."
sed -i "s|VITE_PROXY_WEBSOCKET_CHAT_URL=.*|VITE_PROXY_WEBSOCKET_CHAT_URL=wss://freeleaps-alpha.com|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i "s|VITE_PROXY_API_CHAT_URL=.*|VITE_PROXY_API_CHAT_URL=https://freeleaps-alpha.com|g" /home/devbox/freeleaps/frontend/freeleaps/.env.development
fi
echo
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Frontend compilation and startup completed."
echo
# Check frontend git checkout status
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking git status after compilation..."
pushd /home/devbox/freeleaps/frontend > /dev/null
git config --global --add safe.directory /home/devbox/freeleaps
git status -s
if [ -n "\$(git status --porcelain)" ]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Uncommitted changes found. Resetting..."
git reset --hard HEAD
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') No uncommitted changes found."
fi
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Checking for untracked files..."
EOF
}
reset_freeleaps_repo() {
echo "[INIT] $(date '+%Y-%m-%d %H:%M:%S') Resetting FreeLeaps repository..."
devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
DEVBOX_NAME=$(cat "$devbox_container_id_file_path")
docker exec -i "$DEVBOX_NAME" bash <<EOF
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Resetting FreeLeaps repository..."
pushd /home/devbox/freeleaps > /dev/null
git config --global --add safe.directory /home/devbox/freeleaps
git reset --hard HEAD
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Checking for uncommitted changes..."
git status -s
if [ -n "\$(git status --porcelain)" ]; then
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Uncommitted changes found. Resetting..."
git reset --hard HEAD
else
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') No uncommitted changes found."
fi
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') Checking for untracked files..."
popd > /dev/null
echo "[INIT] \$(date '+%Y-%m-%d %H:%M:%S') FreeLeaps repository reset completed."
USE_LOCAL_COMPONENT_FLAG="/home/devbox/.use-local-component"
USE_LOCAL_COMPONENT_VAL="false"
if [ -f "\$USE_LOCAL_COMPONENT_FLAG" ]; then
# Read the value from the file
USE_LOCAL_COMPONENT_VAL=\$(cat "\$USE_LOCAL_COMPONENT_FLAG")
fi
if [[ "\$USE_LOCAL_COMPONENT_VAL" == "true" ]]; then
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use local component dev environment."
sed -i 's#VITE_PROXY_WEBSOCKET_CHAT_URL=.*#VITE_PROXY_WEBSOCKET_CHAT_URL=ws://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i 's#VITE_PROXY_API_CHAT_URL=.*#VITE_PROXY_API_CHAT_URL=http://chat:8012#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
else
echo "[FRONTEND] \$(date '+%Y-%m-%d %H:%M:%S') Use online component dev environment."
sed -i 's#VITE_PROXY_WEBSOCKET_CHAT_URL=.*#VITE_PROXY_WEBSOCKET_CHAT_URL=wss://freeleaps-alpha.com#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
sed -i 's#VITE_PROXY_API_CHAT_URL=http://localhost:8012#VITE_PROXY_API_CHAT_URL=https://freeleaps-alpha.com#g' /home/devbox/freeleaps/frontend/freeleaps/.env.development
fi
EOF
}
# :command.command_functions
# :command.function
devbox_init_command() {
log_info "[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
# set local components to content of DEVBOX_COMPONENTS
local components=("${DEVBOX_COMPONENTS[@]}")
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
exit_with_message " Invalid component: $component, please check the component name." 1
fi
done
start_components=("${freeleaps_components[@]}")
else
start_components=("${components[@]}")
fi
log_info "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[@]}")
log_info "Pulling all components..."
log_info "start components: ${start_components[@]}"
fi
# Remove duplicated components
start_components=($(echo "${start_components[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
echo "===================================================== "
log_info "Parameters:"
log_info " OS = $OS"
log_info " ARCH = $ARCH"
log_info " DEVBOX_NAME = $DEVBOX_NAME"
log_info " DEVBOX_PORT = $DEVBOX_PORT"
log_info " DEVBOX_FRONTEND_PORT = $DEVBOX_FRONTEND_PORT"
log_info " DEVBOX_BACKEND_PORT = $DEVBOX_BACKEND_PORT"
log_info " DEVBOX_REPO = $DEVBOX_REPO"
log_info " DEVBOX_IMAGE = $DEVBOX_IMAGE"
log_info " DEVBOX_TAG = $DEVBOX_TAG"
log_info " WORKING_HOME = $WORKING_HOME"
log_info " FREELEAPS_USERNAME= $FREELEAPS_USERNAME"
log_info " (FREELEAPS_PASSWORD is hidden for security)"
log_info " USE_LOCAL_COMPONENT= $USE_LOCAL_COMPONENT"
log_info " FREELEAPS_COMPONENTS= ${start_components[@]}"
log_info " 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
exit_with_message " Unsupported OS: $OS, please check the OS." 1
fi
# Auto detected $OS
if [[ "$OS" == "auto" ]]; then
log_info "Auto detecting OS..."
OS="$(detect_os)"
log_info "Detected OS: $OS"
fi
if [[ "$ARCH" != "auto" && "$ARCH" != "amd64" && "$ARCH" != "arm64" ]]; then
exit_with_message " Unsupported architecture: $ARCH, please check the architecture." 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"
log_info "Detected AMD64 architecture."
else
ARCH="amd64"
fi
elif [[ "$ARCH" == "aarch64" ]] || [[ "$ARCH" == "arm64" ]]; 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
exit_with_message " Failed to install Docker or Docker service is not running. Please install Docker and start Docker service." 1
fi
if ! check_docker_running; then
exit_with_message " Docker service is not running. Please start Docker service." 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
exit_with_message " Insufficient disk space (need >10GB). Please free up some space." 1
fi
# 3.3 WORKING_HOME Check
if ! mkdir -p "$WORKING_HOME" 2>/dev/null; then
exit_with_message " Can't create or write to WORKING_HOME: $WORKING_HOME, please check the path." 1
fi
# 3.4 Network to docker.com(sampleping docker.com)
if ! ping -c 1 docker.com &>/dev/null; then
exit_with_message " Network to Docker.com is not available. Please check your network connection." 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
read -p "DevBox instance already exists. Do you want to force remove it? (y/N): " ans
case "$ans" in
[Yy]* )
FORCE_INIT=true
;;
* )
exit_with_message "DevBox instance already exists. Use --force to remove it." 1
;;
esac
fi
echo
# Check if any component is running on the host when force init is not set
if [ -z "$FORCE_INIT" ]; then
running_containers=$(docker ps --format '{{.Names}}')
# Check if any component is running on the host
components_to_check=("devbox" "freeleaps2-gitea" "freeleaps2-mongodb" "freeleaps2-rabbitmq" "freeleaps2-redis")
components_to_check+=("${DEVBOX_COMPONENTS[@]}")
for comp in "${components_to_check[@]}"; do
if echo "$running_containers" | grep -qx "$comp"; then
echo
read -p "Container '$comp' is already running. Do you want to force update it? (y/N): " ans
case "$ans" in
[Yy]* )
FORCE_INIT=true
break
;;
* )
exit_with_message " Container '$comp' is already running. Use --force to override." 1
;;
esac
fi
done
fi
echo
log_info "Current OS is $OS"
# Check if Installed the net-tools netstat under MacOS, WSL2 and Linux OS
if [[ "$OS" == "darwin" || "$OS" == "wsl2" || "$OS" == "linux" ]]; then
if ! command -v netstat &>/dev/null; then
log_info "Installing net-tools package..."
if [[ "$OS" == "darwin" ]]; then
brew install net-tools
elif [[ "$OS" == "wsl2" ]]; then
sudo apt-get update -y
sudo apt-get install net-tools -y
elif [[ "$OS" == "linux" ]]; then
sudo apt-get update -y
sudo apt-get install net-tools -y
else
exit_with_message " Failed install net-tools package on OS: $OS, please install it manually." 1
fi
else
log_info "net-tools package already installed."
fi
fi
# Check if force init is set, if not, check if the ports are in use
if [[ -z "$FORCE_INIT" ]]; then
log_info "Checking if the ports are in use..."
# Check if the gittea, mongodb, rabbitmq, redis ports are in use
if netstat -tuln | grep -q ":3000"; then
exit_with_message " gitea port 3000 is already in use, please stop the service." 1
fi
if netstat -tuln | grep -q ":27017"; then
exit_with_message " mongodb port 27017 is already in use, please stop the service." 1
fi
if netstat -tuln | grep -q ":5672"; then
exit_with_message " rabbitmq port 5672 is already in use, please stop the service." 1
fi
if netstat -tuln | grep -q ":15672"; then
exit_with_message " rabbitmq port 15672 is already in use, please stop the service." 1
fi
if netstat -tuln | grep -q ":6379"; then
exit_with_message " redis port 6379 is already in use, please stop the service." 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
log_info "DevBox image $devbox_full_image already exists."
# Check if the local image is not used by any container
local devbox_full_image="${DEVBOX_REPO}/${DEVBOX_IMAGE}:${DEVBOX_TAG}"
local local_image_id remote_image_id
# Get the local image ID
log_info "DevBox image $devbox_full_image already exists."
local_image_id=$(docker images --format '{{.ID}}' | grep "^${devbox_full_image}\$")
remote_image_id=$(docker images --format '{{.ID}}' "$devbox_full_image" | head -n 1)
if [[ "$local_image_id" != "$remote_image_id" ]]; then
timestamp=$(date +%Y%m%d%H%M%S)
local backup_tag="${DEVBOX_TAG}-$timestamp"
if docker tag "$local_image_id" "${DEVBOX_REPO}/${DEVBOX_IMAGE}:${backup_tag}"; then
log_info "Backup local image $local_image_id to ${DEVBOX_REPO}/${DEVBOX_IMAGE}:${backup_tag}"
else
log_warn " Failed to backup local image $local_image_id to ${DEVBOX_REPO}/${DEVBOX_IMAGE}:${backup_tag}"
fi
# Check if the local image is not used by any container
if docker ps -a --format '{{.Image}}' | grep -q "^${local_image_id}\$"; then
log_info "Local image $local_image_id is used by a container. Stopping it first..."
docker ps -a --filter "ancestor=$local_image_id" --format '{{.ID}}' | while read -r container_id; do
docker stop "$container_id" &>/dev/null || true
docker rm "$container_id" &>/dev/null || true
done
fi
# Delete local image by image id
if docker rmi "$local_image_id" &>/dev/null; then
log_info "Deleted local image $local_image_id"
else
log_warn " Failed to delete local image $local_image_id"
fi
# Pull the latest image from the remote repository
log_info "Pulling DevBox image $devbox_full_image..."
docker pull "$devbox_full_image" || {
exit_with_message " Failed to pull DevBox image $devbox_full_image, please check the image name and tag." 1
}
else
log_info "The correct version of devbox image exists and use local image."
fi
else
log_info "Pulling DevBox image $devbox_full_image..."
docker pull "$devbox_full_image"
fi
else
exit_with_message " DevBox image repository, name, or tag is not specified, please check the parameters." 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
log_info "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
exit_with_message " Container named $DEVBOX_NAME already exists. Use --force to remove it." 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"
log_info ' Starting DevBox environment initialization...'
# Check if docker network create devbox_freeleaps2-network
if ! docker network ls | grep -q "$DEVBOX_FREELEAPS2_NETWORK"; then
log_info "Creating Docker network: $DEVBOX_FREELEAPS2_NETWORK"
docker network create "$DEVBOX_FREELEAPS2_NETWORK"
else
log_info "Docker network devbox_freeleaps2-network already exists."
fi
# Check if use custom repository
if [[ -n "$USE_CUSTOM_REPOSITORY" ]]; then
log_info "[INIT] Using custom repository."
elif [[ -z "$FREELEAPS_USERNAME" || -z "$FREELEAPS_PASSWORD" ]]; then
exit_with_message " Username or password is missing. Please provide a valid username and password for freeleaps.com repository." 1
fi
log_info ' [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
exit_with_message " Failed to create DevBox container." 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"
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
log_info "Testing access to freeleaps.com repository..."
if ! git ls-remote "https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_FREELEAPS_PASSWORD@gitea.freeleaps.mathmast.com/products/freeleaps.git" &>/dev/null; then
exit_with_message " Failed to access freeleaps.com repository. Please check your username and password." 1
fi
FREELEAPS_DIR="$WORKING_HOME/freeleaps"
FRONTEND_GIT_URL="https://$ENCODEING_FREELEAPS_USERNAME:$ENCODEING_FREELEAPS_PASSWORD@gitea.freeleaps.mathmast.com/products/freeleaps.git"
# Check if freeleaps2-frontend exists, if not git clone it
if [ ! -d "$FREELEAPS_DIR" ]; then
pushd "$WORKING_HOME" > /dev/null
log_info "Git cloning gitea.freeleaps.mathmast.com/products/freeleaps.git to $FREELEAPS_DIR"
git clone --depth 5 $FRONTEND_GIT_URL
else
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
log_info "Cloning repository again: $FRONTEND_GIT_URL"
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} "$WORKING_HOME"
git clone --depth 5 "$FRONTEND_GIT_URL"
else
log_info "Git pulling gitea.freeleaps.mathmast.com/products/freeleaps.git"
git pull
fi
popd > /dev/null
fi
else
if ! echo "$USE_CUSTOM_REPOSITORY" | grep -Eq '^(https:\/\/|git@|git:\/\/|file:\/\/\/)[^ ]+\.git$'; then
exit_with_message " Invalid custom repository URL. Please provide a valid URL." 1
fi
# Check if the custom repository is a git repository
# Test if the user can access the custom repository
log_info "Testing access to custom repository..."
if ! git ls-remote "$USE_CUSTOM_REPOSITORY" &>/dev/null; then
exit_with_message " Failed to access custom repository. Please check the repository URL." 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
log_info "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
log_info "Cloning repository again: $ECHO_USE_CUSTOM_REPOSITORY"
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} "$WORKING_HOME"
git clone --depth 5 "$USE_CUSTOM_REPOSITORY"
else
log_info "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
# -------------------------------------------------------------------
log_info "[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
log_info "[INIT] Custom repository initialization completed."
log_info "Custom repository is located at: ${WORKING_HOME}/${CUSTOM_FOLDER_NAME}"
log_info "Custom repository URL: $ECHO_USE_CUSTOM_REPOSITORY"
log_info "Custom repository is ready for use."
echo
echo "==========================================================="
echo
exit 0
fi
# Check if docker-compose command exists
log_info "Cehck if docker-compose command exists"
# Check if docker-compose is installed
local DC_CMD
if command -v docker-compose >/dev/null 2>&1; then
DC_CMD="docker-compose"
# 如果没有找到 docker-compose再检查 docker composev2 插件)
elif docker compose version >/dev/null 2>&1; then
DC_CMD="docker compose"
else
DC_CMD=""
log_error "docker-compose is not installed."
fi
if [[ "$DC_CMD" == "" ]]; then
exit_with_message "Please install docker-compose or docker compose (v2) and try again." 1
fi
# If USE_LOCAL_COMPONENT is true, then use local components
if [[ $USE_LOCAL_COMPONENT_VAL == true ]]; then
log_info ' = 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
exit_with_message " gitea_data_backup.tar.gz not found. Please make sure it exists in the current directory." 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
exit_with_message " Failed to extract gitea data backup, please check the backup file." 1
fi
# 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 current user of the gitea data directories
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} ${GITEA_HOST_DIR}
log_info "Gitea data copying is done"
# Check if gitea data directories exist in the gitea container
if [[ ! -d "${GITEA_HOST_DIR}/gitea" ]]; then
exit_with_message " Failed to copy gitea data, please check the data directories." 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
# Check if FORCE_INIT is set, if not just docker compose up or docker-compose up --force
# Start Gitea, MongoDB, RabbitMQ and other components containers
log_info "start Gitea, MongoDB, RabbitMQ and other components containers"
if [[ -z "$FORCE_INIT" ]]; then
log_info "Starting Gitea, MongoDB, RabbitMQ and other components containers..."
$DC_CMD -f docker-compose.yaml up -d mongodb rabbitmq gitea redis "${start_components[@]}"
else
log_info "Force starting Gitea, MongoDB, RabbitMQ and other components containers..."
$DC_CMD -f docker-compose.yaml up --force-recreate -d mongodb rabbitmq gitea redis "${start_components[@]}"
fi
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
log_info "${component} container created: $component_container_id"
# Check all components are started
for component in "${start_components[@]}"; do
if [[ -z "$(docker ps -a --format '{{.Names}}' | grep "^$component\$")" ]]; then
exit_with_message " Failed to start $component container. Please check the logs for more information." 1
fi
done
else
echo '============================================================'
log_info 'Using online components for Freeleaps services.'
echo '============================================================'
# Start Gitea, MongoDB, RabbitMQ containers
if [[ -z "$FORCE_INIT" ]]; then
log_info "Starting Gitea, MongoDB, RabbitMQ and other components containers..."
$DC_CMD -f docker-compose.yaml up -d gitea mongodb rabbitmq redis
else
log_info "Force starting Gitea, MongoDB, RabbitMQ and other components containers..."
$DC_CMD -f docker-compose.yaml up --force-recreate -d gitea mongodb rabbitmq redis
fi
# 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
echo
read -p "Do you want to continue to pull freeleaps.com code and start the services? (Y/N): " user_input
echo
# Initialize the compile environment
init_compile_env
if [[ "$user_input" == "N" || "$user_input" == "n" ]]; then
# Echo as init job completed and exit
reset_freeleaps_repo
echo
echo "==========================================================="
log_info "DevBox init completed successfully!"
log_info "DevBox Environment Details:"
log_info "DevBox container name: $DEVBOX_NAME"
log_info "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
compile_backend_service
compile_frontend_service
reset_freeleaps_repo
# -------------------------------------------------------------------
# 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
log_info "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
log_info "Deinitialization parameters:"
log_info " WORKING_HOME = $WORKING_HOME"
log_info " CLEAR_LOGS = $CLEAR_LOGS"
log_info " CLEAR_REPO = $CLEAR_REPO"
log_info " CLEAR_ALL = $CLEAR_ALL"
log_info "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")
log_info "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"
else
log_info "DevBox container is not running."
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^devbox\$")" ]]; then
# Get the container ID of the DevBox container
log_info "DevBox container is stopped."
local container_id
container_id=$(docker ps -a --format '{{.Names}}' | grep "^devbox\$")
log_info "Stopping and removing DevBox container: $container_id"
docker stop "$container_id" &>/dev/null || true
docker rm "$container_id" &>/dev/null || true
fi
fi
# Check if devbox container is running
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^devbox\$")" ]]; then
# Get the container ID of the DevBox container
log_info "DevBox container is stopped."
local container_id
container_id=$(docker ps -a --format '{{.Names}}' | grep "^devbox\$")
exit_with_message " Failed to stop and remove DevBox container when deinitializing. Please try deinit again or manually stop and remove the container." 1
fi
if [[ -f "$WORKING_HOME/.gitea-instance" ]]; then
local gitea_container_id
gitea_container_id=$(cat "$WORKING_HOME/.gitea-instance")
log_info "Stopping and removing Gitea container: $gitea_container_id"
docker stop "$gitea_container_id" &>/dev/null || true
docker rm "$gitea_container_id" &>/dev/null || true
# Check if the Gitea container is still running, then use docker compose down to stop and remove the container
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-gitea\$")" ]]; then
log_info "Using docker-compose down to stop and remove Gitea container."
$DC_CMD -f docker-compose.yaml down gitea
fi
rm -f "$WORKING_HOME/.gitea-instance"
elif [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-gitea\$")" ]]; then
# If the Gitea container is still running, stop and remove it
log_info "Gitea container is stopped."
local gitea_container_id
gitea_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-gitea\$")
log_info "Stopping and removing Gitea container: $gitea_container_id"
docker stop "$gitea_container_id" &>/dev/null || true
docker rm "$gitea_container_id" &>/dev/null || true
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")
log_info "Stopping and removing MongoDB container: $mongodb_container_id"
docker stop "$mongodb_container_id" &>/dev/null || true
docker rm "$mongodb_container_id" &>/dev/null || true
# Check if the MongoDB container is still running, then use docker compose down to stop and remove the container
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-mongodb\$")" ]]; then
log_info "Using docker-compose down to stop and remove MongoDB container."
$DC_CMD -f docker-compose.yaml down mongodb
fi
rm -f "$WORKING_HOME/.mongodb-instance"
elif [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-mongodb\$")" ]]; then
# If the MongoDB container is still running, stop and remove it
log_info "MongoDB container is stopped."
local mongodb_container_id
mongodb_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-mongodb\$")
log_info "Stopping and removing MongoDB container: $mongodb_container_id"
docker stop "$mongodb_container_id" &>/dev/null || true
docker rm "$mongodb_container_id" &>/dev/null || true
fi
if [[ -f "$WORKING_HOME/.redis-instance" ]]; then
local redis_container_id
redis_container_id=$(cat "$WORKING_HOME/.redis-instance")
log_info "Stopping and removing Redis container: $redis_container_id"
docker stop "$redis_container_id" &>/dev/null || true
docker rm "$redis_container_id" &>/dev/null || true
# Check if the Redis container is still running, then use docker compose down to stop and remove the container
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-redis\$")" ]]; then
log_info "Using docker-compose down to stop and remove Redis container."
$DC_CMD -f docker-compose.yaml down redis
fi
rm -f "$WORKING_HOME/.redis-instance"
elif [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-redis\$")" ]]; then
# If the Redis container is still running, stop and remove it
log_info "Redis container is stopped."
local redis_container_id
redis_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-redis\$")
log_info "Stopping and removing Redis container: $redis_container_id"
docker stop "$redis_container_id" &>/dev/null || true
docker rm "$redis_container_id" &>/dev/null || true
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")
log_info "Stopping and removing RabbitMQ container: $rabbitmq_container_id"
docker stop "$rabbitmq_container_id" &>/dev/null || true
docker rm "$rabbitmq_container_id" &>/dev/null || true
# Check if the RabbitMQ container is still running, then use docker compose down to stop and remove the container
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-rabbitmq\$")" ]]; then
log_info "Using docker-compose down to stop and remove RabbitMQ container."
$DC_CMD -f docker-compose.yaml down rabbitmq
fi
rm -f "$WORKING_HOME/.rabbitmq-instance"
elif [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-rabbitmq\$")" ]]; then
# If the RabbitMQ container is still running, stop and remove it
log_info "RabbitMQ container is stopped."
local rabbitmq_container_id
rabbitmq_container_id=$(docker ps -a --format '{{.Names}}' | grep "^freeleaps2-rabbitmq\$")
log_info "Stopping and removing RabbitMQ container: $rabbitmq_container_id"
docker stop "$rabbitmq_container_id" &>/dev/null || true
docker rm "$rabbitmq_container_id" &>/dev/null || true
fi
# Stop and remove other components
local components=("${DEVBOX_COMPONENTS[@]}")
for component in "${components[@]}"; do
if [[ -f "$WORKING_HOME/.${component}-instance" ]]; then
local component_container_id
component_container_id=$(cat "$WORKING_HOME/.${component}-instance")
log_info "Stopping and removing ${component} container: $component_container_id"
docker stop "$component_container_id" &>/dev/null || true
docker rm "$component_container_id" &>/dev/null || true
# Check if the component is still running, then use docker compose down to stop and remove the container
if [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^$component\$")" ]]; then
log_info "Using docker-compose down to stop and remove $component container."
$DC_CMD -f docker-compose.yaml down "$component"
fi
rm -f "$WORKING_HOME/.${component}-instance"
elif [[ -n "$(docker ps -a --format '{{.Names}}' | grep "^$component\$")" ]]; then
# If the component is still running, stop and remove it
log_info "${component} container is stopped."
local component_container_id
component_container_id=$(docker ps -a --format '{{.Names}}' | grep "^$component\$")
log_info "Stopping and removing ${component} container: $component_container_id"
docker stop "$component_container_id" &>/dev/null || true
docker rm "$component_container_id" &>/dev/null || true
fi
done
# Clear the DevBox container logs
if [[ "$CLEAR_LOGS" == "true" ]]; then
log_info "Clearing logs in $WORKING_HOME/logs..."
if [[ -d "$WORKING_HOME/logs" ]]; then
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} "$WORKING_HOME/logs"
rm -rf "$WORKING_HOME/logs" 2>/dev/null || true
mkdir -p "$WORKING_HOME/logs" 2>/dev/null || true
fi
else
log_info "Skipping log clearing."
fi
# Clear the source repository
if [[ "$CLEAR_REPO" == "true" && -d "$WORKING_HOME/freeleaps" ]]; then
log_info "Deleting source repository at $WORKING_HOME/freeleaps"
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} "$WORKING_HOME/freeleaps"
rm -rf "$WORKING_HOME/freeleaps" 2>/dev/null || true
rmdir "$WORKING_HOME/freeleaps" 2>/dev/null || true
else
log_info "Skipping repository deletion."
fi
if [[ "$CLEAR_LOGS" == "true" ]]; then
# Check if logs directory is removed
if [[ -d "$WORKING_HOME/logs" ]]; then
log_warn " $WORKING_HOME/logs still exists after removal."
rm -rf "$WORKING_HOME/logs"
else
log_info "Logs directory removed successfully."
fi
fi
if [[ "$CLEAR_ALL" == "true" ]]; then
# Check Y/N to remove the working home directory
echo
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
echo
if [[ "$user_input" == "Y" || "$user_input" == "y" ]]; then
REMOVE_WORKING_HOME=true
# Remove the working home directory
log_info "Removing working home directory: $WORKING_HOME"
if [[ -d "$WORKING_HOME" ]]; then
uid=$(id -u)
gid=$(id -g)
sudo chown -R ${uid}:${gid} "$WORKING_HOME"
rm -rf "$WORKING_HOME" 2>/dev/null || true
rmdir "$WORKING_HOME" 2>/dev/null || true
fi
log_info "Working home directory removed successfully."
else
REMOVE_WORKING_HOME=false
log_info "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 -
echo -n "[INFO] $(date '+%Y-%m-%d %H:%M:%S') Stopping services"
for i in {1..10}; do
echo -n "."
sleep 0.5
done
echo
# Remove the use-local-component file
rm -f "$WORKING_HOME/.use-local-component"
exit_with_message "DevBox deinitialization completed." 0
}
# :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
# 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
exit_with_message " DevBox container is not running. Please run 'devbox init' first." 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
log_info "Using local components for Freeleaps services."
USE_LOCAL_COMPONENT="true"
else
log_info "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=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
COMPONENTS+=("${DEVBOX_COMPONENTS[@]}")
else
COMPONENTS=("$COMPONENT")
fi
else
# If no component is specified, start all components
if [[ -z "$COMPONENT" ]]; then
COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
else
# Check if the component is a local component from DEVBOX_COMPONENT
found=false
for item in "${DEVBOX_COMPONENTS[@]}"; do
if [ "$item" = "$COMPONENT" ]; then
found=true
break
fi
done
if [ "$found" = true ]; then
exit_with_message "Remote component $COMPONENT cannot be restarted, please use local components." 1
fi
COMPONENTS=("$COMPONENT")
fi
fi
BASIC_COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
for comp in "${COMPONENTS[@]}"; do
should_start=false
# Check if it's in BASIC_COMPONENTS
for basic in "${BASIC_COMPONENTS[@]}"; do
if [ "$comp" = "$basic" ]; then
should_start=true
break
fi
done
# Check if it's in DEVBOX_COMPONENTS
if [ "$should_start" = false ]; then
for dev in "${DEVBOX_COMPONENTS[@]}"; do
if [ "$comp" = "$dev" ]; then
should_start=true
break
fi
done
fi
if [ "$should_start" = true ]; then
log_info "Starting $comp service..."
local component_container_id_file_path="${WORKING_HOME}/.${comp}-instance"
if [ ! -f "$component_container_id_file_path" ]; then
log_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
log_info "$comp container is not running, starting container..."
if ! docker start "${component_container_id}"; then
log_error "Failed to start $comp container."
else
log_info "$comp container started successfully."
fi
else
log_info "$comp container is already running."
fi
fi
else
exit_with_message " Unknown component: $comp, please check the component name." 1
fi
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
log_info "Starting Freeleaps frontend and backend services..."
# Check if start backend service
if [[ "${START_BACKEND}" == "true" ]]; then
compile_backend_service
fi
# Start the frontend service
if [[ "${START_FRONTEND}" == "true" ]]; then
compile_frontend_service
fi
else
exit_with_message " DevBox container is not running, please run 'devbox init' first." 1
fi
fi
success_message=" Freeleaps services started successfully. "
frontend_port=$(cat "${WORKING_HOME}/.devbox-frontend-port")
if [[ "${START_FRONTEND}" == "true" && "${START_BACKEND}" == "true" ]]; then
success_message=" Frontend and backend services started successfully. Open up the frontend by visiting: http://localhost:${frontend_port}"
elif [[ "${START_FRONTEND}" == "true" ]]; then
success_message=" Frontend service started successfully. Open up the frontend by visiting: http://localhost:${frontend_port}"
elif [[ "${START_BACKEND}" == "true" ]]; then
success_message=" Backend service started successfully."
fi
exit_with_message "$success_message" 0
}
# :command.function
devbox_stop_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 STOP_FRONTEND=true
export STOP_BACKEND=true
elif [[ "$FREELEAPS_ENDPOINT" == "frontend" ]]; then
export STOP_FRONTEND=true
export STOP_BACKEND=false
elif [[ "$FREELEAPS_ENDPOINT" == "backend" ]]; then
export STOP_FRONTEND=false
export STOP_BACKEND=true
else
# Default behavior can be adjusted if needed
export STOP_FRONTEND=false
export STOP_BACKEND=false
fi
if [[ -f "${WORKING_HOME}/.devbox-instance" ]]; then
local devbox_container_id
devbox_container_id=$(cat "${WORKING_HOME}/.devbox-instance")
# If the DevBox container is not running, exit
if ! docker ps --no-trunc --format '{{.ID}}' | grep -q "^${devbox_container_id}\$"; then
exit_with_message " DevBox container is not running, please run 'devbox init' first." 1
fi
# Check if STOP_BACKEND is true, stop the backend service
if [[ "${STOP_BACKEND}" == "true" ]]; then
if [[ -f "${WORKING_HOME}/.backend.pid" ]]; then
stop_backend_service
else
log_info "Backend service is not running."
fi
fi
# Check if STOP_FRONTEND is true, stop the frontend service
if [[ "${STOP_FRONTEND}" == "true" ]]; then
if [[ -f "${WORKING_HOME}/.frontend.pid" ]]; then
stop_frontend_service
else
log_info "Frontend service is not running."
fi
fi
fi
# if any of STOP_FRONTEND and STOP_BACKEND is true, then completed stop process
if [[ "${STOP_FRONTEND}" == "true" || "${STOP_BACKEND}" == "true" ]]; then
stoped_freeleaps_service_names=()
if [[ "${STOP_FRONTEND}" == "true" ]]; then
stoped_freeleaps_service_names+=("frontend")
fi
if [[ "${STOP_BACKEND}" == "true" ]]; then
stoped_freeleaps_service_names+=("backend")
fi
# Combine the stoped_freeleaps_service_names array to a string with "and" if there are more than one service
if [[ "${#stoped_freeleaps_service_names[@]}" -gt 1 ]]; then
stoped_freeleaps_service_names="frontend and backend"
else
stoped_freeleaps_service_names="${stoped_freeleaps_service_names[0]}"
fi
exit_message="Stopped Freeleaps $stoped_freeleaps_service_names services successfully."
exit_with_message "$exit_message" 0
fi
# If the DevBox container is not running, exit
if [[ -z "$COMPONENT" ]]; then
COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
COMPONENTS+=("${DEVBOX_COMPONENTS[@]}")
else
COMPONENTS=("$COMPONENT")
fi
# Stop the specified components
BASIC_COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis")
for comp in "${COMPONENTS[@]}"; do
if [ "$comp" = "devbox" ]; then
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
log_info "Stopping devbox..."
docker stop "$container_id" &>/dev/null || true
rm -f "${WORKING_HOME}/.backend.pid"
rm -f "${WORKING_HOME}/.frontend.pid"
else
log_info "DevBox container is not running."
fi
else
log_info "Backend service is not running."
fi
continue
fi
should_stop=false
for basic in "${BASIC_COMPONENTS[@]}"; do
if [ "$comp" = "$basic" ]; then
should_stop=true
break
fi
done
if [ "$should_stop" = false ]; then
for dev in "${DEVBOX_COMPONENTS[@]}"; do
if [ "$comp" = "$dev" ]; then
should_stop=true
break
fi
done
fi
if [ "$should_stop" = true ]; then
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
log_info "Stopping $comp service..."
docker stop "$container_id" &>/dev/null || true
else
log_info "$comp service is not running."
fi
else
log_info "$comp service is not running."
fi
else
exit_with_message " Unknown component: $comp, please check the component name." 1
fi
done
exit_with_message "Stopped Freeleaps services successfully. " 0
}
# :command.function
devbox_status_command() {
log_info "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
exit_with_message " DevBox container is not running. Please run 'devbox init' first." 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
exit_with_message " DevBox container is not running. Please run 'devbox init' first." 1
fi
# If no component is specified, check all components
if [[ -z "$COMPONENT" ]]; then
COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
COMPONENTS+=("${DEVBOX_COMPONENTS[@]}")
else
COMPONENTS=("$COMPONENT")
fi
# Check the status of the specified components
BASIC_COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis")
ALL_COMPONENTS=("${BASIC_COMPONENTS[@]}" "${DEVBOX_COMPONENTS[@]}" "devbox")
for comp in "${COMPONENTS[@]}"; do
case_checked=false
# devsvc, notification, content...
if [ "$case_checked" = false ]; then
for svc in "${ALL_COMPONENTS[@]}"; do
if [ "$comp" = "$svc" ]; then
log_info "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
log_info "[RESULT]: $comp service is running."
else
log_info "[RESULT]: $comp service is not running."
fi
else
log_info "[RESULT]: $comp service is not running."
fi
case_checked=true
break
fi
done
fi
# unknown
if [ "$case_checked" = false ]; then
exit_with_message " Unknown component: $comp, please check the component name." 1
fi
done
exit_with_message " DevBox services status checked successfully." 0
}
# :command.function
devbox_restart_command() {
log_info "Restarting DevBox services..."
local COMPONENT="$(get_arg '--component')"
local WORKING_HOME="$(get_arg '--working-home' "${HOME}/devbox")"
local FREELEAPS_ENDPOINT="$(get_arg '--freeleaps-endpoint')"
# Check if --freeleaps-endpoint is not empty and start the frontend and backend services
restart_services=()
if [[ "$FREELEAPS_ENDPOINT" == "all" ]]; then
export START_FRONTEND=true
export START_BACKEND=true
restart_services=("frontend" "backend")
elif [[ "$FREELEAPS_ENDPOINT" == "frontend" ]]; then
export START_FRONTEND=true
export START_BACKEND=false
restart_services=("frontend")
elif [[ "$FREELEAPS_ENDPOINT" == "backend" ]]; then
export START_FRONTEND=false
export START_BACKEND=true
restart_services=("backend")
else
# Default behavior can be adjusted if needed
export START_FRONTEND=false
export START_BACKEND=false
fi
# Check if --freeleaps-endpoint is not empty and start the frontend and backend services
if [[ "$FREELEAPS_ENDPOINT" != "" ]]; then
devbox_container_id=$(cat "${WORKING_HOME}/.devbox-instance")
log_info "docker ps --no-trunc --format ${devbox_container_id} "
if docker ps --no-trunc --format '{{.ID}}' | grep -q "${devbox_container_id}\$"; then
log_info "Starting Freeleaps frontend and backend services..."
# Check if start backend service
if [[ "${START_BACKEND}" == "true" ]]; then
stop_backend_service
compile_backend_service
fi
# Start the frontend service
if [[ "${START_FRONTEND}" == "true" ]]; then
stop_frontend_service
compile_frontend_service
fi
else
exit_with_message " DevBox container is not running." 1
fi
frontend_port=$(cat "${WORKING_HOME}/.devbox-frontend-port")
success_message="Freeleaps $restart_services services restarted successfully."
if [[ "${START_FRONTEND}" == "true" ]]; then
success_message+=" Open up the frontend by visiting: http://localhost:${frontend_port}"
fi
exit_with_message "$success_message" 0
fi
# Check devbox container file path
local devbox_container_id_file_path="${WORKING_HOME}/.devbox-instance"
if [[ ! -f "$devbox_container_id_file_path" ]]; then
exit_with_message " DevBox container is not running. Please run 'devbox init' first." 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
log_info "Using local components..."
if [[ -z "$COMPONENT" ]]; then
COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
COMPONENTS+=("${DEVBOX_COMPONENTS[@]}")
else
COMPONENTS=("$COMPONENT")
fi
else
log_info "Using remote components..."
if [[ -z "$COMPONENT" ]]; then
COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis" "devbox")
else
found=false
for item in "${DEVBOX_COMPONENTS[@]}"; do
if [ "$item" = "$COMPONENT" ]; then
found=true
break
fi
done
if [ "$found" = true ]; then
exit_with_message "Remote component $COMPONENT cannot be restarted, please use local components." 1
fi
COMPONENTS=("$COMPONENT")
fi
fi
# Stop the specified components
BASIC_COMPONENTS=("mongodb" "rabbitmq" "gitea" "redis")
ALL_COMPONENTS=("${BASIC_COMPONENTS[@]}" "${DEVBOX_COMPONENTS[@]}" "devbox")
# Stop the specified components
for comp in "${COMPONENTS[@]}"; do
if [ "$comp" = "devbox" ]; then
if [ -f "${WORKING_HOME}/.devbox-instance" ]; then
local container_id
container_id=$(cat "${WORKING_HOME}/.devbox-instance")
log_info "Stopping devbox service..."
docker stop "$container_id" &>/dev/null || true
rm -f "${WORKING_HOME}/.backend.pid"
rm -f "${WORKING_HOME}/.frontend.pid"
else
log_info "Devbox is not running."
fi
continue
fi
should_stop=false
for known in "${BASIC_COMPONENTS[@]}" "${DEVBOX_COMPONENTS[@]}"; do
if [ "$comp" = "$known" ]; then
should_stop=true
break
fi
done
if [ "$should_stop" = true ]; then
if [ -f "${WORKING_HOME}/.${comp}-instance" ]; then
local container_id
container_id=$(cat "${WORKING_HOME}/.${comp}-instance")
log_info "Stopping $comp service..."
docker stop "$container_id" &>/dev/null || true
else
log_info "$comp service is not running."
fi
else
exit_with_message " Unknown component: $comp, please check the component name." 1
fi
done
# 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 comp in "${COMPONENTS[@]}"; do
is_known=false
for known in "${ALL_COMPONENTS[@]}"; do
if [ "$comp" = "$known" ]; then
is_known=true
break
fi
done
if [ "$is_known" = true ]; then
log_info "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
log_info "$comp service is not running."
fi
else
exit_with_message " Unknown component: $comp, please check the component name." 1
fi
done
exit_with_message " DevBox services restarted successfully." 0
}
# :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"
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 | -q)
# :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" ] || [ "$detected_arch" = "arm64" ] ; 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 '--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
;;
--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.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 "$@"