Files
SMF/Start.sh

258 lines
9.3 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# =====================================================================
# SMF2290 Pensum — Start.sh
# Universal launcher: setter opp alt som trengs og starter studie-appen.
# Fungerer på Linux, macOS, og WSL/Git-Bash på Windows.
# =====================================================================
set -e
# --- Resolve script directory (works with symlinks too) -----------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_DIR="$SCRIPT_DIR/app"
VENDOR_DIR="$APP_DIR/vendor"
DEFAULT_PORT=8765
# --- ANSI colours --------------------------------------------------
if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
BOLD="$(tput bold)"; DIM="$(tput dim)"; RESET="$(tput sgr0)"
RED="$(tput setaf 1)"; GREEN="$(tput setaf 2)"; YELLOW="$(tput setaf 3)"
BLUE="$(tput setaf 4)"; ORANGE="$(tput setaf 208 2>/dev/null || tput setaf 3)"
else
BOLD=""; DIM=""; RESET=""; RED=""; GREEN=""; YELLOW=""; BLUE=""; ORANGE=""
fi
say() { printf "%s\n" "$*"; }
info() { printf " ${BLUE}${RESET} %s\n" "$*"; }
ok() { printf " ${GREEN}${RESET} %s\n" "$*"; }
warn() { printf " ${YELLOW}!${RESET} %s\n" "$*"; }
err() { printf " ${RED}${RESET} %s\n" "$*"; }
# --- Banner --------------------------------------------------------
banner() {
printf "\n"
printf " ${ORANGE}${BOLD}SMF · 2290${RESET} ${DIM}Etikk, bærekraft og samfunnsansvar${RESET}\n"
printf " ${BOLD}${BOLD}Pensum${RESET} ${DIM}studie-app · v1.0${RESET}\n"
printf "\n"
}
banner
# --- Sanity check --------------------------------------------------
if [ ! -d "$APP_DIR" ]; then
err "Fant ikke app-mappen: $APP_DIR"
err "Kjør Start.sh fra SMF-prosjektmappen."
exit 1
fi
# --- OS detection --------------------------------------------------
OS_NAME="$(uname -s 2>/dev/null || echo unknown)"
case "$OS_NAME" in
Linux*) PLATFORM="linux" ;;
Darwin*) PLATFORM="macos" ;;
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
*) PLATFORM="unknown" ;;
esac
info "Plattform: ${BOLD}$PLATFORM${RESET}"
# --- Detect / install HTTP server ---------------------------------
SERVER_CMD=""
SERVER_NAME=""
find_server() {
if command -v python3 >/dev/null 2>&1; then
SERVER_CMD="python3 -m http.server PORT --bind 127.0.0.1"
SERVER_NAME="Python 3 ($(python3 --version 2>&1 | awk '{print $2}'))"
return 0
fi
if command -v python >/dev/null 2>&1 && python --version 2>&1 | grep -q "Python 3"; then
SERVER_CMD="python -m http.server PORT --bind 127.0.0.1"
SERVER_NAME="Python 3 ($(python --version 2>&1 | awk '{print $2}'))"
return 0
fi
if command -v php >/dev/null 2>&1; then
SERVER_CMD="php -S 127.0.0.1:PORT -t ."
SERVER_NAME="PHP $(php --version 2>&1 | head -1 | awk '{print $2}')"
return 0
fi
if command -v ruby >/dev/null 2>&1; then
SERVER_CMD="ruby -run -e httpd . --port=PORT --bind-address=127.0.0.1"
SERVER_NAME="Ruby $(ruby --version 2>&1 | awk '{print $2}')"
return 0
fi
if command -v node >/dev/null 2>&1 && command -v npx >/dev/null 2>&1; then
SERVER_CMD="npx --yes http-server -p PORT -a 127.0.0.1 --silent"
SERVER_NAME="Node.js $(node --version 2>&1)"
return 0
fi
return 1
}
try_install_python() {
warn "Ingen webserver funnet. Forsøker å installere Python 3 …"
local installed=0
if command -v apt-get >/dev/null 2>&1; then
info "Bruker apt (Debian/Ubuntu)"
if sudo -n true 2>/dev/null || sudo -v; then
sudo apt-get update -y && sudo apt-get install -y python3 && installed=1
fi
elif command -v dnf >/dev/null 2>&1; then
info "Bruker dnf (Fedora/RHEL)"
sudo dnf install -y python3 && installed=1
elif command -v yum >/dev/null 2>&1; then
info "Bruker yum"
sudo yum install -y python3 && installed=1
elif command -v pacman >/dev/null 2>&1; then
info "Bruker pacman (Arch)"
sudo pacman -Sy --noconfirm python && installed=1
elif command -v zypper >/dev/null 2>&1; then
info "Bruker zypper (openSUSE)"
sudo zypper install -y python3 && installed=1
elif command -v apk >/dev/null 2>&1; then
info "Bruker apk (Alpine)"
sudo apk add python3 && installed=1
elif command -v brew >/dev/null 2>&1; then
info "Bruker Homebrew (macOS)"
brew install python3 && installed=1
elif [ "$PLATFORM" = "macos" ]; then
warn "Homebrew finnes ikke. Installerer Homebrew først …"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" \
&& brew install python3 && installed=1
fi
[ $installed -eq 1 ]
}
info "Søker etter HTTP-server …"
if find_server; then
ok "Server-runtime: ${BOLD}$SERVER_NAME${RESET}"
else
if try_install_python && find_server; then
ok "Server-runtime: ${BOLD}$SERVER_NAME${RESET} (nylig installert)"
else
err "Klarte ikke installere en webserver automatisk."
say ""
say " Installer ${BOLD}én av disse${RESET} manuelt og prøv igjen:"
say " • Python 3: https://www.python.org/downloads/"
say " • Node.js: https://nodejs.org/"
say " • PHP eller Ruby via pakkesystemet ditt"
say ""
exit 1
fi
fi
# --- Verify marked.js (markdown renderer) -------------------------
if [ ! -s "$VENDOR_DIR/marked.min.js" ]; then
warn "marked.min.js mangler — laster ned …"
mkdir -p "$VENDOR_DIR"
if command -v curl >/dev/null 2>&1; then
curl -fsSL https://cdn.jsdelivr.net/npm/marked/marked.min.js -o "$VENDOR_DIR/marked.min.js" \
&& ok "marked.js lastet ned" \
|| { err "Klarte ikke laste ned marked.js. Trenger internett ved første kjøring."; exit 1; }
elif command -v wget >/dev/null 2>&1; then
wget -q https://cdn.jsdelivr.net/npm/marked/marked.min.js -O "$VENDOR_DIR/marked.min.js" \
&& ok "marked.js lastet ned" \
|| { err "Klarte ikke laste ned marked.js."; exit 1; }
else
err "Hverken curl eller wget funnet. Installer en av dem og kjør Start.sh igjen."
exit 1
fi
else
ok "marked.js OK ($(wc -c < "$VENDOR_DIR/marked.min.js") bytes)"
fi
# --- Sanity-sjekk dataene ----------------------------------------
required_files=(
"index.html"
"css/style.css"
"js/app.js"
"data/flashcards.json"
"data/quiz.json"
"data/exam.json"
"notes/uke17-eksamen.md"
)
missing=0
for f in "${required_files[@]}"; do
if [ ! -e "$APP_DIR/$f" ] && [ ! -L "$APP_DIR/$f" ]; then
err "Mangler: app/$f"
missing=$((missing + 1))
fi
done
# app/notes opprettes per plattform (gitignorert). Den skal være en symlink
# til ../notes. Håndter ødelagt symlink ELLER en git-materialisert tekstfil.
if [ -L "$APP_DIR/notes" ] && [ ! -e "$APP_DIR/notes" ]; then
warn "notes-symlink er ødelagt — gjenoppretter …"
rm -f "$APP_DIR/notes"
elif [ -f "$APP_DIR/notes" ]; then
warn "app/notes er en vanlig fil (git-symlink fra Windows) — erstatter med symlink …"
rm -f "$APP_DIR/notes"
fi
if [ ! -d "$APP_DIR/notes" ]; then
if [ -d "$SCRIPT_DIR/notes" ]; then
ln -sfn "../notes" "$APP_DIR/notes"
ok "Symlink notes/ gjenopprettet"
else
err "Fant ikke notes/-mappen i prosjektet"
missing=$((missing + 1))
fi
fi
[ $missing -eq 0 ] && ok "Alle nødvendige filer på plass"
# --- Pick a free port --------------------------------------------
port_free() {
local p="$1"
if command -v lsof >/dev/null 2>&1; then
! lsof -i :"$p" -sTCP:LISTEN >/dev/null 2>&1
elif command -v ss >/dev/null 2>&1; then
! ss -ltn 2>/dev/null | awk '{print $4}' | grep -q ":$p$"
elif command -v netstat >/dev/null 2>&1; then
! netstat -ltn 2>/dev/null | awk '{print $4}' | grep -q ":$p$"
else
# No tool — assume free, the server will error out if not
return 0
fi
}
PORT="$DEFAULT_PORT"
while ! port_free "$PORT"; do
warn "Port $PORT er opptatt — prøver $((PORT + 1))"
PORT=$((PORT + 1))
if [ "$PORT" -gt 8800 ]; then
err "Fant ingen ledig port i 87658800. Lukk noen prosesser og prøv igjen."
exit 1
fi
done
URL="http://localhost:$PORT"
SERVER_CMD="${SERVER_CMD//PORT/$PORT}"
# --- Auto-open browser -------------------------------------------
open_browser() {
( sleep 1.5
if command -v xdg-open >/dev/null 2>&1; then
xdg-open "$URL" >/dev/null 2>&1 &
elif command -v open >/dev/null 2>&1; then
open "$URL" >/dev/null 2>&1 &
elif command -v start >/dev/null 2>&1; then
start "$URL" >/dev/null 2>&1 &
fi
) &
}
# --- Banner og start ----------------------------------------------
printf "\n"
printf " ${BOLD}┌──────────────────────────────────────────────┐${RESET}\n"
printf " ${BOLD}${RESET} ${ORANGE}${BOLD}SMF2290${RESET} · Pensum ${BOLD}${RESET}\n"
printf " ${BOLD}${RESET} ${BOLD}${RESET}\n"
printf " ${BOLD}${RESET} ${GREEN}→ %-42s${RESET}${BOLD}${RESET}\n" "$URL"
printf " ${BOLD}${RESET} ${BOLD}${RESET}\n"
SHORT_NAME="${SERVER_NAME:0:36}"
printf " ${BOLD}${RESET} ${DIM}Server: %-38s${RESET}${BOLD}${RESET}\n" "$SHORT_NAME"
printf " ${BOLD}${RESET} ${DIM}Trykk Ctrl+C for å stoppe${RESET} ${BOLD}${RESET}\n"
printf " ${BOLD}└──────────────────────────────────────────────┘${RESET}\n\n"
open_browser
cd "$APP_DIR"
# shellcheck disable=SC2086
exec $SERVER_CMD