Skip to content

Commit 781eb1a

Browse files
authored
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.
1 parent 247dab2 commit 781eb1a

File tree

4 files changed

+192
-85
lines changed

4 files changed

+192
-85
lines changed

Mac/BuildScript/build-installer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,7 @@ def main():
17471747
fn = os.path.join(folder, "ReadMe.rtf")
17481748
patchFile("resources/ReadMe.rtf", fn)
17491749
fn = os.path.join(folder, "Update Shell Profile.command")
1750-
patchScript("scripts/postflight.patch-profile", fn)
1750+
patchScript("resources/update_shell_profile.command", fn)
17511751
fn = os.path.join(folder, "Install Certificates.command")
17521752
patchScript("resources/install_certificates.command", fn)
17531753
os.chmod(folder, STAT_0o755)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/bin/sh
2+
3+
echo "This script will update your shell profile when the 'bin' directory"
4+
echo "of python is not early enough of the PATH of your shell."
5+
echo "These changes will be effective only in shell windows that you open"
6+
echo "after running this script."
7+
8+
PYVER=@PYVER@
9+
PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
10+
11+
if [ `id -ur` = 0 ]; then
12+
# Run from the installer, do some trickery to fetch the information
13+
# we need.
14+
theShell="`finger $USER | grep Shell: | head -1 | awk '{ print $NF }'`"
15+
16+
else
17+
theShell="${SHELL}"
18+
fi
19+
20+
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
21+
BSH="`basename "${theShell}"`"
22+
case "${BSH}" in
23+
bash|ksh|sh|*csh|zsh|fish)
24+
if [ `id -ur` = 0 ]; then
25+
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'`
26+
else
27+
P="`(exec -l ${theShell} -c 'echo $PATH')`"
28+
fi
29+
;;
30+
*)
31+
echo "Sorry, I don't know how to patch $BSH shells"
32+
exit 0
33+
;;
34+
esac
35+
36+
# Now ensure that our bin directory is on $P and before /usr/bin at that
37+
for elem in `echo $P | tr ':' ' '`
38+
do
39+
if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
40+
echo "All right, you're a python lover already"
41+
exit 0
42+
elif [ "${elem}" = "/usr/bin" ]; then
43+
break
44+
fi
45+
done
46+
47+
echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
48+
case "${BSH}" in
49+
*csh)
50+
if [ -f "${HOME}/.tcshrc" ]; then
51+
RC="${HOME}/.tcshrc"
52+
else
53+
RC="${HOME}/.cshrc"
54+
fi
55+
# Create backup copy before patching
56+
if [ -f "${RC}" ]; then
57+
cp -fp "${RC}" "${RC}.pysave"
58+
fi
59+
echo "" >> "${RC}"
60+
echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
61+
echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
62+
echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
63+
if [ `id -ur` = 0 ]; then
64+
chown -h "${USER}" "${RC}"
65+
fi
66+
exit 0
67+
;;
68+
bash)
69+
if [ -e "${HOME}/.bash_profile" ]; then
70+
PR="${HOME}/.bash_profile"
71+
elif [ -e "${HOME}/.bash_login" ]; then
72+
PR="${HOME}/.bash_login"
73+
elif [ -e "${HOME}/.profile" ]; then
74+
PR="${HOME}/.profile"
75+
else
76+
PR="${HOME}/.bash_profile"
77+
fi
78+
;;
79+
fish)
80+
CONFIG_DIR="${HOME}/.config/fish/conf.d/"
81+
RC="${CONFIG_DIR}/python-${PYVER}.fish"
82+
mkdir -p "$CONFIG_DIR"
83+
if [ -f "${RC}" ]; then
84+
cp -fp "${RC}" "${RC}.pysave"
85+
fi
86+
echo "# Setting PATH for Python ${PYVER}" > "${RC}"
87+
if [ -f "${RC}.pysave" ]; then
88+
echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
89+
fi
90+
echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
91+
if [ `id -ur` = 0 ]; then
92+
chown -h "${USER}" "${RC}"
93+
fi
94+
exit 0
95+
;;
96+
zsh)
97+
PR="${HOME}/.zprofile"
98+
;;
99+
*sh)
100+
PR="${HOME}/.profile"
101+
;;
102+
esac
103+
104+
# Create backup copy before patching
105+
if [ -f "${PR}" ]; then
106+
cp -fp "${PR}" "${PR}.pysave"
107+
fi
108+
echo "" >> "${PR}"
109+
echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
110+
echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
111+
echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
112+
echo 'export PATH' >> "${PR}"
113+
if [ `id -ur` = 0 ]; then
114+
chown -h "${USER}" "${PR}"
115+
fi
116+
exit 0
Lines changed: 72 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,104 @@
11
#!/bin/sh
22

3-
echo "This script will update your shell profile when the 'bin' directory"
4-
echo "of python is not early enough of the PATH of your shell."
5-
echo "These changes will be effective only in shell windows that you open"
6-
echo "after running this script."
7-
83
PYVER=@PYVER@
94
PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
105

11-
if [ `id -ur` = 0 ]; then
12-
# Run from the installer, do some trickery to fetch the information
13-
# we need.
14-
theShell="`finger $USER | grep Shell: | head -1 | awk '{ print $NF }'`"
156

16-
else
17-
theShell="${SHELL}"
18-
fi
7+
# Run from the installer, do some trickery to fetch the information
8+
# we need.
9+
theShell="`finger $USER | grep Shell: | head -1 | awk '{ print $NF }'`"
1910

2011
# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
2112
BSH="`basename "${theShell}"`"
2213
case "${BSH}" in
2314
bash|ksh|sh|*csh|zsh|fish)
24-
if [ `id -ur` = 0 ]; then
25-
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'`
26-
else
27-
P="`(exec -l ${theShell} -c 'echo $PATH')`"
28-
fi
29-
;;
15+
true
16+
;;
3017
*)
31-
echo "Sorry, I don't know how to patch $BSH shells"
32-
exit 0
33-
;;
18+
exit 0
19+
;;
3420
esac
3521

36-
# Now ensure that our bin directory is on $P and before /usr/bin at that
37-
for elem in `echo $P | tr ':' ' '`
38-
do
39-
if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
40-
echo "All right, you're a python lover already"
41-
exit 0
42-
elif [ "${elem}" = "/usr/bin" ]; then
43-
break
44-
fi
45-
done
46-
47-
echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
4822
case "${BSH}" in
4923
*csh)
50-
if [ -f "${HOME}/.tcshrc" ]; then
51-
RC="${HOME}/.tcshrc"
52-
else
53-
RC="${HOME}/.cshrc"
54-
fi
55-
# Create backup copy before patching
56-
if [ -f "${RC}" ]; then
57-
cp -fp "${RC}" "${RC}.pysave"
58-
fi
59-
echo "" >> "${RC}"
60-
echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
61-
echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
62-
echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
63-
if [ `id -ur` = 0 ]; then
64-
chown "${USER}" "${RC}"
65-
fi
66-
exit 0
67-
;;
24+
if [ -f "${HOME}/.tcshrc" ]; then
25+
RC="${HOME}/.tcshrc"
26+
else
27+
RC="${HOME}/.cshrc"
28+
fi
29+
30+
# Drop privileges while writing files.
31+
su -m ${USER} <<EOFC
32+
# Create backup copy before patching
33+
if [ -f "${RC}" ]; then
34+
cp -fp "${RC}" "${RC}.pysave"
35+
fi
36+
echo "" >> "${RC}"
37+
echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
38+
echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
39+
echo "set path=(${PYTHON_ROOT}/bin "'\$path'")" >> "${RC}"
40+
EOFC
41+
42+
if [ `id -ur` = 0 ]; then
43+
chown -h "${USER}" "${RC}"
44+
fi
45+
exit 0
46+
;;
6847
bash)
69-
if [ -e "${HOME}/.bash_profile" ]; then
70-
PR="${HOME}/.bash_profile"
71-
elif [ -e "${HOME}/.bash_login" ]; then
72-
PR="${HOME}/.bash_login"
73-
elif [ -e "${HOME}/.profile" ]; then
74-
PR="${HOME}/.profile"
75-
else
76-
PR="${HOME}/.bash_profile"
77-
fi
78-
;;
48+
if [ -e "${HOME}/.bash_profile" ]; then
49+
PR="${HOME}/.bash_profile"
50+
elif [ -e "${HOME}/.bash_login" ]; then
51+
PR="${HOME}/.bash_login"
52+
elif [ -e "${HOME}/.profile" ]; then
53+
PR="${HOME}/.profile"
54+
else
55+
PR="${HOME}/.bash_profile"
56+
fi
57+
;;
7958
fish)
80-
CONFIG_DIR="${HOME}/.config/fish/conf.d/"
81-
RC="${CONFIG_DIR}/python-${PYVER}.fish"
82-
mkdir -p "$CONFIG_DIR"
83-
if [ -f "${RC}" ]; then
84-
cp -fp "${RC}" "${RC}.pysave"
85-
fi
86-
echo "# Setting PATH for Python ${PYVER}" > "${RC}"
87-
if [ -f "${RC}.pysave" ]; then
88-
echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
89-
fi
90-
echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
91-
if [ `id -ur` = 0 ]; then
92-
chown "${USER}" "${RC}"
93-
fi
94-
exit 0
95-
;;
59+
CONFIG_DIR="${HOME}/.config/fish/conf.d/"
60+
RC="${CONFIG_DIR}/python-${PYVER}.fish"
61+
62+
# Drop privileges while writing files.
63+
su -m ${USER} <<EOFF
64+
mkdir -p "$CONFIG_DIR"
65+
if [ -f "${RC}" ]; then
66+
cp -fp "${RC}" "${RC}.pysave"
67+
fi
68+
echo "# Setting PATH for Python ${PYVER}" > "${RC}"
69+
if [ -f "${RC}.pysave" ]; then
70+
echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
71+
fi
72+
echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
73+
EOFF
74+
75+
if [ `id -ur` = 0 ]; then
76+
chown -h "${USER}" "${RC}"
77+
fi
78+
exit 0
79+
;;
9680
zsh)
97-
PR="${HOME}/.zprofile"
98-
;;
81+
PR="${HOME}/.zprofile"
82+
;;
9983
*sh)
100-
PR="${HOME}/.profile"
101-
;;
84+
PR="${HOME}/.profile"
85+
;;
10286
esac
10387

88+
# Drop privileges while writing files.
89+
su -m ${USER} <<EOFS
10490
# Create backup copy before patching
10591
if [ -f "${PR}" ]; then
106-
cp -fp "${PR}" "${PR}.pysave"
92+
cp -fp "${PR}" "${PR}.pysave"
10793
fi
10894
echo "" >> "${PR}"
10995
echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
11096
echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
111-
echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
97+
echo 'PATH="'"${PYTHON_ROOT}/bin"':\${PATH}"' >> "${PR}"
11298
echo 'export PATH' >> "${PR}"
99+
EOFS
100+
113101
if [ `id -ur` = 0 ]; then
114-
chown "${USER}" "${PR}"
102+
chown -h "${USER}" "${PR}"
115103
fi
116104
exit 0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
macOS installer shell path management improvements: separate the installer
2+
``Shell profile updater`` postinstall script from the
3+
``Update Shell Profile.command`` to enable more robust error handling.

0 commit comments

Comments
 (0)