Features: 1) Introduce CLI utility lessy.py to streamline project management tasks (e.g., install, run, restart, test); 2) Add Unix and Windows script commands for make-messages and compile-messages to improve translation workflow; 3) Include shared utility libraries (utils.sh, utils.ps1) for reusable functions across scripts.
Fixes: 1) Remove obsolete `reboot` scripts for Unix and Windows to prevent redundancy; 2) Update Windows `test.ps1` to handle omitted coverage patterns and improve error feedback. Extra: 1) Refactor Windows scripts (`make-messages.ps1`, `compile-messages.ps1`, `backup.ps1`) to use shared utilities for better consistency and output formatting; 2) Add spinner-based progress indicators to enhance user experience in interactive environments.
This commit is contained in:
parent
4c7b40b899
commit
42b40627de
23 changed files with 1218 additions and 237 deletions
129
lessy.py
Executable file
129
lessy.py
Executable file
|
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python3
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
OS = platform.system().lower()
|
||||
SCRIPT_EXT = ".ps1" if OS == "windows" else ".sh"
|
||||
SCRIPT_DIR = "Windows" if OS == "windows" else "Unix"
|
||||
PROJECT_ROOT = Path(__file__).parent.absolute()
|
||||
SCRIPTS_PATH = PROJECT_ROOT / "scripts" / SCRIPT_DIR
|
||||
|
||||
|
||||
def get_script_path(command: str) -> Path:
|
||||
return SCRIPTS_PATH / f"{command}{SCRIPT_EXT}"
|
||||
|
||||
|
||||
def run_script(script_name: str, *args) -> int:
|
||||
script_path = get_script_path(script_name)
|
||||
|
||||
if not script_path.exists():
|
||||
click.secho(f"Error: Script '{script_name}' not found at {script_path}", fg="red", err=True)
|
||||
return 1
|
||||
|
||||
if OS == "windows":
|
||||
cmd = ["pwsh", "-File", str(script_path)]
|
||||
else:
|
||||
cmd = ["bash", str(script_path)]
|
||||
|
||||
cmd.extend(args)
|
||||
|
||||
try:
|
||||
result = subprocess.run(cmd, cwd=PROJECT_ROOT)
|
||||
return result.returncode
|
||||
except FileNotFoundError:
|
||||
shell_name = "PowerShell" if OS == "windows" else "bash"
|
||||
click.secho(f"Error: {shell_name} not found. Please ensure it's installed.", fg="red", err=True)
|
||||
return 127
|
||||
except KeyboardInterrupt:
|
||||
click.secho("\nOperation cancelled by user.", fg="yellow")
|
||||
return 130
|
||||
|
||||
|
||||
@click.group(
|
||||
context_settings={"help_option_names": ["-h", "--help"]},
|
||||
invoke_without_command=True,
|
||||
)
|
||||
@click.pass_context
|
||||
def cli(ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
click.echo(ctx.get_help())
|
||||
|
||||
|
||||
@cli.command()
|
||||
def install():
|
||||
return sys.exit(run_script("install"))
|
||||
|
||||
|
||||
@cli.command()
|
||||
def run():
|
||||
return sys.exit(run_script("run"))
|
||||
|
||||
|
||||
@cli.command()
|
||||
def restart():
|
||||
return sys.exit(run_script("restart"))
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("-r", "--report", type=click.Choice(["xml", "html"]), help="Generate coverage report (xml or html)")
|
||||
def test(report):
|
||||
args = []
|
||||
if report:
|
||||
args.extend(["-r", report])
|
||||
return sys.exit(run_script("test", *args))
|
||||
|
||||
|
||||
@cli.command()
|
||||
def uninstall():
|
||||
if click.confirm("This will remove all Docker containers, volumes, and generated files. Continue?"):
|
||||
return sys.exit(run_script("uninstall"))
|
||||
else:
|
||||
click.secho("Uninstall cancelled.", fg="yellow")
|
||||
return 0
|
||||
|
||||
|
||||
@cli.command()
|
||||
def backup():
|
||||
return sys.exit(run_script("backup"))
|
||||
|
||||
|
||||
@cli.command(name="generate-env")
|
||||
def generate_env():
|
||||
return sys.exit(run_script("generate-environment-file"))
|
||||
|
||||
|
||||
@cli.command(name="export-env")
|
||||
def export_env():
|
||||
return sys.exit(run_script("export-environment-file"))
|
||||
|
||||
|
||||
@cli.command(name="make-messages")
|
||||
def make_messages():
|
||||
return sys.exit(run_script("make-messages"))
|
||||
|
||||
|
||||
@cli.command(name="compile-messages")
|
||||
def compile_messages():
|
||||
return sys.exit(run_script("compile-messages"))
|
||||
|
||||
|
||||
@cli.command()
|
||||
def info():
|
||||
click.echo(f"{'='*60}")
|
||||
click.secho("lessy - eVibes Project CLI", fg="cyan", bold=True)
|
||||
click.echo(f"{'='*60}")
|
||||
click.echo(f"Operating System: {platform.system()} ({platform.release()})")
|
||||
click.echo(f"Python Version: {platform.python_version()}")
|
||||
click.echo(f"Architecture: {platform.machine()}")
|
||||
click.echo(f"Project Root: {PROJECT_ROOT}")
|
||||
click.echo(f"Scripts Directory: {SCRIPTS_PATH}")
|
||||
click.echo(f"Script Extension: {SCRIPT_EXT}")
|
||||
click.echo(f"{'='*60}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
|
@ -3,10 +3,21 @@ set -euo pipefail
|
|||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
echo "Starting database backup process..."
|
||||
docker compose exec app uv run manage.py dbbackup
|
||||
echo "Database backup created under ./dbbackup"
|
||||
# Database backup
|
||||
log_step "Starting database backup process..."
|
||||
if ! docker compose exec app uv run manage.py dbbackup; then
|
||||
log_error "Database backup failed"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Database backup created under ./dbbackup"
|
||||
|
||||
echo "Starting media backup process..."
|
||||
docker compose exec app uv run manage.py mediabackup
|
||||
echo "Media backup created under ./dbbackup"
|
||||
# Media backup
|
||||
log_step "Starting media backup process..."
|
||||
if ! docker compose exec app uv run manage.py mediabackup; then
|
||||
log_error "Media backup failed"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Media backup created under ./dbbackup"
|
||||
|
||||
echo
|
||||
log_result "Backup completed successfully!"
|
||||
|
|
|
|||
28
scripts/Unix/compile-messages.sh
Executable file
28
scripts/Unix/compile-messages.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
log_warning ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check placeholders
|
||||
log_step "Checking placeholders in PO files..."
|
||||
if ! docker compose exec app uv run manage.py check_translated -l ALL -a ALL; then
|
||||
log_error "PO files have placeholder issues"
|
||||
exit 1
|
||||
fi
|
||||
log_success "PO files have no placeholder issues!"
|
||||
|
||||
# Compile messages
|
||||
log_step "Compiling PO files into MO files..."
|
||||
if ! docker compose exec app uv run manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans; then
|
||||
log_error "Failed to compile messages"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Compiled successfully!"
|
||||
|
||||
echo
|
||||
log_result "Translation compilation complete!"
|
||||
|
|
@ -4,41 +4,30 @@ set -euo pipefail
|
|||
source ./scripts/Unix/starter.sh
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
echo ".env file not found. Exiting without running Docker steps." >&2
|
||||
log_warning ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cpu_count=$(getconf _NPROCESSORS_ONLN)
|
||||
if [ "$cpu_count" -lt 4 ]; then
|
||||
# Check system requirements
|
||||
if ! check_system_requirements 4 6 20; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f /proc/meminfo ]; then
|
||||
mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $mem_kb/1024/1024}")
|
||||
else
|
||||
total_mem_bytes=$(sysctl -n hw.memsize)
|
||||
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $total_mem_bytes/1024/1024/1024}")
|
||||
fi
|
||||
if ! awk "BEGIN {exit !($total_mem_gb >= 6)}"; then
|
||||
# Pull Docker images
|
||||
log_step "Pulling images..."
|
||||
if ! docker compose pull; then
|
||||
log_error "Failed to pull Docker images"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Images pulled successfully"
|
||||
|
||||
avail_kb=$(df -k . | tail -1 | awk '{print $4}')
|
||||
free_gb=$(awk "BEGIN {printf \"%.2f\", $avail_kb/1024/1024}")
|
||||
if ! awk "BEGIN {exit !($free_gb >= 20)}"; then
|
||||
# Build Docker images
|
||||
log_step "Building images..."
|
||||
if ! docker compose build; then
|
||||
log_error "Failed to build Docker images"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "System requirements met: CPU cores=$cpu_count, RAM=${total_mem_gb}GB, FreeDisk=${free_gb}GB"
|
||||
|
||||
echo "Pulling images"
|
||||
docker compose pull
|
||||
echo "Images pulled successfully"
|
||||
|
||||
echo "Building images"
|
||||
docker compose build
|
||||
echo "Images built successfully"
|
||||
log_success "Images built successfully"
|
||||
|
||||
echo
|
||||
echo "You can now use run.sh script."
|
||||
log_result "You can now use run.sh script or run: ./lessy.py run"
|
||||
|
|
|
|||
44
scripts/Unix/make-messages.sh
Executable file
44
scripts/Unix/make-messages.sh
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
log_warning ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove old fuzzy entries
|
||||
log_step "Remove old fuzzy entries..."
|
||||
if ! docker compose exec app uv run manage.py fix_fuzzy; then
|
||||
log_error "Failed to remove old fuzzy entries"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Old fuzzy entries removed successfully!"
|
||||
|
||||
# Update PO files
|
||||
log_step "Updating PO files..."
|
||||
if ! docker compose exec app uv run manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans; then
|
||||
log_error "Failed to update PO files"
|
||||
exit 1
|
||||
fi
|
||||
log_success "PO files updated successfully!"
|
||||
|
||||
# Fix new fuzzy entries
|
||||
log_step "Fixing new fuzzy entries..."
|
||||
if ! docker compose exec app uv run manage.py fix_fuzzy; then
|
||||
log_error "Failed to fix new fuzzy entries"
|
||||
exit 1
|
||||
fi
|
||||
log_success "New fuzzy entries fixed successfully!"
|
||||
|
||||
# Translate with DeepL
|
||||
log_step "Translating with DeepL..."
|
||||
if ! docker compose exec app uv run manage.py deepl_translate -l ALL -a ALL; then
|
||||
log_error "Translation failed"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Translated successfully!"
|
||||
|
||||
echo
|
||||
log_result "You can now use compile-messages.sh script or run: ./lessy.py compile-messages"
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
echo "Shutting down..."
|
||||
docker compose down
|
||||
echo "Services were shut down successfully!"
|
||||
|
||||
echo "Spinning services up..."
|
||||
docker compose up -d --build --wait
|
||||
echo "Services are up and healthy!"
|
||||
|
||||
echo "Completing pre-run tasks..."
|
||||
docker compose exec app uv run manage.py migrate --no-input --verbosity 0
|
||||
docker compose exec app uv run manage.py initialize
|
||||
docker compose exec app uv run manage.py set_default_caches
|
||||
docker compose exec app uv run manage.py search_index --rebuild -f
|
||||
docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0
|
||||
echo "Pre-run tasks completed successfully!"
|
||||
|
||||
echo "Cleaning up unused Docker data..."
|
||||
docker system prune -f
|
||||
echo "Unused Docker data cleaned successfully!"
|
||||
|
||||
echo "All done! eVibes is up and running!"
|
||||
65
scripts/Unix/restart.sh
Executable file
65
scripts/Unix/restart.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
# Shutdown services
|
||||
log_step "Shutting down..."
|
||||
if ! docker compose down; then
|
||||
log_error "Failed to shut down services"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Services were shut down successfully!"
|
||||
|
||||
# Rebuild and start services
|
||||
log_step "Spinning services up with rebuild..."
|
||||
if ! docker compose up -d --build --wait; then
|
||||
log_error "Failed to start services"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Services are up and healthy!"
|
||||
|
||||
# Run pre-run tasks
|
||||
log_step "Completing pre-run tasks..."
|
||||
|
||||
log_info " → Running migrations..."
|
||||
if ! docker compose exec app uv run manage.py migrate --no-input --verbosity 0; then
|
||||
log_error "Migrations failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Initializing..."
|
||||
if ! docker compose exec app uv run manage.py initialize; then
|
||||
log_error "Initialization failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Setting default caches..."
|
||||
if ! docker compose exec app uv run manage.py set_default_caches; then
|
||||
log_error "Cache setup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Rebuilding search index..."
|
||||
if ! docker compose exec app uv run manage.py search_index --rebuild -f; then
|
||||
log_error "Search index rebuild failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Collecting static files..."
|
||||
if ! docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0; then
|
||||
log_error "Static files collection failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Pre-run tasks completed successfully!"
|
||||
|
||||
# Cleanup
|
||||
log_step "Cleaning up unused Docker data..."
|
||||
if ! docker system prune -f; then
|
||||
log_warning "Docker cleanup had issues, but continuing..."
|
||||
fi
|
||||
log_success "Unused Docker data cleaned successfully!"
|
||||
|
||||
echo
|
||||
log_result "All done! eVibes is up and running!"
|
||||
|
|
@ -3,36 +3,72 @@ set -euo pipefail
|
|||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
echo "Verifying all images are present..."
|
||||
# Verify Docker images
|
||||
log_step "Verifying all images are present..."
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
images=$(docker compose config --format json | jq -r '.services[].image // empty')
|
||||
if [ -n "$images" ]; then
|
||||
for image in $images; do
|
||||
if ! docker image inspect "$image" > /dev/null 2>&1; then
|
||||
echo "Required images not found. Please run install.sh first." >&2
|
||||
log_error "Required images not found. Please run install.sh first."
|
||||
exit 1
|
||||
fi
|
||||
echo " - Found image: $image"
|
||||
log_info " • Found image: $image"
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo "jq is not installed; skipping image verification step."
|
||||
log_warning "jq is not installed; skipping image verification step."
|
||||
fi
|
||||
|
||||
echo "Spinning services up..."
|
||||
docker compose up --no-build --detach --wait
|
||||
echo "Services are up and healthy!"
|
||||
# Start services
|
||||
log_step "Spinning services up..."
|
||||
if ! docker compose up --no-build --detach --wait; then
|
||||
log_error "Failed to start services"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Services are up and healthy!"
|
||||
|
||||
echo "Completing pre-run tasks..."
|
||||
docker compose exec app uv run manage.py migrate --no-input --verbosity 0
|
||||
docker compose exec app uv run manage.py initialize
|
||||
docker compose exec app uv run manage.py set_default_caches
|
||||
docker compose exec app uv run manage.py search_index --rebuild -f
|
||||
docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0
|
||||
echo "Pre-run tasks completed successfully!"
|
||||
# Run pre-run tasks
|
||||
log_step "Completing pre-run tasks..."
|
||||
|
||||
echo "Cleaning unused Docker data..."
|
||||
docker system prune -f
|
||||
echo "Unused Docker data cleaned successfully!"
|
||||
log_info " → Running migrations..."
|
||||
if ! docker compose exec app uv run manage.py migrate --no-input --verbosity 0; then
|
||||
log_error "Migrations failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All done! eVibes is up and running!"
|
||||
log_info " → Initializing..."
|
||||
if ! docker compose exec app uv run manage.py initialize; then
|
||||
log_error "Initialization failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Setting default caches..."
|
||||
if ! docker compose exec app uv run manage.py set_default_caches; then
|
||||
log_error "Cache setup failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Rebuilding search index..."
|
||||
if ! docker compose exec app uv run manage.py search_index --rebuild -f; then
|
||||
log_error "Search index rebuild failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Collecting static files..."
|
||||
if ! docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0; then
|
||||
log_error "Static files collection failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Pre-run tasks completed successfully!"
|
||||
|
||||
# Cleanup
|
||||
log_step "Cleaning unused Docker data..."
|
||||
if ! docker system prune -f; then
|
||||
log_warning "Docker cleanup had issues, but continuing..."
|
||||
fi
|
||||
log_success "Unused Docker data cleaned successfully!"
|
||||
|
||||
echo
|
||||
log_result "All done! eVibes is up and running!"
|
||||
|
|
|
|||
|
|
@ -7,18 +7,30 @@ else script_path="$0"
|
|||
fi
|
||||
script_dir="$(cd "$(dirname "$script_path")" && pwd -P)"
|
||||
|
||||
# Load shared utilities
|
||||
# shellcheck source=../lib/utils.sh
|
||||
source "$script_dir/../lib/utils.sh"
|
||||
|
||||
if [ ! -d "./evibes" ]; then
|
||||
echo "❌ Please run this script from the project's root (where the 'evibes' directory lives)." >&2
|
||||
log_error "❌ Please run this script from the project's root (where the 'evibes' directory lives)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
art_path="$script_dir/../ASCII_ART_EVIBES"
|
||||
if [ ! -f "$art_path" ]; then
|
||||
echo "❌ Could not find ASCII art at $art_path" >&2
|
||||
log_error "❌ Could not find ASCII art at $art_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat "$art_path"
|
||||
echo
|
||||
echo " by WISELESS TEAM"
|
||||
echo
|
||||
if is_interactive; then
|
||||
# In interactive mode, show colorful banner
|
||||
purple='\033[38;2;121;101;209m'
|
||||
reset='\033[0m'
|
||||
echo -e "${purple}$(cat "$art_path")${reset}"
|
||||
echo
|
||||
echo -e "${COLOR_GRAY} by WISELESS TEAM${COLOR_RESET}"
|
||||
echo
|
||||
else
|
||||
# In non-interactive mode, show simple banner
|
||||
echo "eVibes by WISELESS TEAM"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ set -euo pipefail
|
|||
source ./scripts/Unix/starter.sh
|
||||
|
||||
report=""
|
||||
omit_pattern='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--report|-r)
|
||||
if [ "${2-}" = "" ]; then
|
||||
echo "Error: --report/-r requires an argument: xml or html" >&2
|
||||
log_error "Error: --report/-r requires an argument: xml or html"
|
||||
exit 1
|
||||
fi
|
||||
report="$2"
|
||||
|
|
@ -24,7 +25,7 @@ while [ "$#" -gt 0 ]; do
|
|||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
log_error "Unknown argument: $1"
|
||||
echo "Usage: $0 [--report|-r xml|html]" >&2
|
||||
exit 1
|
||||
;;
|
||||
|
|
@ -33,18 +34,43 @@ done
|
|||
|
||||
case "${report:-}" in
|
||||
"")
|
||||
docker compose exec app uv run coverage erase
|
||||
docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test
|
||||
log_step "Running tests with coverage..."
|
||||
|
||||
log_info " → Erasing previous coverage data..."
|
||||
if ! docker compose exec app uv run coverage erase; then
|
||||
log_error "Failed to erase coverage data"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Running tests..."
|
||||
if ! docker compose exec app uv run coverage run --source='.' --omit="$omit_pattern" manage.py test; then
|
||||
log_error "Tests failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info " → Generating coverage report..."
|
||||
docker compose exec app uv run coverage report -m
|
||||
;;
|
||||
xml)
|
||||
docker compose exec app uv run coverage xml --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
log_step "Generating XML coverage report..."
|
||||
if docker compose exec app uv run coverage xml --omit="$omit_pattern"; then
|
||||
log_success "XML coverage report generated"
|
||||
else
|
||||
log_error "Failed to generate XML coverage report"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
html)
|
||||
docker compose exec app uv run coverage html --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
log_step "Generating HTML coverage report..."
|
||||
if docker compose exec app uv run coverage html --omit="$omit_pattern"; then
|
||||
log_success "HTML coverage report generated"
|
||||
else
|
||||
log_error "Failed to generate HTML coverage report"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Invalid report type: $report (expected xml or html)" >&2
|
||||
log_error "Invalid report type: $report (expected xml or html)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -3,21 +3,31 @@ set -euo pipefail
|
|||
|
||||
source ./scripts/Unix/starter.sh
|
||||
|
||||
echo "Shutting down..."
|
||||
docker compose down
|
||||
echo "Services were shut down successfully!"
|
||||
# Shutdown services
|
||||
log_step "Shutting down..."
|
||||
if ! docker compose down; then
|
||||
log_error "Failed to shut down services"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Services were shut down successfully!"
|
||||
|
||||
echo "Removing volumes..."
|
||||
docker volume rm -f evibes_prometheus-data
|
||||
docker volume rm -f evibes_es-data
|
||||
echo "Volumes were removed successfully!"
|
||||
# Remove volumes
|
||||
log_step "Removing volumes..."
|
||||
docker volume rm -f evibes_prometheus-data || log_warning "Failed to remove prometheus-data volume"
|
||||
docker volume rm -f evibes_es-data || log_warning "Failed to remove es-data volume"
|
||||
log_success "Volumes were removed successfully!"
|
||||
|
||||
echo "Cleaning up unused Docker data..."
|
||||
docker system prune -a -f --volumes
|
||||
echo "Unused Docker data cleaned successfully!"
|
||||
# Cleanup Docker
|
||||
log_step "Cleaning up unused Docker data..."
|
||||
if ! docker system prune -a -f --volumes; then
|
||||
log_warning "Docker cleanup had issues, but continuing..."
|
||||
fi
|
||||
log_success "Unused Docker data cleaned successfully!"
|
||||
|
||||
echo "Removing related files..."
|
||||
# Remove local files
|
||||
log_step "Removing related files..."
|
||||
rm -rf ./media ./static
|
||||
echo "Related files removed successfully!"
|
||||
log_success "Related files removed successfully!"
|
||||
|
||||
echo "Bye-bye, hope you return later!"
|
||||
echo
|
||||
log_result "Bye-bye, hope you return later!"
|
||||
|
|
|
|||
|
|
@ -2,21 +2,32 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "Starting database backup process..." -ForegroundColor Magenta
|
||||
# Database backup
|
||||
Write-Step "Starting database backup process..."
|
||||
docker compose exec app uv run manage.py dbbackup
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Database backup failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Database backup created under ./dbbackup" -ForegroundColor Green
|
||||
Write-Success "Database backup created under ./dbbackup"
|
||||
|
||||
Write-Host "Starting media backup process..." -ForegroundColor Magenta
|
||||
# Media backup
|
||||
Write-Step "Starting media backup process..."
|
||||
docker compose exec app uv run manage.py mediabackup
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Media backup failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Media backup created under ./dbbackup" -ForegroundColor Green
|
||||
Write-Success "Media backup created under ./dbbackup"
|
||||
|
||||
Write-Result ""
|
||||
Write-Result "Backup completed successfully!"
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
|
|
@ -8,20 +12,27 @@ if ($LASTEXITCODE -ne 0) {
|
|||
|
||||
if (-not (Test-Path '.env'))
|
||||
{
|
||||
Write-Warning ".env file not found. Exiting without running Docker steps."
|
||||
Write-Warning-Custom ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Checking placeholders in PO files..." -ForegroundColor Magenta
|
||||
# Check placeholders
|
||||
Write-Step "Checking placeholders in PO files..."
|
||||
docker compose exec app uv run manage.py check_translated -l ALL -a ALL
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "PO files have placeholder issues"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "PO files have no placeholder issues!" -ForegroundColor Green
|
||||
Write-Success "PO files have no placeholder issues!"
|
||||
|
||||
Write-Host "Compiling PO files into MO files..." -ForegroundColor Magenta
|
||||
# Compile messages
|
||||
Write-Step "Compiling PO files into MO files..."
|
||||
docker compose exec app uv run manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to compile messages"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Compiled successfully!" -ForegroundColor Green
|
||||
Write-Success "Compiled successfully!"
|
||||
|
||||
Write-Result ""
|
||||
Write-Result "Translation compilation complete!"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
|
|
@ -8,39 +12,33 @@ if ($LASTEXITCODE -ne 0) {
|
|||
|
||||
if (-not (Test-Path '.env'))
|
||||
{
|
||||
Write-Warning ".env file not found. Exiting without running Docker steps."
|
||||
Write-Warning-Custom ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$cpuCount = [Environment]::ProcessorCount
|
||||
if ($cpuCount -lt 4)
|
||||
# Check system requirements
|
||||
if (-not (Test-SystemRequirements -MinCpu 4 -MinRamGB 6 -MinDiskGB 20))
|
||||
{
|
||||
exit 1
|
||||
}
|
||||
|
||||
$totalMemBytes = (Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory
|
||||
$totalMemGB = [Math]::Round($totalMemBytes / 1GB, 2)
|
||||
if ($totalMemGB -lt 6)
|
||||
{
|
||||
exit 1
|
||||
}
|
||||
|
||||
$currentDrive = Split-Path -Qualifier $PWD
|
||||
$driveLetter = $currentDrive.Substring(0, 1)
|
||||
$freeGB = [Math]::Round((Get-PSDrive -Name $driveLetter).Free / 1GB, 2)
|
||||
if ($freeGB -lt 20)
|
||||
{
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "System requirements met: CPU cores=$cpuCount, RAM=${totalMemGB}GB, FreeDisk=${freeGB}GB" -ForegroundColor Green
|
||||
|
||||
Write-Host "Pulling images" -ForegroundColor Magenta
|
||||
# Pull Docker images
|
||||
Write-Step "Pulling images..."
|
||||
docker compose pull
|
||||
Write-Host "Images pulled successfully" -ForegroundColor Green
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to pull Docker images"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Success "Images pulled successfully"
|
||||
|
||||
Write-Host "Building images" -ForegroundColor Magenta
|
||||
# Build Docker images
|
||||
Write-Step "Building images..."
|
||||
docker compose build
|
||||
Write-Host "Images built successfully" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "You can now use run.ps1 script." -ForegroundColor Cyan
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to build Docker images"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Success "Images built successfully"
|
||||
|
||||
Write-Result ""
|
||||
Write-Result "You can now use run.ps1 script or run: lessy.py run"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
|
|
@ -8,37 +12,45 @@ if ($LASTEXITCODE -ne 0) {
|
|||
|
||||
if (-not (Test-Path '.env'))
|
||||
{
|
||||
Write-Warning ".env file not found. Exiting without running Docker steps."
|
||||
Write-Warning-Custom ".env file not found. Exiting without running Docker steps."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Remove old fuzzy entries..." -ForegroundColor Magenta
|
||||
# Remove old fuzzy entries
|
||||
Write-Step "Remove old fuzzy entries..."
|
||||
docker compose exec app uv run manage.py fix_fuzzy
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to remove old fuzzy entries"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Old fuzzy entries removed successfully!" -ForegroundColor Green
|
||||
Write-Success "Old fuzzy entries removed successfully!"
|
||||
|
||||
Write-Host "Updating PO files..." -ForegroundColor Magenta
|
||||
# Update PO files
|
||||
Write-Step "Updating PO files..."
|
||||
docker compose exec app uv run manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to update PO files"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "PO files updated successfully!" -ForegroundColor Green
|
||||
Write-Success "PO files updated successfully!"
|
||||
|
||||
Write-Host "Fixing new fuzzy entries..." -ForegroundColor Magenta
|
||||
# Fix new fuzzy entries
|
||||
Write-Step "Fixing new fuzzy entries..."
|
||||
docker compose exec app uv run manage.py fix_fuzzy
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to fix new fuzzy entries"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "New fuzzy entries fixed successfully!" -ForegroundColor Green
|
||||
Write-Success "New fuzzy entries fixed successfully!"
|
||||
|
||||
Write-Host "Translating with DeepL..." -ForegroundColor Magenta
|
||||
# Translate with DeepL
|
||||
Write-Step "Translating with DeepL..."
|
||||
docker compose exec app uv run manage.py deepl_translate -l ALL -a ALL
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Translation failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Translated successfully!" -ForegroundColor Green
|
||||
Write-Success "Translated successfully!"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "You can now use compile-messages.ps1 script." -ForegroundColor Cyan
|
||||
Write-Result ""
|
||||
Write-Result "You can now use compile-messages.ps1 script or run: lessy.py compile-messages"
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
|
||||
Write-Host "Shutting down..." -ForegroundColor Magenta
|
||||
docker compose down
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Services were shut down successfully!" -ForegroundColor Green
|
||||
|
||||
Write-Host "Spinning services up..." -ForegroundColor Magenta
|
||||
docker compose up -d --build --wait
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Services are up and healthy!" -ForegroundColor Green
|
||||
|
||||
Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta
|
||||
docker compose exec app uv run manage.py migrate --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
docker compose exec app uv run manage.py initialize
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
docker compose exec app uv run manage.py set_default_caches
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
docker compose exec app uv run manage.py search_index --rebuild -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
docker compose exec app uv run manage.py collectstatic --clear --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Pre-run tasks completed successfully!" -ForegroundColor Green
|
||||
|
||||
Write-Host "Cleaning up unused Docker data..." -ForegroundColor Magenta
|
||||
docker system prune -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
|
||||
|
||||
Write-Host "All done! eVibes is up and running!" -ForegroundColor Cyan
|
||||
80
scripts/Windows/restart.ps1
Normal file
80
scripts/Windows/restart.ps1
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Shutdown services
|
||||
Write-Step "Shutting down..."
|
||||
docker compose down
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to shut down services"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Success "Services were shut down successfully!"
|
||||
|
||||
# Rebuild and start services
|
||||
Write-Step "Spinning services up with rebuild..."
|
||||
docker compose up -d --build --wait
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to start services"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Success "Services are up and healthy!"
|
||||
|
||||
# Run pre-run tasks
|
||||
Write-Step "Completing pre-run tasks..."
|
||||
|
||||
Write-Info " → Running migrations..."
|
||||
docker compose exec app uv run manage.py migrate --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Migrations failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Initializing..."
|
||||
docker compose exec app uv run manage.py initialize
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Initialization failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Setting default caches..."
|
||||
docker compose exec app uv run manage.py set_default_caches
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Cache setup failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Rebuilding search index..."
|
||||
docker compose exec app uv run manage.py search_index --rebuild -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Search index rebuild failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Collecting static files..."
|
||||
docker compose exec app uv run manage.py collectstatic --clear --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Static files collection failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Success "Pre-run tasks completed successfully!"
|
||||
|
||||
# Cleanup
|
||||
Write-Step "Cleaning up unused Docker data..."
|
||||
docker system prune -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning-Custom "Docker cleanup had issues, but continuing..."
|
||||
}
|
||||
Write-Success "Unused Docker data cleaned successfully!"
|
||||
|
||||
Write-Result ""
|
||||
Write-Result "All done! eVibes is up and running!"
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "Verifying all images are present…" -ForegroundColor Green
|
||||
# Verify Docker images
|
||||
Write-Step "Verifying all images are present…"
|
||||
|
||||
$config = docker compose config --format json | ConvertFrom-Json
|
||||
|
||||
|
|
@ -21,50 +26,71 @@ foreach ($prop in $config.services.PSObject.Properties)
|
|||
|
||||
$image = $svc.PSObject.Properties['image'].Value
|
||||
|
||||
if (-not (docker image inspect $image))
|
||||
if (-not (docker image inspect $image 2>$null))
|
||||
{
|
||||
Write-Error "Required images not found. Please run install.ps1 first."
|
||||
Write-Error-Custom "Required images not found. Please run install.ps1 first."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host " • Found image: $image"
|
||||
Write-Info " • Found image: $image"
|
||||
}
|
||||
|
||||
Write-Host "Spinning services up..." -ForegroundColor Magenta
|
||||
# Start services
|
||||
Write-Step "Spinning services up..."
|
||||
docker compose up --no-build --detach --wait
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to start services"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Services are up and healthy!" -ForegroundColor Green
|
||||
Write-Success "Services are up and healthy!"
|
||||
|
||||
Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta
|
||||
# Run pre-run tasks
|
||||
Write-Step "Completing pre-run tasks..."
|
||||
|
||||
Write-Info " → Running migrations..."
|
||||
docker compose exec app uv run manage.py migrate --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Migrations failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Initializing..."
|
||||
docker compose exec app uv run manage.py initialize
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Initialization failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Setting default caches..."
|
||||
docker compose exec app uv run manage.py set_default_caches
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Cache setup failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Rebuilding search index..."
|
||||
docker compose exec app uv run manage.py search_index --rebuild -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Search index rebuild failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Collecting static files..."
|
||||
docker compose exec app uv run manage.py collectstatic --clear --no-input
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Static files collection failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Pre-run tasks completed successfully!" -ForegroundColor Green
|
||||
|
||||
Write-Host "Cleaning unused Docker data..." -ForegroundColor Magenta
|
||||
Write-Success "Pre-run tasks completed successfully!"
|
||||
|
||||
# Cleanup
|
||||
Write-Step "Cleaning unused Docker data..."
|
||||
docker system prune -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
Write-Warning-Custom "Docker cleanup had issues, but continuing..."
|
||||
}
|
||||
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
|
||||
Write-Success "Unused Docker data cleaned successfully!"
|
||||
|
||||
Write-Host "All done! eVibes is up and running!" -ForegroundColor Cyan
|
||||
Write-Result ""
|
||||
Write-Result "All done! eVibes is up and running!"
|
||||
|
|
|
|||
|
|
@ -1,22 +1,35 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
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
|
||||
Write-Error-Custom "❌ Please run this script from the project's root (where the 'evibes' directory lives)."
|
||||
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
|
||||
Write-Error-Custom "❌ Could not find ASCII art at $artPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Get-Content -Raw -Path $artPath | ForEach-Object { Write-Host "$purple$_$reset" }
|
||||
Write-Host "`n by WISELESS TEAM`n" -ForegroundColor Gray
|
||||
if (Test-Interactive)
|
||||
{
|
||||
$purple = "`e[38;2;121;101;209m"
|
||||
$reset = "`e[0m"
|
||||
Get-Content -Raw -Path $artPath | ForEach-Object { Write-Host "$purple$_$reset" }
|
||||
Write-Host "`n by WISELESS TEAM`n" -ForegroundColor Gray
|
||||
}
|
||||
else
|
||||
{
|
||||
# In non-interactive mode, just show simple banner
|
||||
Write-Output "eVibes by WISELESS TEAM"
|
||||
}
|
||||
|
||||
exit 0
|
||||
|
|
@ -6,33 +6,62 @@ param(
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
& .\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
$omitPattern = 'storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
|
||||
if (-not $PSBoundParameters.ContainsKey('Report') -or [string]::IsNullOrWhiteSpace($Report)) {
|
||||
Write-Step "Running tests with coverage..."
|
||||
|
||||
Write-Info " → Erasing previous coverage data..."
|
||||
docker compose exec app uv run coverage erase
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to erase coverage data"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
Write-Info " → Running tests..."
|
||||
docker compose exec app uv run coverage run --source='.' --omit=$omitPattern manage.py test
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Tests failed"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Info " → Generating coverage report..."
|
||||
docker compose exec app uv run coverage report -m
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
switch ($Report.ToLowerInvariant()) {
|
||||
'xml' {
|
||||
docker compose exec app uv run coverage xml --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
Write-Step "Generating XML coverage report..."
|
||||
docker compose exec app uv run coverage xml --omit=$omitPattern
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Success "XML coverage report generated"
|
||||
} else {
|
||||
Write-Error-Custom "Failed to generate XML coverage report"
|
||||
}
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
'html' {
|
||||
docker compose exec app uv run coverage html --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*'
|
||||
Write-Step "Generating HTML coverage report..."
|
||||
docker compose exec app uv run coverage html --omit=$omitPattern
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Success "HTML coverage report generated"
|
||||
} else {
|
||||
Write-Error-Custom "Failed to generate HTML coverage report"
|
||||
}
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
default {
|
||||
Write-Error "Invalid -Report/-r value '$Report'. Expected 'xml' or 'html'."
|
||||
Write-Error-Custom "Invalid -Report/-r value '$Report'. Expected 'xml' or 'html'."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,49 @@
|
|||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Load shared utilities
|
||||
$utilsPath = Join-Path $PSScriptRoot '..\lib\utils.ps1'
|
||||
. $utilsPath
|
||||
|
||||
.\scripts\Windows\starter.ps1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "Shutting down..." -ForegroundColor Magenta
|
||||
# Shutdown services
|
||||
Write-Step "Shutting down..."
|
||||
docker compose down
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error-Custom "Failed to shut down services"
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
Write-Host "Services were shut down successfully!" -ForegroundColor Green
|
||||
Write-Success "Services were shut down successfully!"
|
||||
|
||||
Write-Host "Removing volumes..." -ForegroundColor Magenta
|
||||
# Remove volumes
|
||||
Write-Step "Removing volumes..."
|
||||
docker volume remove -f evibes_prometheus-data
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
Write-Warning-Custom "Failed to remove prometheus-data volume"
|
||||
}
|
||||
docker volume remove -f evibes_es-data
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
Write-Warning-Custom "Failed to remove es-data volume"
|
||||
}
|
||||
Write-Host "Volumes were removed successfully!" -ForegroundColor Green
|
||||
Write-Success "Volumes were removed successfully!"
|
||||
|
||||
Write-Host "Cleaning up unused Docker data..." -ForegroundColor Magenta
|
||||
# Cleanup Docker
|
||||
Write-Step "Cleaning up unused Docker data..."
|
||||
docker system prune -a -f --volumes
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
Write-Warning-Custom "Docker cleanup had issues, but continuing..."
|
||||
}
|
||||
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
|
||||
Write-Success "Unused Docker data cleaned successfully!"
|
||||
|
||||
Write-Host "Removing related files..." -ForegroundColor Magenta
|
||||
# Remove local files
|
||||
Write-Step "Removing related files..."
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./media
|
||||
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./static
|
||||
Write-Host "Related files removed successfully!" -ForegroundColor Green
|
||||
Write-Success "Related files removed successfully!"
|
||||
|
||||
Write-Host "Bye-bye, hope you return later!" -ForegroundColor Red
|
||||
Write-Result ""
|
||||
Write-Result "Bye-bye, hope you return later!"
|
||||
298
scripts/lib/utils.ps1
Normal file
298
scripts/lib/utils.ps1
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
# Shared utilities for Windows scripts
|
||||
# Provides: colors, progress indicators, interactive detection
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Detect if running in interactive shell
|
||||
function Test-Interactive
|
||||
{
|
||||
# Check if both input and output are from terminal
|
||||
# In non-interactive environments (CI/CD), this will be false
|
||||
$isInteractive = [Environment]::UserInteractive -and
|
||||
(-not [Console]::IsInputRedirected) -and
|
||||
(-not [Console]::IsOutputRedirected)
|
||||
return $isInteractive
|
||||
}
|
||||
|
||||
# Global spinner state
|
||||
$script:SpinnerJob = $null
|
||||
$script:SpinnerFrames = @('⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏')
|
||||
|
||||
# Logging functions
|
||||
function Write-Info
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Blue
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $Message
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Success
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Green
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $Message
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Warning-Custom
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Yellow
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "WARNING: $Message"
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Error-Custom
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Red
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "ERROR: $Message" *>&1
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Step
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Magenta
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $Message
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Result
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Write-Host $Message -ForegroundColor Cyan
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $Message
|
||||
}
|
||||
}
|
||||
|
||||
# Spinner functions (only for interactive shells)
|
||||
function Start-Spinner
|
||||
{
|
||||
param([string]$Message = "Processing...")
|
||||
|
||||
if (-not (Test-Interactive))
|
||||
{
|
||||
Write-Output $Message
|
||||
return
|
||||
}
|
||||
|
||||
$script:SpinnerJob = Start-Job -ScriptBlock {
|
||||
param($Frames, $Msg)
|
||||
|
||||
$i = 0
|
||||
while ($true)
|
||||
{
|
||||
$frame = $Frames[$i % $Frames.Length]
|
||||
[Console]::SetCursorPosition(0, [Console]::CursorTop)
|
||||
Write-Host -NoNewline "$frame $Msg"
|
||||
Start-Sleep -Milliseconds 100
|
||||
$i++
|
||||
}
|
||||
} -ArgumentList $script:SpinnerFrames, $Message
|
||||
}
|
||||
|
||||
function Stop-Spinner
|
||||
{
|
||||
if ($script:SpinnerJob -ne $null)
|
||||
{
|
||||
Stop-Job -Job $script:SpinnerJob -ErrorAction SilentlyContinue
|
||||
Remove-Job -Job $script:SpinnerJob -Force -ErrorAction SilentlyContinue
|
||||
$script:SpinnerJob = $null
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
# Clear the spinner line
|
||||
[Console]::SetCursorPosition(0, [Console]::CursorTop)
|
||||
Write-Host (' ' * ([Console]::WindowWidth - 1)) -NoNewline
|
||||
[Console]::SetCursorPosition(0, [Console]::CursorTop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Update-Spinner
|
||||
{
|
||||
param([string]$Message)
|
||||
|
||||
if (-not (Test-Interactive))
|
||||
{
|
||||
Write-Output $Message
|
||||
return
|
||||
}
|
||||
|
||||
if ($script:SpinnerJob -ne $null)
|
||||
{
|
||||
Stop-Spinner
|
||||
Start-Spinner -Message $Message
|
||||
}
|
||||
}
|
||||
|
||||
# Execute command with progress indicator
|
||||
function Invoke-WithProgress
|
||||
{
|
||||
param(
|
||||
[string]$Message,
|
||||
[scriptblock]$ScriptBlock
|
||||
)
|
||||
|
||||
if (Test-Interactive)
|
||||
{
|
||||
Start-Spinner -Message $Message
|
||||
|
||||
try
|
||||
{
|
||||
$output = & $ScriptBlock 2>&1
|
||||
$exitCode = $LASTEXITCODE
|
||||
|
||||
Stop-Spinner
|
||||
|
||||
if ($exitCode -eq 0 -or $null -eq $exitCode)
|
||||
{
|
||||
Write-Success "✓ $Message - Done!"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error-Custom "✗ $Message - Failed!"
|
||||
if ($output)
|
||||
{
|
||||
Write-Output $output
|
||||
}
|
||||
}
|
||||
|
||||
return $exitCode
|
||||
}
|
||||
catch
|
||||
{
|
||||
Stop-Spinner
|
||||
Write-Error-Custom "✗ $Message - Failed!"
|
||||
throw
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Non-interactive: just show message and run
|
||||
Write-Output "→ $Message"
|
||||
|
||||
try
|
||||
{
|
||||
& $ScriptBlock
|
||||
$exitCode = $LASTEXITCODE
|
||||
|
||||
if ($exitCode -eq 0 -or $null -eq $exitCode)
|
||||
{
|
||||
Write-Output "✓ $Message - Done!"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "✗ $Message - Failed!"
|
||||
}
|
||||
|
||||
return $exitCode
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Output "✗ $Message - Failed!"
|
||||
throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check system requirements
|
||||
function Test-SystemRequirements
|
||||
{
|
||||
param(
|
||||
[int]$MinCpu = 4,
|
||||
[int]$MinRamGB = 6,
|
||||
[int]$MinDiskGB = 20
|
||||
)
|
||||
|
||||
Write-Step "Checking system requirements..."
|
||||
|
||||
# Check CPU cores
|
||||
$cpuCount = [Environment]::ProcessorCount
|
||||
if ($cpuCount -lt $MinCpu)
|
||||
{
|
||||
Write-Error-Custom "Insufficient CPU cores: $cpuCount (minimum: $MinCpu)"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Check RAM
|
||||
$totalMemBytes = (Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory
|
||||
$totalMemGB = [Math]::Round($totalMemBytes / 1GB, 2)
|
||||
if ($totalMemGB -lt $MinRamGB)
|
||||
{
|
||||
Write-Error-Custom "Insufficient RAM: ${totalMemGB}GB (minimum: ${MinRamGB}GB)"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Check disk space
|
||||
$currentDrive = Split-Path -Qualifier $PWD
|
||||
$driveLetter = $currentDrive.Substring(0, 1)
|
||||
$freeGB = [Math]::Round((Get-PSDrive -Name $driveLetter).Free / 1GB, 2)
|
||||
if ($freeGB -lt $MinDiskGB)
|
||||
{
|
||||
Write-Error-Custom "Insufficient disk space: ${freeGB}GB (minimum: ${MinDiskGB}GB)"
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Success "System requirements met: CPU cores=$cpuCount, RAM=${totalMemGB}GB, FreeDisk=${freeGB}GB"
|
||||
return $true
|
||||
}
|
||||
|
||||
# Confirm action
|
||||
function Confirm-Action
|
||||
{
|
||||
param([string]$Prompt = "Are you sure?")
|
||||
|
||||
if (-not (Test-Interactive))
|
||||
{
|
||||
# In non-interactive mode, assume yes
|
||||
return $true
|
||||
}
|
||||
|
||||
$response = Read-Host "$Prompt [y/N]"
|
||||
return $response -match '^[yY]([eE][sS])?$'
|
||||
}
|
||||
|
||||
# Ensure spinner cleanup on exit
|
||||
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
|
||||
Stop-Spinner
|
||||
}
|
||||
223
scripts/lib/utils.sh
Normal file
223
scripts/lib/utils.sh
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
#!/usr/bin/env bash
|
||||
# Shared utilities for Unix scripts
|
||||
# Provides: colors, progress indicators, interactive detection
|
||||
|
||||
# Detect if running in interactive shell
|
||||
is_interactive() {
|
||||
[[ -t 0 && -t 1 ]]
|
||||
}
|
||||
|
||||
# Color definitions (only used in interactive mode)
|
||||
if is_interactive && [[ "${NO_COLOR:-}" != "1" ]]; then
|
||||
COLOR_RESET='\033[0m'
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_YELLOW='\033[0;33m'
|
||||
COLOR_BLUE='\033[0;34m'
|
||||
COLOR_MAGENTA='\033[0;35m'
|
||||
COLOR_CYAN='\033[0;36m'
|
||||
COLOR_GRAY='\033[0;90m'
|
||||
COLOR_BOLD='\033[1m'
|
||||
else
|
||||
COLOR_RESET=''
|
||||
COLOR_RED=''
|
||||
COLOR_GREEN=''
|
||||
COLOR_YELLOW=''
|
||||
COLOR_BLUE=''
|
||||
COLOR_MAGENTA=''
|
||||
COLOR_CYAN=''
|
||||
COLOR_GRAY=''
|
||||
COLOR_BOLD=''
|
||||
fi
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${COLOR_BLUE}${1}${COLOR_RESET}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${COLOR_GREEN}${1}${COLOR_RESET}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${COLOR_YELLOW}${1}${COLOR_RESET}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${COLOR_RED}${1}${COLOR_RESET}" >&2
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${COLOR_MAGENTA}${1}${COLOR_RESET}"
|
||||
}
|
||||
|
||||
log_result() {
|
||||
echo -e "${COLOR_CYAN}${1}${COLOR_RESET}"
|
||||
}
|
||||
|
||||
# Spinner animation (only for interactive shells)
|
||||
SPINNER_FRAMES=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
||||
SPINNER_PID=""
|
||||
|
||||
start_spinner() {
|
||||
local message="${1:-Processing...}"
|
||||
|
||||
if ! is_interactive; then
|
||||
echo "$message"
|
||||
return
|
||||
fi
|
||||
|
||||
{
|
||||
local i=0
|
||||
while true; do
|
||||
printf "\r${COLOR_CYAN}${SPINNER_FRAMES[$i]}${COLOR_RESET} %s" "$message"
|
||||
i=$(( (i + 1) % ${#SPINNER_FRAMES[@]} ))
|
||||
sleep 0.1
|
||||
done
|
||||
} &
|
||||
SPINNER_PID=$!
|
||||
|
||||
# Ensure spinner is cleaned up on script exit
|
||||
trap "stop_spinner" EXIT INT TERM
|
||||
}
|
||||
|
||||
stop_spinner() {
|
||||
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
|
||||
kill "$SPINNER_PID" 2>/dev/null
|
||||
wait "$SPINNER_PID" 2>/dev/null
|
||||
SPINNER_PID=""
|
||||
fi
|
||||
|
||||
if is_interactive; then
|
||||
printf "\r\033[K" # Clear the spinner line
|
||||
fi
|
||||
}
|
||||
|
||||
update_spinner_message() {
|
||||
local message="${1:-Processing...}"
|
||||
|
||||
if ! is_interactive; then
|
||||
echo "$message"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
|
||||
stop_spinner
|
||||
start_spinner "$message"
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute command with progress indicator
|
||||
run_with_progress() {
|
||||
local message="$1"
|
||||
shift
|
||||
local cmd=("$@")
|
||||
|
||||
if is_interactive; then
|
||||
start_spinner "$message"
|
||||
local output
|
||||
local exit_code
|
||||
|
||||
# Capture output and exit code
|
||||
output=$("${cmd[@]}" 2>&1)
|
||||
exit_code=$?
|
||||
|
||||
stop_spinner
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
log_success "✓ $message - Done!"
|
||||
else
|
||||
log_error "✗ $message - Failed!"
|
||||
echo "$output"
|
||||
fi
|
||||
|
||||
return $exit_code
|
||||
else
|
||||
# Non-interactive: just show message and run
|
||||
echo "→ $message"
|
||||
"${cmd[@]}"
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
echo "✓ $message - Done!"
|
||||
else
|
||||
echo "✗ $message - Failed!"
|
||||
fi
|
||||
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Validate system requirements
|
||||
check_system_requirements() {
|
||||
local min_cpu="${1:-4}"
|
||||
local min_ram_gb="${2:-6}"
|
||||
local min_disk_gb="${3:-20}"
|
||||
|
||||
log_step "Checking system requirements..."
|
||||
|
||||
# Check CPU cores
|
||||
local cpu_count
|
||||
cpu_count=$(getconf _NPROCESSORS_ONLN)
|
||||
|
||||
if [[ "$cpu_count" -lt "$min_cpu" ]]; then
|
||||
log_error "Insufficient CPU cores: $cpu_count (minimum: $min_cpu)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check RAM
|
||||
local total_mem_gb
|
||||
if [[ -f /proc/meminfo ]]; then
|
||||
local mem_kb
|
||||
mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $mem_kb/1024/1024}")
|
||||
else
|
||||
local total_mem_bytes
|
||||
total_mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo "0")
|
||||
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $total_mem_bytes/1024/1024/1024}")
|
||||
fi
|
||||
|
||||
if ! awk "BEGIN {exit !($total_mem_gb >= $min_ram_gb)}"; then
|
||||
log_error "Insufficient RAM: ${total_mem_gb}GB (minimum: ${min_ram_gb}GB)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check disk space
|
||||
local avail_kb free_gb
|
||||
avail_kb=$(df -k . | tail -1 | awk '{print $4}')
|
||||
free_gb=$(awk "BEGIN {printf \"%.2f\", $avail_kb/1024/1024}")
|
||||
|
||||
if ! awk "BEGIN {exit !($free_gb >= $min_disk_gb)}"; then
|
||||
log_error "Insufficient disk space: ${free_gb}GB (minimum: ${min_disk_gb}GB)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "System requirements met: CPU cores=$cpu_count, RAM=${total_mem_gb}GB, FreeDisk=${free_gb}GB"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Confirm action (returns 0 for yes, 1 for no)
|
||||
confirm() {
|
||||
local prompt="${1:-Are you sure?}"
|
||||
local response
|
||||
|
||||
if ! is_interactive; then
|
||||
# In non-interactive mode, assume yes
|
||||
return 0
|
||||
fi
|
||||
|
||||
read -r -p "$prompt [y/N]: " response
|
||||
case "$response" in
|
||||
[yY][eE][sS]|[yY])
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
Loading…
Reference in a new issue