Features: 1) Added validation to ensure scripts execute from project root with 'evibes' directory check; 2) Introduced color formatting and ASCII art for enhanced script output; 3) Added RAM, CPU, and disk space verification to installation scripts; 4) Ensured Docker images existence before service startup; 5) Unified spinner-based progress display in Windows and Unix scripts.

Fixes: 1) Replaced hardcoded paths with script-relative paths for better portability; 2) Corrected CPU and memory calculation logic for system checks; 3) Replaced inconsistent script formatting and error handling; 4) Resolved redundant cleanup steps post service startup.

Extra: Refactored and cleaned up script logic for maintainability; added WISELESS branding across scripts for consistency; enhanced terminal output and user messaging.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-06-16 15:40:44 +03:00
parent 6b829331c3
commit 7d1bcaa8d4
13 changed files with 681 additions and 216 deletions

12
scripts/ASCII_ART_EVIBES Normal file
View file

@ -0,0 +1,12 @@
=== ==. ===
.=== ==: ==== ===
==== ==- ===
==== === ===
=. ==== === .== === .===== =====- .===.
.=.= == = ===: ==- === ====. :===. ==== === .==:
.=::=== -= ===. ==- === === === ====::::::=== ===-
:== === === === === === === ====.
.. === === === === === === ====
= ====- === === === .===. . :===
.= == ==- === =:========. :========. ======.

View file

@ -1,26 +1,62 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
env_file='.env' if [ ! -d "./evibes" ]; then
printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
if [[ ! -f $env_file ]]; then exit 1
echo "Error: $env_file not found in the current directory." >&2
return 1 2>/dev/null || exit 1
fi fi
while IFS= read -r line || [[ -n $line ]]; do PURPLE="\e[38;2;121;101;209m"
line="${line#"${line%%[![:space:]]*}"}" RESET="\e[0m"
line="${line%"${line##*[![:space:]]}"}" GRAY="\e[90m"
[[ -z $line || $line == \#* ]] && continue
[[ $line != *"="* ]] && continue
SOURCE="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
if [ ! -f "$ART_PATH" ]; then
printf "\e[31m❌ Could not find ASCII art at %s\e[0m\n" "$ART_PATH"
exit 1
fi
while IFS= read -r line; do
printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
done < "$ART_PATH"
printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
ENV_FILE=".env"
if [ ! -f "$ENV_FILE" ]; then
printf "\e[31m.env file not found in the current directory.\e[0m\n"
exit 1
fi
declare -A env_vars
declare -a keys
while IFS= read -r raw; do
line="${raw%%#*}"
line="${line%"${line##*[![:space:]]}"}"
line="${line#"${line%%[![:space:]]*}"}"
[ -z "$line" ] || [[ "$line" != *=* ]] && continue
key="${line%%=*}" key="${line%%=*}"
value="${line#*=}" value="${line#*=}"
if [[ "${value:0:1}" == '"' && "${value: -1}" == '"' ]] || \
if [[ ( $value == \"*\" && $value == *\" ) || ( $value == \'*\' && $value == *\' ) ]]; then [[ "${value:0:1}" == "'" && "${value: -1}" == "'" ]]; then
value="${value:1:-1}" value="${value:1:-1}"
fi fi
export "$key"="$value" export "$key"="$value"
echo "Exported $key" env_vars["$key"]="$value"
done < "$env_file" keys+=("$key")
done < "$ENV_FILE"
if [ "${#keys[@]}" -gt 0 ]; then
IFS=$'\n' sorted=($(sort <<<"${keys[*]}"))
unset IFS
formatted=""
for k in "${sorted[@]}"; do
[ -z "$formatted" ] && formatted="$k=${env_vars[$k]}" \
|| formatted="$formatted;$k=${env_vars[$k]}"
done
printf "%s\n" "$formatted"
fi

View file

@ -1,122 +1,145 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
rand_hex() { if [ ! -d "./evibes" ]; then
openssl rand -hex "$1" printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
} exit 1
prompt_default() {
local name="$1" default="$2" val
read -rp "Enter $name [$default]: " val
printf -v "$name" '%s' "${val:-$default}"
}
prompt_autogen() {
local name="$1" bytes="$2" val
read -rp "Enter $name (leave blank to auto-generate): " val
if [[ -z "$val" ]]; then
printf -v "$name" '%s' "$(rand_hex "$bytes")"
else
printf -v "$name" '%s' "$val"
fi
}
prompt_default EVIBES_PROJECT_NAME "eVibes"
prompt_default EVIBES_FRONTEND_DOMAIN "evibes.com"
prompt_default EVIBES_BASE_DOMAIN "evibes.com"
prompt_default SENTRY_DSN ""
prompt_default DEBUG "1"
prompt_autogen SECRET_KEY 32
prompt_autogen JWT_SIGNING_KEY 64
prompt_default ALLOWED_HOSTS "evibes.com api.evibes.com b2b.evibes.com"
prompt_default CSRF_TRUSTED_ORIGINS "https://evibes.com https://api.evibes.com https://www.evibes.com https://b2b.evibes.com"
prompt_default CORS_ALLOWED_ORIGINS "$CSRF_TRUSTED_ORIGINS"
prompt_default POSTGRES_DB "evibes"
prompt_default POSTGRES_USER "evibes_user"
prompt_autogen POSTGRES_PASSWORD 16
prompt_default DBBACKUP_SFTP_HOST "Your SFTP backup host"
prompt_default DBBACKUP_SFTP_USER "The username to use to log in to that host"
prompt_default DBBACKUP_SFTP_PASS "The password to use to log in to that host"
prompt_autogen ELASTIC_PASSWORD 16
prompt_autogen REDIS_PASSWORD 16
prompt_default PROMETHEUS_USER "evibes"
prompt_autogen PROMETHEUS_PASSWORD 16
prompt_default EMAIL_BACKEND "django.core.mail.backends.smtp.EmailBackend"
prompt_default EMAIL_HOST "smtp.whatever.evibes.com"
prompt_default EMAIL_PORT "465"
prompt_default EMAIL_USE_TLS "0"
prompt_default EMAIL_USE_SSL "1"
prompt_default EMAIL_HOST_USER "your-email-user@whatever.evibes.com"
prompt_default EMAIL_FROM "$EMAIL_HOST_USER"
prompt_default EMAIL_HOST_PASSWORD "SUPERSECRETEMAILHOSTPASSWORD"
prompt_default COMPANY_NAME "eVibes, Inc."
prompt_default COMPANY_PHONE_NUMBER "+888888888888"
prompt_default COMPANY_ADDRESS "The place that does not exist"
prompt_default OPENAI_API_KEY "Haha, really?"
prompt_default ABSTRACT_API_KEY "Haha, really? x2"
prompt_default DEEPL_AUTH_KEY "Haha, really? x3"
if [[ -f .env ]]; then
read -rp ".env already exists and will be overwritten. Press ENTER to continue or Ctrl+C to abort. "
fi fi
cat > .env <<EOF PURPLE="\e[38;2;121;101;209m"
EVIBES_PROJECT_NAME="${EVIBES_PROJECT_NAME}" RESET="\e[0m"
EVIBES_FRONTEND_DOMAIN="${EVIBES_FRONTEND_DOMAIN}" GRAY="\e[90m"
EVIBES_BASE_DOMAIN="${EVIBES_BASE_DOMAIN}"
SENTRY_DSN="${SENTRY_DSN}"
DEBUG=${DEBUG}
SECRET_KEY="${SECRET_KEY}" SOURCE="${BASH_SOURCE[0]:-$0}"
JWT_SIGNING_KEY="${JWT_SIGNING_KEY}" SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
ALLOWED_HOSTS="${ALLOWED_HOSTS}" if [ ! -f "$ART_PATH" ]; then
CSRF_TRUSTED_ORIGINS="${CSRF_TRUSTED_ORIGINS}" printf "\e[31m❌ Could not find ASCII art at %s\e[0m\n" "$ART_PATH"
CORS_ALLOWED_ORIGINS="${CORS_ALLOWED_ORIGINS}" exit 1
fi
POSTGRES_DB="${POSTGRES_DB}" while IFS= read -r line; do
POSTGRES_USER="${POSTGRES_USER}" printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" done < "$ART_PATH"
DBBACKUP_SFTP_HOST="${DBBACKUP_SFTP_HOST}" printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
DBBACKUP_SFTP_USER="${DBBACKUP_SFTP_USER}"
DBBACKUP_SFTP_PASS="${DBBACKUP_SFTP_PASS}"
ELASTIC_PASSWORD="${ELASTIC_PASSWORD}" # prompt for a value with default
prompt_default() {
local name="$1" default="$2" result
read -rp "Enter $name [$default]: " result
printf '%s\n' "${result:-$default}"
}
REDIS_PASSWORD="${REDIS_PASSWORD}" # prompt for a value, auto-generate hex if blank
prompt_autogen() {
local name="$1" bytes="$2" result
read -rp "Enter $name (leave blank to auto-generate): " result
if [ -z "$result" ]; then
# generate $bytes random bytes as hex
result="$(head -c "$bytes" /dev/urandom | od -An -tx1 | tr -d ' \n')"
fi
printf '%s\n' "$result"
}
CELERY_BROKER_URL="redis://:${REDIS_PASSWORD}@redis:6379/0" if [ -f .env ]; then
CELERY_RESULT_BACKEND="redis://:${REDIS_PASSWORD}@redis:6379/0" printf "\e[33m.env already exists and will be overwritten.\e[0m\n"
read -rp "Press Enter to continue or Ctrl+C to abort"
fi
PROMETHEUS_USER="${PROMETHEUS_USER}" PROJECT_NAME=$(prompt_default 'EVIBES_PROJECT_NAME' 'eVibes')
PROMETHEUS_PASSWORD="${PROMETHEUS_PASSWORD}" FRONTEND_DOMAIN=$(prompt_default 'EVIBES_FRONTEND_DOMAIN' 'evibes.com')
BASE_DOMAIN=$(prompt_default 'EVIBES_BASE_DOMAIN' 'evibes.com')
SENTRY_DSN=$(prompt_default 'SENTRY_DSN' '')
DEBUG=$(prompt_default 'DEBUG' '1')
EMAIL_BACKEND="${EMAIL_BACKEND}" SECRET_KEY=$(prompt_autogen 'SECRET_KEY' 32)
EMAIL_HOST="${EMAIL_HOST}" JWT_SIGNING_KEY=$(prompt_autogen 'JWT_SIGNING_KEY' 64)
EMAIL_PORT="${EMAIL_PORT}"
EMAIL_USE_TLS=${EMAIL_USE_TLS}
EMAIL_USE_SSL=${EMAIL_USE_SSL}
EMAIL_HOST_USER="${EMAIL_HOST_USER}"
EMAIL_HOST_PASSWORD="${EMAIL_HOST_PASSWORD}"
EMAIL_FROM="${EMAIL_FROM}"
COMPANY_NAME="${COMPANY_NAME}" ALLOWED_HOSTS=$(prompt_default 'ALLOWED_HOSTS' 'evibes.com api.evibes.com b2b.evibes.com')
COMPANY_PHONE_NUMBER="${COMPANY_PHONE_NUMBER}" CSRF_TRUSTED_ORIGINS=$(prompt_default 'CSRF_TRUSTED_ORIGINS' 'https://evibes.com https://api.evibes.com https://www.evibes.com https://b2b.evibes.com')
COMPANY_ADDRESS="${COMPANY_ADDRESS}" CORS_ALLOWED_ORIGINS="$CSRF_TRUSTED_ORIGINS"
OPENAI_API_KEY="${OPENAI_API_KEY}" POSTGRES_DB=$(prompt_default 'POSTGRES_DB' 'evibes')
ABSTRACT_API_KEY="${ABSTRACT_API_KEY}" POSTGRES_USER=$(prompt_default 'POSTGRES_USER' 'evibes_user')
DEEPL_AUTH_KEY="${DEEPL_AUTH_KEY}" POSTGRES_PASSWORD=$(prompt_autogen 'POSTGRES_PASSWORD' 16)
EOF
echo ".env file generated with fresh values." DBBACKUP_SFTP_HOST=$(prompt_default 'DBBACKUP_SFTP_HOST' 'Your SFTP backup host')
DBBACKUP_SFTP_USER=$(prompt_default 'DBBACKUP_SFTP_USER' 'The username to use to log in to that host')
DBBACKUP_SFTP_PASS=$(prompt_default 'DBBACKUP_SFTP_PASS' 'The password to use to log in to that host')
ELASTIC_PASSWORD=$(prompt_autogen 'ELASTIC_PASSWORD' 16)
REDIS_PASSWORD=$(prompt_autogen 'REDIS_PASSWORD' 16)
PROMETHEUS_USER=$(prompt_default 'PROMETHEUS_USER' 'evibes')
PROMETHEUS_PASSWORD=$(prompt_autogen 'PROMETHEUS_PASSWORD' 16)
EMAIL_BACKEND=$(prompt_default 'EMAIL_BACKEND' 'django.core.mail.backends.smtp.EmailBackend')
EMAIL_HOST=$(prompt_default 'EMAIL_HOST' 'smtp.whatever.evibes.com')
EMAIL_PORT=$(prompt_default 'EMAIL_PORT' '465')
EMAIL_USE_TLS=$(prompt_default 'EMAIL_USE_TLS' '0')
EMAIL_USE_SSL=$(prompt_default 'EMAIL_USE_SSL' '1')
EMAIL_HOST_USER=$(prompt_default 'EMAIL_HOST_USER' 'your-email-user@whatever.evibes.com')
EMAIL_FROM="$EMAIL_HOST_USER"
EMAIL_HOST_PASSWORD=$(prompt_default 'EMAIL_HOST_PASSWORD' 'SUPERSECRETEMAILHOSTPASSWORD')
COMPANY_NAME=$(prompt_default 'COMPANY_NAME' 'eVibes, Inc.')
COMPANY_PHONE_NUMBER=$(prompt_default 'COMPANY_PHONE_NUMBER' '+888888888888')
COMPANY_ADDRESS=$(prompt_default 'COMPANY_ADDRESS' 'The place that does not exist')
OPENAI_API_KEY=$(prompt_default 'OPENAI_API_KEY' 'Haha, really?')
ABSTRACT_API_KEY=$(prompt_default 'ABSTRACT_API_KEY' 'Haha, really? x2')
DEEPL_AUTH_KEY=$(prompt_default 'DEEPL_AUTH_KEY' 'Haha, really? x3')
# Write to .env
{
printf 'EVIBES_PROJECT_NAME="%s"\n' "$PROJECT_NAME"
printf 'EVIBES_FRONTEND_DOMAIN="%s"\n' "$FRONTEND_DOMAIN"
printf 'EVIBES_BASE_DOMAIN="%s"\n' "$BASE_DOMAIN"
printf 'SENTRY_DSN="%s"\n' "$SENTRY_DSN"
printf 'DEBUG=%s\n\n' "$DEBUG"
printf 'SECRET_KEY="%s"\n' "$SECRET_KEY"
printf 'JWT_SIGNING_KEY="%s"\n\n' "$JWT_SIGNING_KEY"
printf 'ALLOWED_HOSTS="%s"\n' "$ALLOWED_HOSTS"
printf 'CSRF_TRUSTED_ORIGINS="%s"\n' "$CSRF_TRUSTED_ORIGINS"
printf 'CORS_ALLOWED_ORIGINS="%s"\n\n' "$CORS_ALLOWED_ORIGINS"
printf 'POSTGRES_DB="%s"\n' "$POSTGRES_DB"
printf 'POSTGRES_USER="%s"\n' "$POSTGRES_USER"
printf 'POSTGRES_PASSWORD="%s"\n\n' "$POSTGRES_PASSWORD"
printf 'DBBACKUP_SFTP_HOST="%s"\n' "$DBBACKUP_SFTP_HOST"
printf 'DBBACKUP_SFTP_USER="%s"\n' "$DBBACKUP_SFTP_USER"
printf 'DBBACKUP_SFTP_PASS="%s"\n\n' "$DBBACKUP_SFTP_PASS"
printf 'ELASTIC_PASSWORD="%s"\n\n' "$ELASTIC_PASSWORD"
printf 'REDIS_PASSWORD="%s"\n' "$REDIS_PASSWORD"
printf 'CELERY_BROKER_URL="redis://:%s@redis:6379/0"\n' "$REDIS_PASSWORD"
printf 'CELERY_RESULT_BACKEND="redis://:%s@redis:6379/0"\n\n' "$REDIS_PASSWORD"
printf 'PROMETHEUS_USER="%s"\n' "$PROMETHEUS_USER"
printf 'PROMETHEUS_PASSWORD="%s"\n\n' "$PROMETHEUS_PASSWORD"
printf 'EMAIL_BACKEND="%s"\n' "$EMAIL_BACKEND"
printf 'EMAIL_HOST="%s"\n' "$EMAIL_HOST"
printf 'EMAIL_PORT="%s"\n' "$EMAIL_PORT"
printf 'EMAIL_USE_TLS=%s\n' "$EMAIL_USE_TLS"
printf 'EMAIL_USE_SSL=%s\n' "$EMAIL_USE_SSL"
printf 'EMAIL_HOST_USER="%s"\n' "$EMAIL_HOST_USER"
printf 'EMAIL_HOST_PASSWORD="%s"\n' "$EMAIL_HOST_PASSWORD"
printf 'EMAIL_FROM="%s"\n\n' "$EMAIL_FROM"
printf 'COMPANY_NAME="%s"\n' "$COMPANY_NAME"
printf 'COMPANY_PHONE_NUMBER="%s"\n' "$COMPANY_PHONE_NUMBER"
printf 'COMPANY_ADDRESS="%s"\n\n' "$COMPANY_ADDRESS"
printf 'OPENAI_API_KEY="%s"\n\n' "$OPENAI_API_KEY"
printf 'ABSTRACT_API_KEY="%s"\n\n' "$ABSTRACT_API_KEY"
printf 'DEEPL_AUTH_KEY="%s"\n' "$DEEPL_AUTH_KEY"
} > .env
printf "\e[32m.env file generated with fresh values.\e[0m\n"

View file

@ -1,35 +1,63 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
if [[ ! -f .env ]]; then if [ ! -d "./evibes" ]; then
echo "Warning: .env file not found. Exiting without running Docker steps." printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
exit 1
fi
PURPLE="\e[38;2;121;101;209m"
RESET="\e[0m"
GRAY="\e[90m"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
if [ ! -f "$ART_PATH" ]; then
printf "\e[31m❌ Could not find ASCII art at %s\e[0m\n" "$ART_PATH"
exit 1
fi
while IFS= read -r line; do
printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
done < "$ART_PATH"
printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
if [ ! -f .env ]; then
printf "\e[33m.env file not found. Exiting without running Docker steps.\e[0m\n"
exit 0 exit 0
fi fi
cpuCount=$(nproc) CPU_COUNT=$(nproc 2>/dev/null || sysctl -n hw.ncpu)
if (( cpuCount < 4 )); then if [ "$CPU_COUNT" -lt 4 ]; then
echo "Error: Insufficient CPU cores: $cpuCount detected. Minimum 4 required." >&2 printf "\e[31mInsufficient CPU cores: %d detected. Minimum 4 required.\e[0m\n" "$CPU_COUNT"
exit 1 exit 1
fi fi
mem_kb=$(awk '/MemTotal:/ {print $2}' /proc/meminfo) if [ -f /proc/meminfo ]; then
totalMemGB=$(awk "BEGIN {printf \"%.2f\", $mem_kb/1024/1024}") MEM_KB=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
if (( mem_kb < 6*1024*1024 )); then MEM_GB=$(awk "BEGIN {printf \"%.2f\", ${MEM_KB}/1024/1024}")
echo "Error: Insufficient RAM: ${totalMemGB} GB detected. Minimum 6 GB required." >&2 else
MEM_BYTES=$(vm_stat | awk '/Pages free/ {print $3 * 4096}')
MEM_GB=$(awk "BEGIN {printf \"%.2f\", ${MEM_BYTES}/1024/1024/1024}")
fi
if (( $(echo "$MEM_GB < 6" | bc -l) )); then
printf "\e[31mInsufficient RAM: %.2fGB detected. Minimum 6 GB required.\e[0m\n" "$MEM_GB"
exit 1 exit 1
fi fi
avail_kb=$(df --output=avail . | tail -n1) FREE_GB=$(df -BG . | awk 'NR==2 {gsub("G","",$4); print $4}')
freeGB=$(awk "BEGIN {printf \"%.2f\", $avail_kb/1024/1024}") if [ "$FREE_GB" -lt 20 ]; then
if (( avail_kb < 20*1024*1024 )); then printf "\e[31mInsufficient free disk space: %dGB available. Minimum 20 GB required.\e[0m\n" "$FREE_GB"
echo "Error: Insufficient free disk space: ${freeGB} GB available. Minimum 20 GB required." >&2
exit 1 exit 1
fi fi
echo "System requirements met: CPU cores=${cpuCount}, RAM=${totalMemGB}GB, FreeDisk=${freeGB}GB" printf "\e[32mSystem requirements met: CPU cores=%d, RAM=%.2fGB, FreeDisk=%dGB\e[0m\n" "$CPU_COUNT" "$MEM_GB" "$FREE_GB"
echo "Pulling related images..." printf "\e[36mPulling related images…\e[0m\n"
docker compose pull docker compose pull --ansi never
echo "Building the project's images..." printf "\e[36mBuilding the project's images…\e[0m\n"
docker compose build docker compose build --ansi never

View file

@ -1,35 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
run_cmd() { if [ ! -d "./evibes" ]; then
local msg=$1; shift printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
printf "%s... " "$msg" exit 1
"$@" fi
printf "OK\n"
}
echo PURPLE="\e[38;2;121;101;209m"
RESET="\e[0m"
GRAY="\e[90m"
CYAN="\e[36m"
run_cmd "Stopping services (down)" \ SOURCE="${BASH_SOURCE[0]:-$0}"
docker compose down SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
run_cmd "Rebuilding services" \ if [ ! -f "$ART_PATH" ]; then
docker compose build printf "\e[31m❌ Could not find ASCII art at %s\e[0m\n" "$ART_PATH"
exit 1
fi
run_cmd "Starting services" \ while IFS= read -r line; do
docker compose up -d printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
done < "$ART_PATH"
run_cmd "Applying database migrations" \ printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
docker compose exec app poetry run python manage.py migrate --no-input
run_cmd "Collecting static files" \ printf "%bStopping services…%b\n" "$CYAN" "$RESET"
docker compose exec app poetry run python manage.py collectstatic --no-input docker compose down --ansi never
run_cmd "Setting default caches" \ printf "%bRebuilding services…%b\n" "$CYAN" "$RESET"
docker compose exec app poetry run python manage.py set_default_caches docker compose build --ansi never
run_cmd "Cleaning up unused Docker data" \ printf "%bStarting services…%b\n" "$CYAN" "$RESET"
docker system prune -f docker compose up -d --ansi never
echo printf "%bApplying database migrations…%b\n" "$CYAN" "$RESET"
echo "All done! eVibes is up and running." docker compose exec app poetry run python manage.py migrate --no-input
printf "%bCollecting static files…%b\n" "$CYAN" "$RESET"
docker compose exec app poetry run python manage.py collectstatic --no-input
printf "%bSetting default caches…%b\n" "$CYAN" "$RESET"
docker compose exec app poetry run python manage.py set_default_caches
printf "%bCleaning up unused Docker data…%b\n" "$CYAN" "$RESET"
docker system prune -f
printf "\n\e[37mAll done! eVibes is up and running.\e[0m\n"

View file

@ -1,11 +1,60 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
echo "Starting Docker Compose services..." if [ ! -d "./evibes" ]; then
printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
if ! docker compose up --no-build --detach --wait; then
echo "Error: Images are not pulled/built. Please run the install.sh script first." >&2
exit 1 exit 1
fi fi
echo "Containers are up and healthy." PURPLE="\e[38;2;121;101;209m"
RESET="\e[0m"
GRAY="\e[90m"
SOURCE="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
if [ ! -f "$ART_PATH" ]; then
printf "\e[31m❌ Could not find ASCII art at %s\e[0m\n" "$ART_PATH"
exit 1
fi
while IFS= read -r line; do
printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
done < "$ART_PATH"
printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
printf "\e[32mVerifying all images are present…\e[0m\n"
if ! command -v jq >/dev/null 2>&1; then
printf "\e[31mjq is required for verifying images. Please install jq.\e[0m\n"
exit 1
fi
images=$(docker compose config --format json | jq -r '.services[]?.image // empty')
for image in $images; do
if ! docker image inspect "$image" >/dev/null 2>&1; then
printf "\e[31mRequired images not found. Please run install.sh first.\e[0m\n"
exit 1
fi
printf " • Found image: %s\n" "$image"
done
printf "\e[36mStarting services…\e[0m\n"
docker compose up --no-build --detach --wait --ansi never
printf "\e[36mApplying migrations…\e[0m\n"
docker compose exec app poetry run python manage.py migrate --no-input
printf "\e[36mCollecting static files…\e[0m\n"
docker compose exec app poetry run python manage.py collectstatic --no-input
printf "\e[36mSetting default caches…\e[0m\n"
docker compose exec app poetry run python manage.py set_default_caches
printf "\e[36mCleaning up…\e[0m\n"
docker compose exec app poetry run python manage.py set_default_caches
printf "\e[32mAll done! eVibes is up and running.\e[0m\n"

39
scripts/Unix/uninstall.sh Normal file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
if [ ! -d "./evibes" ]; then
printf "\e[31m❌ Please run this script from the project's root (where the 'evibes' directory lives).\e[0m\n"
exit 1
fi
PURPLE="\e[38;2;121;101;209m"
RESET="\e[0m"
GRAY="\e[90m"
CYAN="\e[36m"
RED="\e[31m"
SOURCE="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
ART_PATH="$SCRIPT_DIR/../ASCII_ART_EVIBES"
if [ ! -f "$ART_PATH" ]; then
printf "%b❌ Could not find ASCII art at %s%b\n" "$RED" "$ART_PATH" "$RESET"
exit 1
fi
while IFS= read -r line; do
printf "%b%s%b\n" "$PURPLE" "$line" "$RESET"
done < "$ART_PATH"
printf "\n%bby WISELESS TEAM%b\n\n" "$GRAY" "$RESET"
printf "%bKilling services…%b\n" "$CYAN" "$RESET"
docker compose down --ansi never
printf "%bCleaning up Docker data…%b\n" "$CYAN" "$RESET"
docker system prune -f
printf "%bRemoving related files…%b\n" "$CYAN" "$RESET"
rm -rf ./services_data ./media ./static
printf "%bBye-bye, hope you return later!%b\n" "$RED" "$RESET"

View file

@ -2,6 +2,62 @@
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
$Spinner = @('|', '/', '-', '\')
$Colors = @('White', 'Gray')
$Delay = 100
function Invoke-Spinner
{
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Arguments,
[Parameter(Mandatory)][string]$Message
)
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}… " -f $Message)
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = "docker"
$si.Arguments = "$Arguments --ansi never"
$si.RedirectStandardOutput = $true
$si.RedirectStandardError = $true
$si.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($si)
$i = 0
while (-not $p.HasExited)
{
$frame = $Spinner[$i % $Spinner.Length]
$col = $Colors[$i % $Colors.Length]
Write-Host -NoNewLine -ForegroundColor $col $frame
Start-Sleep -Milliseconds $Delay
Write-Host -NoNewLine "`b"
$i++
}
$p.WaitForExit()
Write-Host -ForegroundColor Green ""
}
$envFile = '.env' $envFile = '.env'
if (-not (Test-Path $envFile)) if (-not (Test-Path $envFile))
@ -48,4 +104,4 @@ if ($envVars.Count -gt 0)
"$( $_.Key )=$( $_.Value )" "$( $_.Key )=$( $_.Value )"
}) -join ';' }) -join ';'
Write-Host $formatted Write-Host $formatted
} }

View file

@ -2,6 +2,29 @@
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
function Get-RandomHex function Get-RandomHex
{ {
param([int]$Bytes) param([int]$Bytes)

View file

@ -2,6 +2,29 @@
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
if (-not (Test-Path '.env')) if (-not (Test-Path '.env'))
{ {
Write-Warning ".env file not found. Exiting without running Docker steps." Write-Warning ".env file not found. Exiting without running Docker steps."
@ -33,13 +56,40 @@ if ($freeGB -lt 20)
exit 1 exit 1
} }
Write-Host "System requirements met:" ` Write-Host "System requirements met: CPU cores=$cpuCount, RAM=${totalMemGB}GB, FreeDisk=${freeGB}GB" -ForegroundColor Green
"CPU cores=$cpuCount," `
"RAM=${totalMemGB}GB," `
"FreeDisk=${freeGB}GB" -ForegroundColor Green
Write-Host "Pulling related images..." -ForegroundColor Green $Spinner = @('|', '/', '-', '\')
docker compose pull $Colors = @('White', 'Gray')
$Delay = 100
Write-Host "Building the project's images..." -ForegroundColor Green function Invoke-Spinner
docker compose build {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Arguments,
[Parameter(Mandatory)][string]$Message
)
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}… " -f $Message)
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = "docker"
$si.Arguments = "$Arguments --ansi never"
$si.RedirectStandardOutput = $true
$si.RedirectStandardError = $true
$si.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($si)
$i = 0
while (-not $p.HasExited)
{
$frame = $Spinner[$i % $Spinner.Length]
$col = $Colors[$i % $Colors.Length]
Write-Host -NoNewLine -ForegroundColor $col $frame
Start-Sleep -Milliseconds $Delay
Write-Host -NoNewline "`b"
$i++
}
$p.WaitForExit()
Write-Host -ForegroundColor Green ""
}
Invoke-Spinner -Arguments "compose pull" -Message "Pulling related images"
Invoke-Spinner -Arguments "compose build" -Message "Building the project's images"

View file

@ -1,5 +1,28 @@
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
$Spinner = @('|', '/', '-', '\') $Spinner = @('|', '/', '-', '\')
$Colors = @('White', 'Gray') $Colors = @('White', 'Gray')
$Delay = 100 $Delay = 100
@ -8,53 +31,37 @@ function Invoke-Spinner
{ {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)][string]$Arguments,
[string]$Arguments, [Parameter(Mandatory)][string]$Message
[Parameter(Mandatory)]
[string]$Message
) )
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}… " -f $Message)
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}... " -f $Message) $si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = "docker"
$startInfo = New-Object System.Diagnostics.ProcessStartInfo $si.Arguments = "$Arguments --ansi never"
$startInfo.FileName = "docker" $si.RedirectStandardOutput = $true
$startInfo.Arguments = $Arguments + " --ansi never" $si.RedirectStandardError = $true
$startInfo.RedirectStandardOutput = $true $si.UseShellExecute = $false
$startInfo.RedirectStandardError = $true $p = [System.Diagnostics.Process]::Start($si)
$startInfo.UseShellExecute = $false
$proc = [System.Diagnostics.Process]::Start($startInfo)
$i = 0 $i = 0
while (-not $proc.HasExited) while (-not $p.HasExited)
{ {
$frame = $Spinner[$i % $Spinner.Length] $frame = $Spinner[$i % $Spinner.Length]
$color = $Colors[$i % $Colors.Length] $col = $Colors[$i % $Colors.Length]
Write-Host -NoNewLine -ForegroundColor $color $frame Write-Host -NoNewLine -ForegroundColor $col $frame
Start-Sleep -Milliseconds $Delay Start-Sleep -Milliseconds $Delay
Write-Host -NoNewLine "`b" Write-Host -NoNewline "`b"
$i++ $i++
} }
$proc.WaitForExit() $p.WaitForExit()
Write-Host -ForegroundColor Green "" Write-Host -ForegroundColor Green ""
} }
Write-Host "" Invoke-Spinner -Arguments "compose down" -Message "Stopping services"
Invoke-Spinner -Arguments "compose down" ` Invoke-Spinner -Arguments "compose build" -Message "Rebuilding services"
-Message "Stopping services (down)" Invoke-Spinner -Arguments "compose up -d" -Message "Starting services"
Invoke-Spinner -Arguments "compose build" ` Invoke-Spinner -Arguments "compose exec app poetry run python manage.py migrate --no-input" -Message "Applying database migrations"
-Message "Rebuilding services" Invoke-Spinner -Arguments "compose exec app poetry run python manage.py collectstatic --no-input" -Message "Collecting static files"
Invoke-Spinner -Arguments "compose up -d" ` Invoke-Spinner -Arguments "compose exec app poetry run python manage.py set_default_caches" -Message "Setting default caches"
-Message "Starting services" Invoke-Spinner -Arguments "system prune -f" -Message "Cleaning up unused Docker data"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py migrate --no-input" `
-Message "Applying database migrations"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py collectstatic --no-input" `
-Message "Collecting static files"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py set_default_caches" `
-Message "Setting default caches"
Invoke-Spinner -Arguments "system prune -f" `
-Message "Cleaning up unused Docker data"
Write-Host "`nAll done! eVibes is up and running." -ForegroundColor White Write-Host "`nAll done! eVibes is up and running." -ForegroundColor White

View file

@ -2,6 +2,29 @@
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
Write-Host "Verifying all images are present…" -ForegroundColor Green Write-Host "Verifying all images are present…" -ForegroundColor Green
$config = docker compose config --format json | ConvertFrom-Json $config = docker compose config --format json | ConvertFrom-Json
@ -26,6 +49,43 @@ foreach ($prop in $config.services.PSObject.Properties)
Write-Host " • Found image: $image" Write-Host " • Found image: $image"
} }
Write-Host "All images present, starting services…" -ForegroundColor Green $Spinner = @('|', '/', '-', '\')
docker compose up --no-build --detach --wait | Out-Null $Colors = @('White', 'Gray')
Write-Host "Containers are up and healthy." -ForegroundColor Green $Delay = 100
function Invoke-Spinner
{
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Arguments,
[Parameter(Mandatory)][string]$Message
)
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}… " -f $Message)
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = "docker"
$si.Arguments = "$Arguments --ansi never"
$si.RedirectStandardOutput = $true
$si.RedirectStandardError = $true
$si.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($si)
$i = 0
while (-not $p.HasExited)
{
$frame = $Spinner[$i % $Spinner.Length]
$col = $Colors[$i % $Colors.Length]
Write-Host -NoNewLine -ForegroundColor $col $frame
Start-Sleep -Milliseconds $Delay
Write-Host -NoNewLine "`b"
$i++
}
$p.WaitForExit()
Write-Host -ForegroundColor Green ""
}
Invoke-Spinner -Arguments "compose up --no-build --detach --wait" -Message "Starting services"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py migrate --no-input" -Message "Applying migrations"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py collectstatic --no-input" -Message "Collecting static files"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py set_default_caches" -Message "Setting default caches"
Invoke-Spinner -Arguments "compose exec app poetry run python manage.py set_default_caches" -Message "Cleaning up"
Write-Host "All done! eVibes is up and running." -ForegroundColor Green

View file

@ -0,0 +1,67 @@
#!/usr/bin/env pwsh
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -Path ".\evibes" -PathType Container))
{
Write-Host "❌ Please run this script from the project's root (where the 'evibes' directory lives)." -ForegroundColor Red
exit 1
}
$purple = "`e[38;2;121;101;209m"
$reset = "`e[0m"
$artPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\ASCII_ART_EVIBES'
if (-not (Test-Path $artPath))
{
Write-Host "❌ Could not find ASCII art at $artPath" -ForegroundColor Red
exit 1
}
$art = Get-Content -Raw -Path $artPath
$art -split "`r?`n" | ForEach-Object {
Write-Host "$purple$_$reset"
}
Write-Host "`nby WISELESS TEAM`n" -ForegroundColor Gray
$Spinner = @('|', '/', '-', '\')
$Colors = @('White', 'Gray')
$Delay = 100
function Invoke-Spinner
{
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Arguments,
[Parameter(Mandatory)][string]$Message
)
Write-Host -NoNewLine -ForegroundColor Cyan ("{0}… " -f $Message)
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = "docker"
$si.Arguments = "$Arguments --ansi never"
$si.RedirectStandardOutput = $true
$si.RedirectStandardError = $true
$si.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($si)
$i = 0
while (-not $p.HasExited)
{
$frame = $Spinner[$i % $Spinner.Length]
$col = $Colors[$i % $Colors.Length]
Write-Host -NoNewLine -ForegroundColor $col $frame
Start-Sleep -Milliseconds $Delay
Write-Host -NoNewline "`b"
$i++
}
$p.WaitForExit()
Write-Host -ForegroundColor Green ""
}
Invoke-Spinner -Arguments "compose down" -Message "Killing services"
Invoke-Spinner -Arguments "system prune -f" -Message "Cleaning up Docker data"
Write-Host -ForegroundColor Cyan "Removing related files..."
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./services_data
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./media
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./static
Write-Host -ForegroundColor Red "Bye-bye, hope you return later!"