#!/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 ] [--python ] [--desktop] [--no-install] set -euo pipefail VENV_PATH=".venv" EDITABLE=false DESKTOP=false PYTHON_CMD="" NOINSTALL=false FORCE=false usage() { cat < Venv path (default: .venv) --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 " >&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" < "$USER_BIN/mm" </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" <