Files
Medios-Macina/scripts/bootstrap.sh

221 lines
7.1 KiB
Bash
Raw Normal View History

2025-12-23 16:36:39 -08:00
#!/usr/bin/env bash
# Bootstrap script for POSIX (Linux/macOS) to create a Python venv and install the project.
# Usage: scripts/bootstrap.sh [--editable] [--venv <path>] [--python <python>] [--desktop] [--no-install]
set -euo pipefail
VENV_PATH=".venv"
EDITABLE=false
DESKTOP=false
PYTHON_CMD=""
NOINSTALL=false
FORCE=false
usage() {
cat <<EOF
Usage: $0 [options]
Options:
-e, --editable Install project in editable mode (pip -e .)
-p, --venv <path> Venv path (default: .venv)
--python <python> Python executable to use (e.g. python3)
-d, --desktop Create a desktop launcher (~/.local/share/applications and ~/Desktop)
-n, --no-install Skip pip install
-f, --force Overwrite existing venv without prompting
-h, --help Show this help
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
-e|--editable) EDITABLE=true; shift;;
-p|--venv) VENV_PATH="$2"; shift 2;;
--python) PYTHON_CMD="$2"; shift 2;;
-d|--desktop) DESKTOP=true; shift;;
-n|--no-install) NOINSTALL=true; shift;;
-f|--force) FORCE=true; shift;;
-h|--help) usage; exit 0;;
*) echo "Unknown option: $1"; usage; exit 1;;
esac
done
if [[ -n "$PYTHON_CMD" ]]; then
PY="$PYTHON_CMD"
elif command -v python3 >/dev/null 2>&1; then
PY=python3
elif command -v python >/dev/null 2>&1; then
PY=python
else
echo "ERROR: No python executable found; install Python or pass --python <path>" >&2
exit 2
fi
echo "Using Python: $PY"
if [[ -d "$VENV_PATH" ]]; then
if [[ "$FORCE" == "true" ]]; then
echo "Removing existing venv $VENV_PATH"
rm -rf "$VENV_PATH"
else
read -p "$VENV_PATH already exists. Overwrite? [y/N] " REPLY
if [[ "$REPLY" != "y" && "$REPLY" != "Y" ]]; then
echo "Aborted."; exit 0
fi
rm -rf "$VENV_PATH"
fi
fi
echo "Creating venv at $VENV_PATH"
$PY -m venv "$VENV_PATH"
VENV_PY="$VENV_PATH/bin/python"
if [[ ! -x "$VENV_PY" ]]; then
echo "ERROR: venv python not found at $VENV_PY" >&2
exit 3
fi
if [[ "$NOINSTALL" != "true" ]]; then
echo "Upgrading pip, setuptools, wheel..."
"$VENV_PY" -m pip install -U pip setuptools wheel
if [[ "$EDITABLE" == "true" ]]; then
echo "Installing project in editable mode..."
"$VENV_PY" -m pip install -e .
else
echo "Installing project..."
"$VENV_PY" -m pip install .
fi
# Verify the installed CLI module can be imported. This helps catch packaging
# or installation problems early (e.g., missing modules or mispackaged project).
echo "Verifying installed CLI import..."
if "$VENV_PY" -c 'import importlib; importlib.import_module("medeia_macina.cli_entry")' >/dev/null 2>&1; then
echo "OK: 'medeia_macina.cli_entry' is importable in the venv."
else
echo "WARNING: Could not import 'medeia_macina.cli_entry' from the venv." >&2
# Check if legacy top-level module is present; if so, inform the user to prefer the packaged entrypoint
if "$VENV_PY" -c 'import importlib; importlib.import_module("medeia_entry")' >/dev/null 2>&1; then
echo "Note: 'medeia_entry' top-level module is present. It's recommended to install the project so 'medeia_macina.cli_entry' is available." >&2
else
echo "Action: Try running: $VENV_PY -m pip install -e . or inspect the venv site-packages to verify the installation." >&2
fi
fi
else
echo "Skipping install (--no-install)"
fi
# Install Deno (official installer) - installed automatically
if command -v deno >/dev/null 2>&1; then
echo "Deno already installed: $(deno --version | head -n 1)"
else
echo "Installing Deno via official installer (https://deno.land)..."
if command -v curl >/dev/null 2>&1; then
curl -fsSL https://deno.land/install.sh | sh
elif command -v wget >/dev/null 2>&1; then
wget -qO- https://deno.land/install.sh | sh
else
echo "ERROR: curl or wget is required to install Deno automatically; please install Deno manually." >&2
fi
export DENO_INSTALL="${DENO_INSTALL:-$HOME/.deno}"
export PATH="$DENO_INSTALL/bin:$PATH"
if command -v deno >/dev/null 2>&1; then
echo "Deno installed: $(deno --version | head -n 1)"
else
echo "Warning: Deno installer completed but 'deno' not found on PATH; add $HOME/.deno/bin to your PATH or restart your shell." >&2
fi
fi
if [[ "$DESKTOP" == "true" ]]; then
echo "Creating desktop launcher..."
EXEC_PATH="$VENV_PATH/bin/mm"
if [[ ! -x "$EXEC_PATH" ]]; then
# fallback to python -m
EXEC_PATH="$VENV_PY -m medeia_macina.cli_entry"
fi
APPDIR="$HOME/.local/share/applications"
mkdir -p "$APPDIR"
DESKTOP_FILE="$APPDIR/medeia-macina.desktop"
cat > "$DESKTOP_FILE" <<EOF
[Desktop Entry]
Name=Medeia-Macina
Comment=Launch Medeia-Macina
Exec=$EXEC_PATH
Terminal=true
Type=Application
Categories=Utility;
EOF
chmod +x "$DESKTOP_FILE" || true
if [[ -d "$HOME/Desktop" ]]; then
cp "$DESKTOP_FILE" "$HOME/Desktop/"
chmod +x "$HOME/Desktop/$(basename "$DESKTOP_FILE")" || true
fi
echo "Desktop launcher created: $DESKTOP_FILE"
fi
# Install a global 'mm' launcher so it can be invoked from any shell.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$SCRIPT_DIR/.." && pwd)"
USER_BIN="${XDG_BIN_HOME:-$HOME/.local/bin}"
mkdir -p "$USER_BIN"
if [[ -f "$USER_BIN/mm" ]]; then
echo "Backing up existing $USER_BIN/mm to $USER_BIN/mm.bak.$(date +%s)"
mv "$USER_BIN/mm" "$USER_BIN/mm.bak.$(date +%s)"
fi
cat > "$USER_BIN/mm" <<EOF
#!/usr/bin/env bash
REPO="$REPO"
VENV="$REPO/.venv"
if [ -x "$VENV/bin/mm" ]; then
exec "$VENV/bin/mm" "$@"
elif [ -x "$VENV/bin/python" ]; then
exec "$VENV/bin/python" -m medeia_macina.cli_entry "$@"
else
exec python -m medeia_macina.cli_entry "$@"
fi
EOF
chmod +x "$USER_BIN/mm"
# Quick verification of the global launcher; helps catch packaging issues early.
if "$USER_BIN/mm" --help >/dev/null 2>&1; then
echo "Global 'mm' launcher verified: $USER_BIN/mm runs correctly."
else
echo "Warning: Global 'mm' launcher failed to run in this shell. Ensure $USER_BIN is on your PATH and the venv is installed; try: $VENV/bin/python -m medeia_macina.cli_entry --help" >&2
fi
# Ensure the user's bin is on PATH for future sessions by adding to ~/.profile if needed
if ! echo ":$PATH:" | grep -q ":$USER_BIN:"; then
PROFILE="$HOME/.profile"
if [ ! -f "$PROFILE" ]; then
if [ -f "$HOME/.bash_profile" ]; then
PROFILE="$HOME/.bash_profile"
elif [ -f "$HOME/.bashrc" ]; then
PROFILE="$HOME/.bashrc"
elif [ -f "$HOME/.zshrc" ]; then
PROFILE="$HOME/.zshrc"
else
PROFILE="$HOME/.profile"
fi
fi
if ! grep -q "ensure user local bin is on PATH" "$PROFILE" 2>/dev/null; then
cat >> "$PROFILE" <<PROFILE_SNIPPET
# Added by Medeia-Macina setup: ensure user local bin is on PATH
if [ -d "$HOME/.local/bin" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
PATH="$HOME/.local/bin:$PATH"
fi
PROFILE_SNIPPET
echo "Added $USER_BIN export to $PROFILE; restart your shell or source $PROFILE to use 'mm' from anywhere"
fi
fi
cat <<EOF
Bootstrap complete.
To activate the virtualenv:
source $VENV_PATH/bin/activate
To run the app:
$VENV_PATH/bin/mm # if installed as a console script
$VENV_PY -m medeia_macina.cli_entry # alternative
Global launcher installed: $USER_BIN/mm
EOF