From 252beaf4ba59a76a0922c5a22ac3aa7d6b1e3559 Mon Sep 17 00:00:00 2001
From: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Date: Thu, 6 Nov 2025 14:38:31 -0500
Subject: [PATCH 1/5] refactor-install-page
---
docs/docs/get-started/install.mdx | 126 ++++++++++++++++++++----------
1 file changed, 86 insertions(+), 40 deletions(-)
diff --git a/docs/docs/get-started/install.mdx b/docs/docs/get-started/install.mdx
index cbaa5095..7d4d4af1 100644
--- a/docs/docs/get-started/install.mdx
+++ b/docs/docs/get-started/install.mdx
@@ -28,66 +28,112 @@ If you prefer running Podman or Docker containers and manually editing `.env` fi
- Create an [OpenAI API key](https://platform.openai.com/api-keys). This key is **required** to start OpenRAG, but you can choose a different model provider during [Application Onboarding](#application-onboarding).
- Optional: Install GPU support with an NVIDIA GPU, [CUDA](https://docs.nvidia.com/cuda/) support, and compatible NVIDIA drivers on the OpenRAG host machine. If you don't have GPU capabilities, OpenRAG provides an alternate CPU-only deployment.
-## Install OpenRAG {#install}
+## Installation Methods {#install}
:::note Windows users
To use OpenRAG on Windows, use [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install).
:::
-To set up a project and install OpenRAG as a dependency, do the following:
+Choose an installation method based on your needs:
-1. Create a new project with a virtual environment using `uv init`.
+* For a quick test, use `uvx` to run OpenRAG without creating a project or modifying files.
+* Use `uv add` to install OpenRAG as a managed dependency in a new or existing Python project.
+* Use `uv pip install` to install OpenRAG into an existing virtual environment.
- ```bash
- uv init YOUR_PROJECT_NAME
- cd YOUR_PROJECT_NAME
- ```
+
+
- The `(venv)` prompt doesn't change, but `uv` commands will automatically use the project's virtual environment.
- For more information on virtual environments, see the [uv documentation](https://docs.astral.sh/uv/pip/environments).
-
-2. Add OpenRAG to your project.
- ```bash
- uv add openrag
- ```
-
- To add a specific version of OpenRAG:
- ```bash
- uv add openrag==0.1.25
- ```
-
-3. Start the OpenRAG TUI.
- ```bash
- uv run openrag
- ```
-
-
- Install a local wheel
-
- If you downloaded the OpenRAG wheel to your local machine, follow these steps:
-
- 1. Add the wheel to your project's virtual environment.
+ Use `uvx` to quickly run OpenRAG without creating a project or modifying any files.
+ 1. Create a directory to store the OpenRAG configuration files:
```bash
- uv add PATH/TO/openrag-VERSION-py3-none-any.whl
+ mkdir openrag-workspace
+ cd openrag-workspace
```
- Replace `PATH/TO/` and `VERSION` with the path and version of your downloaded OpenRAG `.whl` file.
-
- For example, if your `.whl` file is in the `~/Downloads` directory:
-
+ 2. Run OpenRAG:
```bash
- uv add ~/Downloads/openrag-0.1.8-py3-none-any.whl
+ uvx openrag
```
- 2. Run OpenRAG.
+ To run a specific version:
+ ```bash
+ uvx --from openrag==0.1.30 openrag
+ ```
+ The TUI creates a `.env` file and docker-compose files in the current working directory.
+
+
+
+
+ Use `uv add` to install OpenRAG as a dependency in your Python project. This adds OpenRAG to your `pyproject.toml` and lockfile, making your installation reproducible and version-controlled.
+
+ 1. Create a new project with a virtual environment:
+ ```bash
+ uv init YOUR_PROJECT_NAME
+ cd YOUR_PROJECT_NAME
+ ```
+
+ The `(venv)` prompt doesn't change, but `uv` commands will automatically use the project's virtual environment.
+
+ 2. Add OpenRAG to your project:
+ ```bash
+ uv add openrag
+ ```
+
+ To add a specific version:
+ ```bash
+ uv add openrag==0.1.30
+ ```
+
+ 3. Start the OpenRAG TUI:
```bash
uv run openrag
```
-
+
+
+ Install a local wheel
+
+ If you downloaded the OpenRAG wheel to your local machine, install it by specifying its path:
+
+ 1. Add the wheel to your project:
+ ```bash
+ uv add PATH/TO/openrag-VERSION-py3-none-any.whl
+ ```
+
+ Replace `PATH/TO/` and `VERSION` with the path and version of your downloaded OpenRAG `.whl` file.
+
+ 2. Run OpenRAG:
+ ```bash
+ uv run openrag
+ ```
-4. Continue with [Set up OpenRAG with the TUI](#setup).
+
+
+
+
+ Use `uv pip install` to install OpenRAG into an existing virtual environment that isn't managed by `uv`.
+
+ :::tip
+ For new projects, `uv add` is recommended as it manages dependencies in your project's lockfile.
+ :::
+
+ 1. Activate your virtual environment.
+
+ 2. Install OpenRAG:
+ ```bash
+ uv pip install openrag
+ ```
+
+ 3. Run OpenRAG:
+ ```bash
+ openrag
+ ```
+
+
+
+
+Continue with [Set up OpenRAG with the TUI](#setup).
## Set up OpenRAG with the TUI {#setup}
From 2914723faeb50f89f99fce8dda71ebe7e3bc4458 Mon Sep 17 00:00:00 2001
From: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Date: Thu, 6 Nov 2025 15:58:27 -0500
Subject: [PATCH 2/5] add-symlink-for-script
---
docs/static/scripts/run_openrag_with_prereqs.sh | 1 +
1 file changed, 1 insertion(+)
create mode 120000 docs/static/scripts/run_openrag_with_prereqs.sh
diff --git a/docs/static/scripts/run_openrag_with_prereqs.sh b/docs/static/scripts/run_openrag_with_prereqs.sh
new file mode 120000
index 00000000..efeabacd
--- /dev/null
+++ b/docs/static/scripts/run_openrag_with_prereqs.sh
@@ -0,0 +1 @@
+../../scripts/run_openrag_with_prereqs.sh
\ No newline at end of file
From ea636ac90a99aff31baf39aadbdcc374ecd2bbd7 Mon Sep 17 00:00:00 2001
From: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Date: Thu, 6 Nov 2025 16:00:30 -0500
Subject: [PATCH 3/5] add-script-to-install
---
docs/docs/get-started/install.mdx | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/docs/docs/get-started/install.mdx b/docs/docs/get-started/install.mdx
index 7d4d4af1..4e0ddaec 100644
--- a/docs/docs/get-started/install.mdx
+++ b/docs/docs/get-started/install.mdx
@@ -36,12 +36,31 @@ To use OpenRAG on Windows, use [WSL (Windows Subsystem for Linux)](https://learn
Choose an installation method based on your needs:
+* The automatic installer script detects and installs prerequisites and then runs OpenRAG. Recommended for first-time users.
* For a quick test, use `uvx` to run OpenRAG without creating a project or modifying files.
* Use `uv add` to install OpenRAG as a managed dependency in a new or existing Python project.
* Use `uv pip install` to install OpenRAG into an existing virtual environment.
-
+
+
+ The script detects and installs uv, Docker/Podman, and Docker Compose prerequisites, then runs OpenRAG with `uvx`.
+
+ 1. Create a directory to store the OpenRAG configuration files:
+ ```bash
+ mkdir openrag-workspace
+ cd openrag-workspace
+ ```
+
+ 2. Run the installer:
+ ```bash
+ curl -LsSf https://docs.openr.ag/scripts/run_openrag_with_prereqs.sh | sh
+ ```
+
+ The TUI creates a `.env` file and docker-compose files in the current working directory.
+
+
+
Use `uvx` to quickly run OpenRAG without creating a project or modifying any files.
From 52dbecbefccb1d93843febcb0bbcd9e2f80d4583 Mon Sep 17 00:00:00 2001
From: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Date: Thu, 6 Nov 2025 16:40:26 -0500
Subject: [PATCH 4/5] replace-symlink-with-file
---
docs/static/files/run_openrag_with_prereqs.sh | 345 ++++++++++++++++++
.../scripts/run_openrag_with_prereqs.sh | 1 -
2 files changed, 345 insertions(+), 1 deletion(-)
create mode 100755 docs/static/files/run_openrag_with_prereqs.sh
delete mode 120000 docs/static/scripts/run_openrag_with_prereqs.sh
diff --git a/docs/static/files/run_openrag_with_prereqs.sh b/docs/static/files/run_openrag_with_prereqs.sh
new file mode 100755
index 00000000..d620256e
--- /dev/null
+++ b/docs/static/files/run_openrag_with_prereqs.sh
@@ -0,0 +1,345 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+say() { printf "%s\n" "$*" >&2; }
+hr() { say "----------------------------------------"; }
+
+ask_yes_no() {
+ local prompt="${1:-Continue?} [Y/n] "
+ read -r -p "$prompt" ans || true
+ case "${ans:-Y}" in [Yy]|[Yy][Ee][Ss]|"") return 0 ;; *) return 1 ;; esac
+}
+
+# --- Platform detection ------------------------------------------------------
+uname_s="$(uname -s 2>/dev/null || echo unknown)"
+is_wsl=false
+if [ -f /proc/version ]; then grep -qiE 'microsoft|wsl' /proc/version && is_wsl=true || true; fi
+
+case "$uname_s" in
+ Darwin) PLATFORM="macOS" ;;
+ Linux) PLATFORM="$($is_wsl && echo WSL || echo Linux)" ;;
+ CYGWIN*|MINGW*|MSYS*) PLATFORM="Windows" ;;
+ *) PLATFORM="Unknown" ;;
+esac
+
+if [ "$PLATFORM" = "Windows" ]; then
+ say ">>> Native Windows shell detected. Please run this inside WSL (Ubuntu, etc.)."
+ exit 1
+fi
+
+# --- Minimal sudo (used only when necessary) --------------------------------
+SUDO="sudo"; $SUDO -n true >/dev/null 2>&1 || SUDO="sudo" # may prompt later only if needed
+
+# --- PATH probe for common bins (no sudo) -----------------------------------
+ensure_path_has_common_bins() {
+ local add=()
+ [ -d /opt/homebrew/bin ] && add+=("/opt/homebrew/bin")
+ [ -d /usr/local/bin ] && add+=("/usr/local/bin")
+ [ -d "/Applications/Docker.app/Contents/Resources/bin" ] && add+=("/Applications/Docker.app/Contents/Resources/bin")
+ [ -d "$HOME/.docker/cli-plugins" ] && add+=("$HOME/.docker/cli-plugins")
+ for p in "${add[@]}"; do case ":$PATH:" in *":$p:"*) ;; *) PATH="$p:$PATH" ;; esac; done
+ export PATH
+}
+ensure_path_has_common_bins
+
+# --- Helpers ----------------------------------------------------------------
+has_cmd() { command -v "$1" >/dev/null 2>&1; }
+docker_cli_path() { command -v docker 2>/dev/null || true; }
+podman_cli_path() { command -v podman 2>/dev/null || true; }
+
+docker_daemon_ready() { docker info >/dev/null 2>&1; } # no sudo; fails if socket perms/daemon issue
+compose_v2_ready() { docker compose version >/dev/null 2>&1; }
+compose_v1_ready() { command -v docker-compose >/dev/null 2>&1; }
+podman_ready() { podman info >/dev/null 2>&1; } # macOS may need podman machine
+
+docker_is_podman() {
+ # True if `docker` is Podman (podman-docker shim or alias)
+ if ! has_cmd docker; then return 1; fi
+
+ # 1) Text outputs
+ local out=""
+ out+="$(docker --version 2>&1 || true)\n"
+ out+="$(docker -v 2>&1 || true)\n"
+ out+="$(docker help 2>&1 | head -n 2 || true)\n"
+ if printf "%b" "$out" | grep -qiE '\bpodman\b'; then
+ return 0
+ fi
+
+ # 2) Symlink target / alternatives
+ local p t
+ p="$(command -v docker)"
+ if has_cmd readlink; then
+ t="$(readlink -f "$p" 2>/dev/null || readlink "$p" 2>/dev/null || echo "$p")"
+ printf "%s" "$t" | grep -qi 'podman' && return 0
+ fi
+ if [ -L /etc/alternatives/docker ]; then
+ t="$(readlink -f /etc/alternatives/docker 2>/dev/null || true)"
+ printf "%s" "$t" | grep -qi 'podman' && return 0
+ fi
+
+ # 3) Fallback: package id (rpm/dpkg), best effort (ignore errors)
+ if has_cmd rpm; then
+ rpm -qf "$p" 2>/dev/null | grep -qi 'podman' && return 0
+ fi
+ if has_cmd dpkg-query; then
+ dpkg-query -S "$p" 2>/dev/null | grep -qi 'podman' && return 0
+ fi
+
+ return 1
+}
+
+# --- uv install (optional) --------------------------------------------------
+install_uv() {
+ if has_cmd uv; then
+ say ">>> uv present: $(uv --version 2>/dev/null || echo ok)"
+ return
+ fi
+ if ! ask_yes_no "uv not found. Install uv now?"; then return; fi
+ if ! has_cmd curl; then say ">>> curl is required to install uv. Please install curl and re-run."; exit 1; fi
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+}
+
+# --- Docker: install if missing (never reinstall) ---------------------------
+install_docker_if_missing() {
+ if has_cmd docker; then
+ say ">>> Docker CLI detected at: $(docker_cli_path)"
+ say ">>> Version: $(docker --version 2>/dev/null || echo 'unknown')"
+ return
+ fi
+ say ">>> Docker CLI not found."
+ if ! ask_yes_no "Install Docker now?"; then return; fi
+
+ case "$PLATFORM" in
+ macOS)
+ if has_cmd brew; then
+ brew install --cask docker
+ say ">>> Starting Docker Desktop..."
+ open -gj -a Docker || true
+ else
+ say ">>> Homebrew not found. Install from https://brew.sh then: brew install --cask docker"
+ exit 1
+ fi
+ ;;
+ Linux|WSL)
+ if ! has_cmd curl; then say ">>> Need curl to install Docker. Install curl and re-run."; exit 1; fi
+ curl -fsSL https://get.docker.com | $SUDO sh
+ # Do NOT assume docker group exists everywhere; creation is distro-dependent
+ if getent group docker >/dev/null 2>&1; then
+ $SUDO usermod -aG docker "$USER" || true
+ fi
+ ;;
+ *)
+ say ">>> Unsupported platform for automated Docker install."
+ ;;
+ esac
+}
+
+# --- Docker daemon start/wait (sudo only if starting service) ---------------
+start_docker_daemon_if_needed() {
+ if docker_daemon_ready; then
+ say ">>> Docker daemon is ready."
+ return 0
+ fi
+
+ say ">>> Docker CLI found but daemon not reachable."
+ case "$PLATFORM" in
+ macOS)
+ say ">>> Attempting to start Docker Desktop..."
+ open -gj -a Docker || true
+ ;;
+ Linux|WSL)
+ say ">>> Attempting to start docker service (may prompt for sudo)..."
+ $SUDO systemctl start docker >/dev/null 2>&1 || $SUDO service docker start >/dev/null 2>&1 || true
+ ;;
+ esac
+
+ for i in {1..60}; do
+ docker_daemon_ready && { say ">>> Docker daemon is ready."; return 0; }
+ sleep 2
+ done
+
+ say ">>> Still not reachable. If Linux: check 'systemctl status docker' and group membership."
+ say ">>> If macOS: open Docker.app and wait for 'Docker Desktop is running'."
+ return 1
+}
+
+# --- Docker group activation (safe: only if group exists) -------------------
+activate_docker_group_now() {
+ [ "$PLATFORM" = "Linux" ] || [ "$PLATFORM" = "WSL" ] || return 0
+ has_cmd docker || return 0
+
+ # only act if the docker group actually exists
+ if ! getent group docker >/dev/null 2>&1; then
+ return 0
+ fi
+
+ # If user already in group, nothing to do
+ if id -nG "$USER" 2>/dev/null | grep -qw docker; then return 0; fi
+
+ # Re-enter with sg if available
+ if has_cmd sg; then
+ if [ -z "${REENTERED_WITH_DOCKER_GROUP:-}" ]; then
+ say ">>> Re-entering shell with 'docker' group active for this run..."
+ export REENTERED_WITH_DOCKER_GROUP=1
+ exec sg docker -c "REENTERED_WITH_DOCKER_GROUP=1 bash \"$0\""
+ fi
+ else
+ say ">>> You were likely added to 'docker' group. Open a new shell or run: newgrp docker"
+ fi
+}
+
+# --- Compose detection/offer (no reinstall) ---------------------------------
+check_or_offer_compose() {
+ if compose_v2_ready; then
+ say ">>> Docker Compose v2 available (docker compose)."
+ return 0
+ fi
+ if compose_v1_ready; then
+ say ">>> docker-compose (v1) available: $(docker-compose --version 2>/dev/null || echo ok)"
+ return 0
+ fi
+
+ say ">>> Docker Compose not found."
+ if ! ask_yes_no "Install Docker Compose plugin (v2)?"; then
+ say ">>> Skipping Compose install."
+ return 1
+ fi
+
+ case "$PLATFORM" in
+ macOS)
+ say ">>> On macOS, Docker Desktop bundles Compose v2. Starting Desktop…"
+ open -gj -a Docker || true
+ ;;
+ Linux|WSL)
+ if has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y docker-compose-plugin || true
+ elif has_cmd dnf; then $SUDO dnf install -y docker-compose-plugin || true
+ elif has_cmd yum; then $SUDO yum install -y docker-compose-plugin || true
+ elif has_cmd zypper; then $SUDO zypper install -y docker-compose docker-compose-plugin || true
+ elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm docker-compose || true
+ else
+ say ">>> Please install Compose via your distro's instructions."
+ fi
+ ;;
+ esac
+
+ if compose_v2_ready || compose_v1_ready; then
+ say ">>> Compose is now available."
+ else
+ say ">>> Could not verify Compose installation automatically."
+ fi
+}
+
+# --- Podman: install if missing (never reinstall) ---------------------------
+install_podman_if_missing() {
+ if has_cmd podman; then
+ say ">>> Podman CLI detected at: $(podman_cli_path)"
+ say ">>> Version: $(podman --version 2>/dev/null || echo 'unknown')"
+ return
+ fi
+ say ">>> Podman CLI not found."
+ if ! ask_yes_no "Install Podman now?"; then return; fi
+
+ case "$PLATFORM" in
+ macOS)
+ if has_cmd brew; then
+ brew install podman
+ else
+ say ">>> Install Homebrew first (https://brew.sh) then: brew install podman"
+ exit 1
+ fi
+ ;;
+ Linux|WSL)
+ if has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y podman
+ elif has_cmd dnf; then $SUDO dnf install -y podman
+ elif has_cmd yum; then $SUDO yum install -y podman
+ elif has_cmd zypper; then $SUDO zypper install -y podman
+ elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm podman
+ else
+ say ">>> Please install 'podman' via your distro."
+ fi
+ ;;
+ esac
+}
+
+ensure_podman_ready() {
+ if [ "$PLATFORM" = "macOS" ]; then
+ if ! podman machine list 2>/dev/null | grep -q running; then
+ say ">>> Starting Podman machine (macOS)…"
+ podman machine start || true
+ for i in {1..30}; do podman_ready && break || sleep 2; done
+ fi
+ fi
+ if podman_ready; then
+ say ">>> Podman is ready."
+ return 0
+ else
+ say ">>> Podman CLI present but not ready (try 'podman machine start' on macOS)."
+ return 1
+ fi
+}
+
+# --- Runtime auto-detect (prefer no prompt) ---------------------------------
+hr
+say "Platform: $PLATFORM"
+hr
+
+# uv (optional)
+if has_cmd uv; then say ">>> uv present: $(uv --version 2>/dev/null || echo ok)"; else install_uv; fi
+
+RUNTIME=""
+if docker_is_podman; then
+ say ">>> Detected podman-docker shim: using Podman runtime."
+ RUNTIME="Podman"
+elif has_cmd docker; then
+ say ">>> Docker CLI detected."
+ RUNTIME="Docker"
+elif has_cmd podman; then
+ say ">>> Podman CLI detected."
+ RUNTIME="Podman"
+fi
+
+if [ -z "$RUNTIME" ]; then
+ say "Choose container runtime:"
+ PS3="Select [1-2]: "
+ select rt in "Docker" "Podman"; do
+ case "$REPLY" in 1|2) RUNTIME="$rt"; break ;; *) say "Invalid choice";; esac
+ done
+fi
+
+say "Selected runtime: $RUNTIME"
+hr
+
+# --- Execute runtime path ----------------------------------------------------
+if [ "$RUNTIME" = "Docker" ]; then
+ install_docker_if_missing # no reinstall if present
+ activate_docker_group_now # safe: only if group exists and user not in it
+ start_docker_daemon_if_needed # sudo only to start service on Linux/WSL
+ check_or_offer_compose # offer to install Compose only if missing
+else
+ install_podman_if_missing # no reinstall if present
+ ensure_podman_ready
+ # Optional: podman-compose for compose-like UX
+ if ! command -v podman-compose >/dev/null 2>&1; then
+ if ask_yes_no "Install podman-compose (optional)?"; then
+ if has_cmd brew; then brew install podman-compose
+ elif has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y podman-compose || pip3 install --user podman-compose || true
+ elif has_cmd dnf; then $SUDO dnf install -y podman-compose || true
+ elif has_cmd yum; then $SUDO yum install -y podman-compose || true
+ elif has_cmd zypper; then $SUDO zypper install -y podman-compose || true
+ elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm podman-compose || true
+ else say ">>> Please install podman-compose via your distro."; fi
+ fi
+ fi
+fi
+
+hr
+say "Environment ready — launching: uvx openrag"
+hr
+
+if ! has_cmd uv; then
+ say ">>> 'uv' not on PATH. Add the installer’s bin dir to PATH, then run: uvx openrag"
+ exit 1
+fi
+
+exec uvx openrag
+
diff --git a/docs/static/scripts/run_openrag_with_prereqs.sh b/docs/static/scripts/run_openrag_with_prereqs.sh
deleted file mode 120000
index efeabacd..00000000
--- a/docs/static/scripts/run_openrag_with_prereqs.sh
+++ /dev/null
@@ -1 +0,0 @@
-../../scripts/run_openrag_with_prereqs.sh
\ No newline at end of file
From 94f0903b365bec9cc7d4f374d56fde9678b9a256 Mon Sep 17 00:00:00 2001
From: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Date: Thu, 6 Nov 2025 16:44:01 -0500
Subject: [PATCH 5/5] move-script
---
docs/docs/get-started/install.mdx | 2 +-
scripts/run_openrag_with_prereqs.sh | 345 ----------------------------
2 files changed, 1 insertion(+), 346 deletions(-)
delete mode 100755 scripts/run_openrag_with_prereqs.sh
diff --git a/docs/docs/get-started/install.mdx b/docs/docs/get-started/install.mdx
index 4e0ddaec..c52b6ec3 100644
--- a/docs/docs/get-started/install.mdx
+++ b/docs/docs/get-started/install.mdx
@@ -54,7 +54,7 @@ Choose an installation method based on your needs:
2. Run the installer:
```bash
- curl -LsSf https://docs.openr.ag/scripts/run_openrag_with_prereqs.sh | sh
+ curl -fsSL https://docs.openr.ag/files/run_openrag_with_prereqs.sh | bash
```
The TUI creates a `.env` file and docker-compose files in the current working directory.
diff --git a/scripts/run_openrag_with_prereqs.sh b/scripts/run_openrag_with_prereqs.sh
deleted file mode 100755
index d620256e..00000000
--- a/scripts/run_openrag_with_prereqs.sh
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-say() { printf "%s\n" "$*" >&2; }
-hr() { say "----------------------------------------"; }
-
-ask_yes_no() {
- local prompt="${1:-Continue?} [Y/n] "
- read -r -p "$prompt" ans || true
- case "${ans:-Y}" in [Yy]|[Yy][Ee][Ss]|"") return 0 ;; *) return 1 ;; esac
-}
-
-# --- Platform detection ------------------------------------------------------
-uname_s="$(uname -s 2>/dev/null || echo unknown)"
-is_wsl=false
-if [ -f /proc/version ]; then grep -qiE 'microsoft|wsl' /proc/version && is_wsl=true || true; fi
-
-case "$uname_s" in
- Darwin) PLATFORM="macOS" ;;
- Linux) PLATFORM="$($is_wsl && echo WSL || echo Linux)" ;;
- CYGWIN*|MINGW*|MSYS*) PLATFORM="Windows" ;;
- *) PLATFORM="Unknown" ;;
-esac
-
-if [ "$PLATFORM" = "Windows" ]; then
- say ">>> Native Windows shell detected. Please run this inside WSL (Ubuntu, etc.)."
- exit 1
-fi
-
-# --- Minimal sudo (used only when necessary) --------------------------------
-SUDO="sudo"; $SUDO -n true >/dev/null 2>&1 || SUDO="sudo" # may prompt later only if needed
-
-# --- PATH probe for common bins (no sudo) -----------------------------------
-ensure_path_has_common_bins() {
- local add=()
- [ -d /opt/homebrew/bin ] && add+=("/opt/homebrew/bin")
- [ -d /usr/local/bin ] && add+=("/usr/local/bin")
- [ -d "/Applications/Docker.app/Contents/Resources/bin" ] && add+=("/Applications/Docker.app/Contents/Resources/bin")
- [ -d "$HOME/.docker/cli-plugins" ] && add+=("$HOME/.docker/cli-plugins")
- for p in "${add[@]}"; do case ":$PATH:" in *":$p:"*) ;; *) PATH="$p:$PATH" ;; esac; done
- export PATH
-}
-ensure_path_has_common_bins
-
-# --- Helpers ----------------------------------------------------------------
-has_cmd() { command -v "$1" >/dev/null 2>&1; }
-docker_cli_path() { command -v docker 2>/dev/null || true; }
-podman_cli_path() { command -v podman 2>/dev/null || true; }
-
-docker_daemon_ready() { docker info >/dev/null 2>&1; } # no sudo; fails if socket perms/daemon issue
-compose_v2_ready() { docker compose version >/dev/null 2>&1; }
-compose_v1_ready() { command -v docker-compose >/dev/null 2>&1; }
-podman_ready() { podman info >/dev/null 2>&1; } # macOS may need podman machine
-
-docker_is_podman() {
- # True if `docker` is Podman (podman-docker shim or alias)
- if ! has_cmd docker; then return 1; fi
-
- # 1) Text outputs
- local out=""
- out+="$(docker --version 2>&1 || true)\n"
- out+="$(docker -v 2>&1 || true)\n"
- out+="$(docker help 2>&1 | head -n 2 || true)\n"
- if printf "%b" "$out" | grep -qiE '\bpodman\b'; then
- return 0
- fi
-
- # 2) Symlink target / alternatives
- local p t
- p="$(command -v docker)"
- if has_cmd readlink; then
- t="$(readlink -f "$p" 2>/dev/null || readlink "$p" 2>/dev/null || echo "$p")"
- printf "%s" "$t" | grep -qi 'podman' && return 0
- fi
- if [ -L /etc/alternatives/docker ]; then
- t="$(readlink -f /etc/alternatives/docker 2>/dev/null || true)"
- printf "%s" "$t" | grep -qi 'podman' && return 0
- fi
-
- # 3) Fallback: package id (rpm/dpkg), best effort (ignore errors)
- if has_cmd rpm; then
- rpm -qf "$p" 2>/dev/null | grep -qi 'podman' && return 0
- fi
- if has_cmd dpkg-query; then
- dpkg-query -S "$p" 2>/dev/null | grep -qi 'podman' && return 0
- fi
-
- return 1
-}
-
-# --- uv install (optional) --------------------------------------------------
-install_uv() {
- if has_cmd uv; then
- say ">>> uv present: $(uv --version 2>/dev/null || echo ok)"
- return
- fi
- if ! ask_yes_no "uv not found. Install uv now?"; then return; fi
- if ! has_cmd curl; then say ">>> curl is required to install uv. Please install curl and re-run."; exit 1; fi
- curl -LsSf https://astral.sh/uv/install.sh | sh
-}
-
-# --- Docker: install if missing (never reinstall) ---------------------------
-install_docker_if_missing() {
- if has_cmd docker; then
- say ">>> Docker CLI detected at: $(docker_cli_path)"
- say ">>> Version: $(docker --version 2>/dev/null || echo 'unknown')"
- return
- fi
- say ">>> Docker CLI not found."
- if ! ask_yes_no "Install Docker now?"; then return; fi
-
- case "$PLATFORM" in
- macOS)
- if has_cmd brew; then
- brew install --cask docker
- say ">>> Starting Docker Desktop..."
- open -gj -a Docker || true
- else
- say ">>> Homebrew not found. Install from https://brew.sh then: brew install --cask docker"
- exit 1
- fi
- ;;
- Linux|WSL)
- if ! has_cmd curl; then say ">>> Need curl to install Docker. Install curl and re-run."; exit 1; fi
- curl -fsSL https://get.docker.com | $SUDO sh
- # Do NOT assume docker group exists everywhere; creation is distro-dependent
- if getent group docker >/dev/null 2>&1; then
- $SUDO usermod -aG docker "$USER" || true
- fi
- ;;
- *)
- say ">>> Unsupported platform for automated Docker install."
- ;;
- esac
-}
-
-# --- Docker daemon start/wait (sudo only if starting service) ---------------
-start_docker_daemon_if_needed() {
- if docker_daemon_ready; then
- say ">>> Docker daemon is ready."
- return 0
- fi
-
- say ">>> Docker CLI found but daemon not reachable."
- case "$PLATFORM" in
- macOS)
- say ">>> Attempting to start Docker Desktop..."
- open -gj -a Docker || true
- ;;
- Linux|WSL)
- say ">>> Attempting to start docker service (may prompt for sudo)..."
- $SUDO systemctl start docker >/dev/null 2>&1 || $SUDO service docker start >/dev/null 2>&1 || true
- ;;
- esac
-
- for i in {1..60}; do
- docker_daemon_ready && { say ">>> Docker daemon is ready."; return 0; }
- sleep 2
- done
-
- say ">>> Still not reachable. If Linux: check 'systemctl status docker' and group membership."
- say ">>> If macOS: open Docker.app and wait for 'Docker Desktop is running'."
- return 1
-}
-
-# --- Docker group activation (safe: only if group exists) -------------------
-activate_docker_group_now() {
- [ "$PLATFORM" = "Linux" ] || [ "$PLATFORM" = "WSL" ] || return 0
- has_cmd docker || return 0
-
- # only act if the docker group actually exists
- if ! getent group docker >/dev/null 2>&1; then
- return 0
- fi
-
- # If user already in group, nothing to do
- if id -nG "$USER" 2>/dev/null | grep -qw docker; then return 0; fi
-
- # Re-enter with sg if available
- if has_cmd sg; then
- if [ -z "${REENTERED_WITH_DOCKER_GROUP:-}" ]; then
- say ">>> Re-entering shell with 'docker' group active for this run..."
- export REENTERED_WITH_DOCKER_GROUP=1
- exec sg docker -c "REENTERED_WITH_DOCKER_GROUP=1 bash \"$0\""
- fi
- else
- say ">>> You were likely added to 'docker' group. Open a new shell or run: newgrp docker"
- fi
-}
-
-# --- Compose detection/offer (no reinstall) ---------------------------------
-check_or_offer_compose() {
- if compose_v2_ready; then
- say ">>> Docker Compose v2 available (docker compose)."
- return 0
- fi
- if compose_v1_ready; then
- say ">>> docker-compose (v1) available: $(docker-compose --version 2>/dev/null || echo ok)"
- return 0
- fi
-
- say ">>> Docker Compose not found."
- if ! ask_yes_no "Install Docker Compose plugin (v2)?"; then
- say ">>> Skipping Compose install."
- return 1
- fi
-
- case "$PLATFORM" in
- macOS)
- say ">>> On macOS, Docker Desktop bundles Compose v2. Starting Desktop…"
- open -gj -a Docker || true
- ;;
- Linux|WSL)
- if has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y docker-compose-plugin || true
- elif has_cmd dnf; then $SUDO dnf install -y docker-compose-plugin || true
- elif has_cmd yum; then $SUDO yum install -y docker-compose-plugin || true
- elif has_cmd zypper; then $SUDO zypper install -y docker-compose docker-compose-plugin || true
- elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm docker-compose || true
- else
- say ">>> Please install Compose via your distro's instructions."
- fi
- ;;
- esac
-
- if compose_v2_ready || compose_v1_ready; then
- say ">>> Compose is now available."
- else
- say ">>> Could not verify Compose installation automatically."
- fi
-}
-
-# --- Podman: install if missing (never reinstall) ---------------------------
-install_podman_if_missing() {
- if has_cmd podman; then
- say ">>> Podman CLI detected at: $(podman_cli_path)"
- say ">>> Version: $(podman --version 2>/dev/null || echo 'unknown')"
- return
- fi
- say ">>> Podman CLI not found."
- if ! ask_yes_no "Install Podman now?"; then return; fi
-
- case "$PLATFORM" in
- macOS)
- if has_cmd brew; then
- brew install podman
- else
- say ">>> Install Homebrew first (https://brew.sh) then: brew install podman"
- exit 1
- fi
- ;;
- Linux|WSL)
- if has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y podman
- elif has_cmd dnf; then $SUDO dnf install -y podman
- elif has_cmd yum; then $SUDO yum install -y podman
- elif has_cmd zypper; then $SUDO zypper install -y podman
- elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm podman
- else
- say ">>> Please install 'podman' via your distro."
- fi
- ;;
- esac
-}
-
-ensure_podman_ready() {
- if [ "$PLATFORM" = "macOS" ]; then
- if ! podman machine list 2>/dev/null | grep -q running; then
- say ">>> Starting Podman machine (macOS)…"
- podman machine start || true
- for i in {1..30}; do podman_ready && break || sleep 2; done
- fi
- fi
- if podman_ready; then
- say ">>> Podman is ready."
- return 0
- else
- say ">>> Podman CLI present but not ready (try 'podman machine start' on macOS)."
- return 1
- fi
-}
-
-# --- Runtime auto-detect (prefer no prompt) ---------------------------------
-hr
-say "Platform: $PLATFORM"
-hr
-
-# uv (optional)
-if has_cmd uv; then say ">>> uv present: $(uv --version 2>/dev/null || echo ok)"; else install_uv; fi
-
-RUNTIME=""
-if docker_is_podman; then
- say ">>> Detected podman-docker shim: using Podman runtime."
- RUNTIME="Podman"
-elif has_cmd docker; then
- say ">>> Docker CLI detected."
- RUNTIME="Docker"
-elif has_cmd podman; then
- say ">>> Podman CLI detected."
- RUNTIME="Podman"
-fi
-
-if [ -z "$RUNTIME" ]; then
- say "Choose container runtime:"
- PS3="Select [1-2]: "
- select rt in "Docker" "Podman"; do
- case "$REPLY" in 1|2) RUNTIME="$rt"; break ;; *) say "Invalid choice";; esac
- done
-fi
-
-say "Selected runtime: $RUNTIME"
-hr
-
-# --- Execute runtime path ----------------------------------------------------
-if [ "$RUNTIME" = "Docker" ]; then
- install_docker_if_missing # no reinstall if present
- activate_docker_group_now # safe: only if group exists and user not in it
- start_docker_daemon_if_needed # sudo only to start service on Linux/WSL
- check_or_offer_compose # offer to install Compose only if missing
-else
- install_podman_if_missing # no reinstall if present
- ensure_podman_ready
- # Optional: podman-compose for compose-like UX
- if ! command -v podman-compose >/dev/null 2>&1; then
- if ask_yes_no "Install podman-compose (optional)?"; then
- if has_cmd brew; then brew install podman-compose
- elif has_cmd apt-get; then $SUDO apt-get update -y && $SUDO apt-get install -y podman-compose || pip3 install --user podman-compose || true
- elif has_cmd dnf; then $SUDO dnf install -y podman-compose || true
- elif has_cmd yum; then $SUDO yum install -y podman-compose || true
- elif has_cmd zypper; then $SUDO zypper install -y podman-compose || true
- elif has_cmd pacman; then $SUDO pacman -Sy --noconfirm podman-compose || true
- else say ">>> Please install podman-compose via your distro."; fi
- fi
- fi
-fi
-
-hr
-say "Environment ready — launching: uvx openrag"
-hr
-
-if ! has_cmd uv; then
- say ">>> 'uv' not on PATH. Add the installer’s bin dir to PATH, then run: uvx openrag"
- exit 1
-fi
-
-exec uvx openrag
-