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 -