gh-137450: macOS installer shell path management improvements (#137451)

Separate the installer `Shell profile updater` postinstall script from the `Update Shell Profile.command` to enable more robust error handling.
This commit is contained in:
Ned Deily 2025-08-06 07:21:30 -04:00 committed by GitHub
parent 247dab27fd
commit 781eb1a688
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 192 additions and 85 deletions

View file

@ -1747,7 +1747,7 @@ def main():
fn = os.path.join(folder, "ReadMe.rtf")
patchFile("resources/ReadMe.rtf", fn)
fn = os.path.join(folder, "Update Shell Profile.command")
patchScript("scripts/postflight.patch-profile", fn)
patchScript("resources/update_shell_profile.command", fn)
fn = os.path.join(folder, "Install Certificates.command")
patchScript("resources/install_certificates.command", fn)
os.chmod(folder, STAT_0o755)

View file

@ -0,0 +1,116 @@
#!/bin/sh
echo "This script will update your shell profile when the 'bin' directory"
echo "of python is not early enough of the PATH of your shell."
echo "These changes will be effective only in shell windows that you open"
echo "after running this script."
PYVER=@PYVER@
PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
if [ `id -ur` = 0 ]; then
# Run from the installer, do some trickery to fetch the information
# we need.
theShell="`finger $USER | grep Shell: | head -1 | awk '{ print $NF }'`"
else
theShell="${SHELL}"
fi
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
BSH="`basename "${theShell}"`"
case "${BSH}" in
bash|ksh|sh|*csh|zsh|fish)
if [ `id -ur` = 0 ]; then
P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'`
else
P="`(exec -l ${theShell} -c 'echo $PATH')`"
fi
;;
*)
echo "Sorry, I don't know how to patch $BSH shells"
exit 0
;;
esac
# Now ensure that our bin directory is on $P and before /usr/bin at that
for elem in `echo $P | tr ':' ' '`
do
if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
echo "All right, you're a python lover already"
exit 0
elif [ "${elem}" = "/usr/bin" ]; then
break
fi
done
echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
case "${BSH}" in
*csh)
if [ -f "${HOME}/.tcshrc" ]; then
RC="${HOME}/.tcshrc"
else
RC="${HOME}/.cshrc"
fi
# Create backup copy before patching
if [ -f "${RC}" ]; then
cp -fp "${RC}" "${RC}.pysave"
fi
echo "" >> "${RC}"
echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
if [ `id -ur` = 0 ]; then
chown -h "${USER}" "${RC}"
fi
exit 0
;;
bash)
if [ -e "${HOME}/.bash_profile" ]; then
PR="${HOME}/.bash_profile"
elif [ -e "${HOME}/.bash_login" ]; then
PR="${HOME}/.bash_login"
elif [ -e "${HOME}/.profile" ]; then
PR="${HOME}/.profile"
else
PR="${HOME}/.bash_profile"
fi
;;
fish)
CONFIG_DIR="${HOME}/.config/fish/conf.d/"
RC="${CONFIG_DIR}/python-${PYVER}.fish"
mkdir -p "$CONFIG_DIR"
if [ -f "${RC}" ]; then
cp -fp "${RC}" "${RC}.pysave"
fi
echo "# Setting PATH for Python ${PYVER}" > "${RC}"
if [ -f "${RC}.pysave" ]; then
echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
fi
echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
if [ `id -ur` = 0 ]; then
chown -h "${USER}" "${RC}"
fi
exit 0
;;
zsh)
PR="${HOME}/.zprofile"
;;
*sh)
PR="${HOME}/.profile"
;;
esac
# Create backup copy before patching
if [ -f "${PR}" ]; then
cp -fp "${PR}" "${PR}.pysave"
fi
echo "" >> "${PR}"
echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
echo 'export PATH' >> "${PR}"
if [ `id -ur` = 0 ]; then
chown -h "${USER}" "${PR}"
fi
exit 0

View file

@ -1,50 +1,24 @@
#!/bin/sh
echo "This script will update your shell profile when the 'bin' directory"
echo "of python is not early enough of the PATH of your shell."
echo "These changes will be effective only in shell windows that you open"
echo "after running this script."
PYVER=@PYVER@
PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
if [ `id -ur` = 0 ]; then
# Run from the installer, do some trickery to fetch the information
# we need.
theShell="`finger $USER | grep Shell: | head -1 | awk '{ print $NF }'`"
else
theShell="${SHELL}"
fi
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
BSH="`basename "${theShell}"`"
case "${BSH}" in
bash|ksh|sh|*csh|zsh|fish)
if [ `id -ur` = 0 ]; then
P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'`
else
P="`(exec -l ${theShell} -c 'echo $PATH')`"
fi
true
;;
*)
echo "Sorry, I don't know how to patch $BSH shells"
exit 0
;;
esac
# Now ensure that our bin directory is on $P and before /usr/bin at that
for elem in `echo $P | tr ':' ' '`
do
if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
echo "All right, you're a python lover already"
exit 0
elif [ "${elem}" = "/usr/bin" ]; then
break
fi
done
echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
case "${BSH}" in
*csh)
if [ -f "${HOME}/.tcshrc" ]; then
@ -52,6 +26,9 @@ case "${BSH}" in
else
RC="${HOME}/.cshrc"
fi
# Drop privileges while writing files.
su -m ${USER} <<EOFC
# Create backup copy before patching
if [ -f "${RC}" ]; then
cp -fp "${RC}" "${RC}.pysave"
@ -59,9 +36,11 @@ case "${BSH}" in
echo "" >> "${RC}"
echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
echo "set path=(${PYTHON_ROOT}/bin "'\$path'")" >> "${RC}"
EOFC
if [ `id -ur` = 0 ]; then
chown "${USER}" "${RC}"
chown -h "${USER}" "${RC}"
fi
exit 0
;;
@ -79,6 +58,9 @@ bash)
fish)
CONFIG_DIR="${HOME}/.config/fish/conf.d/"
RC="${CONFIG_DIR}/python-${PYVER}.fish"
# Drop privileges while writing files.
su -m ${USER} <<EOFF
mkdir -p "$CONFIG_DIR"
if [ -f "${RC}" ]; then
cp -fp "${RC}" "${RC}.pysave"
@ -88,8 +70,10 @@ fish)
echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
fi
echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
EOFF
if [ `id -ur` = 0 ]; then
chown "${USER}" "${RC}"
chown -h "${USER}" "${RC}"
fi
exit 0
;;
@ -101,6 +85,8 @@ zsh)
;;
esac
# Drop privileges while writing files.
su -m ${USER} <<EOFS
# Create backup copy before patching
if [ -f "${PR}" ]; then
cp -fp "${PR}" "${PR}.pysave"
@ -108,9 +94,11 @@ fi
echo "" >> "${PR}"
echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
echo 'PATH="'"${PYTHON_ROOT}/bin"':\${PATH}"' >> "${PR}"
echo 'export PATH' >> "${PR}"
EOFS
if [ `id -ur` = 0 ]; then
chown "${USER}" "${PR}"
chown -h "${USER}" "${PR}"
fi
exit 0

View file

@ -0,0 +1,3 @@
macOS installer shell path management improvements: separate the installer
``Shell profile updater`` postinstall script from the
``Update Shell Profile.command`` to enable more robust error handling.