From 415d784ca02c9e0c9a975d1b0942fdc69c7edad6 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Sun, 25 Oct 2026 13:32:32 +0200 Subject: [PATCH] Find Ansible's interpreter also behind python-exec and wrapper scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Gentoo, the shebang of `ansible-playbook` is the python-exec dispatcher (`#!/usr/bin/python-exec2c`), which bin/ansible-python.sh took for an interpreter, because its name starts with `python`. python-exec only runs the programs it wraps, so every `just run…` recipe failed with "no python-exec wrapped executable found". Now only names like `python`, `python3` or `python3.14` are trusted. For anything else (python-exec, wrapper scripts as on Nix), Ansible is asked which interpreter it runs on (`ansible-playbook --version`), before falling back to `python3`, which may lack PyYAML (e.g. in an active virtualenv). Same as https://github.com/mother-of-all-self-hosting/mash-playbook/commit/a685940a Co-Authored-By: Claude Opus 5.5 (1M context) --- bin/ansible-python.sh | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/bin/ansible-python.sh b/bin/ansible-python.sh index ee55fd55f..f3357c536 100755 --- a/bin/ansible-python.sh +++ b/bin/ansible-python.sh @@ -11,12 +11,12 @@ # where the system's `python3` may lack it. # # The interpreter is taken from the first line (shebang) of `ansible-playbook`. -# If that is not a Python interpreter (e.g. `ansible-playbook` is a wrapper script), or Ansible is not installed, -# `python3` is used. +# If that is not a Python interpreter (e.g. `ansible-playbook` is a wrapper script, or Gentoo's python-exec), +# Ansible is asked which interpreter it runs on. If that fails too, or Ansible is not installed, `python3` is used. set -eu -python=python3 +interpreter= ansible_playbook_path=$(command -v ansible-playbook 2>/dev/null || true) if [ -n "$ansible_playbook_path" ] && [ -f "$ansible_playbook_path" ]; then @@ -30,15 +30,26 @@ EOF if [ "$(basename "$interpreter")" = "env" ]; then interpreter=${next_word:-} fi - case "$(basename "${interpreter:-none}")" in - python*) - if command -v "$interpreter" >/dev/null 2>&1; then - python=$interpreter - fi - ;; - esac ;; esac + + # Only names like `python`, `python3` or `python3.14` are interpreters (`python-exec2c` is not) + case "$(basename "${interpreter:-none}")" in + python | python[0-9] | python[0-9].[0-9]*) ;; + *) interpreter= ;; + esac + + if [ -z "$interpreter" ] || ! command -v "$interpreter" >/dev/null 2>&1; then + # The interpreter ends a line like: ` python version = 3.14.0 (main, …) [GCC …] (/usr/bin/python3.14)` + interpreter=$("$ansible_playbook_path" --version 2>/dev/null \ + | sed -n 's/^ *python version = .*(\([^()]*\))$/\1/p' | head -n 1) || true + fi +fi + +if [ -n "$interpreter" ] && command -v "$interpreter" >/dev/null 2>&1; then + python=$interpreter +else + python=python3 fi exec "$python" "$@"