#!/bin/sh # Entry point for the bug-report collector, so agents and people start it through one # stable path on every platform: # # tools/bugreport [options] # # This is the POSIX half - Linux, macOS and Git Bash on Windows. PowerShell resolves # the same string to tools/bugreport.ps1 first. # # tools/bugreport.py is the one part of the stack that has to run when nothing else # does, so this script assumes nothing the preflight sets up: no .wikitool-tools.json, # no venv. It looks for a Python itself, the way the preflight does - on Windows # python, py -3, python3; elsewhere python3, python; every match on PATH in PATH # order - and only then tries the venv's. It never starts anything under WindowsApps: # there, python.exe and python3.exe are the Microsoft Store's aliases, and in Git Bash # `python3` is exactly that. Every candidate is probed first, so one that is too old or # that the machine refuses to run (a venv python.exe blocked by Defender) is passed over # rather than ending the report. # # Without any Python 3.8 or newer it says so and exits 1, never 42: the collector opens # no gate. # # CHEMENU_PREFLIGHT_PLATFORM stands in for the platform, as it does for the preflight; # the test suite is its only user. set -u DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P) || exit 1 MIN=3.8 # Exit 3 marks "a Python, but too old" apart from "did not start at all". PROBE='import sys; sys.exit(0 if sys.version_info >= (3, 8) else 3)' platform=${CHEMENU_PREFLIGHT_PLATFORM:-} if [ -z "$platform" ]; then case "$(uname -s 2>/dev/null)" in MINGW*|MSYS*|CYGWIN*) platform=windows ;; *) platform=other ;; esac fi if [ "$platform" = windows ]; then order="python: py:-3 python3:" looked="python, py -3, python3" else order="python3: python:" looked="python3, python" fi is_store_alias() { case "$1" in *[Ww]indows[Aa]pps/*|*[Ww]indows[Aa]pps\\*) return 0 ;; esac return 1 } # Every executable called on PATH, in PATH order, store aliases dropped. on_path() { set -f old_ifs=$IFS IFS=: for d in $PATH; do [ -n "$d" ] || d=. for f in "$d/$1" "$d/$1.exe"; do if [ -f "$f" ] && [ -x "$f" ] && ! is_store_alias "$f"; then printf '%s\n' "$f" fi done done IFS=$old_ifs set +f } PY="" EXTRA="" TOO_OLD="" probe() { # [extra argument, e.g. -3 for py] -> sets PY/EXTRA on success "$@" -c "$PROBE" >/dev/null 2>&1 status=$? if [ "$status" -eq 0 ]; then PY=$1 EXTRA=${2:-} return 0 fi if [ "$status" -eq 3 ]; then TOO_OLD="$TOO_OLD $1" fi return 1 } for candidate in $order; do name=${candidate%%:*} extra=${candidate#*:} found=$(on_path "$name") [ -n "$found" ] || continue # A here-document, not a pipe: `break 2` has to leave the outer loop of this # shell, and a path may contain spaces ("Program Files"). while IFS= read -r path; do if [ -n "$extra" ]; then probe "$path" "$extra" && break 2 else probe "$path" && break 2 fi done < tools/bugreport.py " } >&2 exit 1