@@ -21,61 +21,136 @@ UPDATE_RC="${UPDATE_RC:-"true"}"
2121
2222set -e
2323
24- # Clean up
25- rm -rf /var/lib/apt/lists/*
26-
2724if [ " $( id -u) " -ne 0 ]; then
2825 echo -e ' Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
2926 exit 1
3027fi
3128
29+ # Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME
30+ . /etc/os-release
31+ # Get an adjusted ID independent of distro variants
32+ MAJOR_VERSION_ID=$( echo ${VERSION_ID} | cut -d . -f 1)
33+ if [ " ${ID} " = " debian" ] || [ " ${ID_LIKE} " = " debian" ]; then
34+ ADJUSTED_ID=" debian"
35+ elif [[ " ${ID} " = " rhel" || " ${ID} " = " fedora" || " ${ID} " = " mariner" || " ${ID_LIKE} " = * " rhel" * || " ${ID_LIKE} " = * " fedora" * || " ${ID_LIKE} " = * " mariner" * ]]; then
36+ ADJUSTED_ID=" rhel"
37+ if [[ " ${ID} " = " rhel" ]] || [[ " ${ID} " = * " alma" * ]] || [[ " ${ID} " = * " rocky" * ]]; then
38+ VERSION_CODENAME=" rhel${MAJOR_VERSION_ID} "
39+ else
40+ VERSION_CODENAME=" ${ID}${MAJOR_VERSION_ID} "
41+ fi
42+ else
43+ echo " Linux distro ${ID} not supported."
44+ exit 1
45+ fi
46+
47+ # Setup INSTALL_CMD & PKG_MGR_CMD
48+ if type apt-get > /dev/null 2>&1 ; then
49+ PKG_MGR_CMD=apt-get
50+ INSTALL_CMD=" ${PKG_MGR_CMD} -y install --no-install-recommends"
51+ elif type microdnf > /dev/null 2>&1 ; then
52+ PKG_MGR_CMD=microdnf
53+ INSTALL_CMD=" ${PKG_MGR_CMD} -y install --refresh --best --nodocs --noplugins --setopt=install_weak_deps=0"
54+ elif type dnf > /dev/null 2>&1 ; then
55+ PKG_MGR_CMD=dnf
56+ INSTALL_CMD=" ${PKG_MGR_CMD} -y install"
57+ else
58+ PKG_MGR_CMD=yum
59+ INSTALL_CMD=" ${PKG_MGR_CMD} -y install"
60+ fi
61+
62+ # Clean up
63+ clean_up () {
64+ case ${ADJUSTED_ID} in
65+ debian)
66+ rm -rf /var/lib/apt/lists/*
67+ ;;
68+ rhel)
69+ rm -rf /var/cache/dnf/* /var/cache/yum/*
70+ rm -f /etc/yum.repos.d/yarn.repo
71+ ;;
72+ esac
73+ }
74+ clean_up
75+
3276# Ensure that login shells get the correct path if the user updated the PATH using ENV.
3377rm -f /etc/profile.d/00-restore-env.sh
3478echo " export PATH=${PATH// $(sh -lc ' echo $PATH' )/ \$ PATH} " > /etc/profile.d/00-restore-env.sh
3579chmod +x /etc/profile.d/00-restore-env.sh
3680
37- # Determine the appropriate non-root user
38- if [ " ${USERNAME} " = " auto" ] || [ " ${USERNAME} " = " automatic" ]; then
39- USERNAME=" "
40- POSSIBLE_USERS=(" vscode" " node" " codespace" " $( awk -v val=1000 -F " :" ' $3==val{print $1}' /etc/passwd) " )
41- for CURRENT_USER in " ${POSSIBLE_USERS[@]} " ; do
42- if id -u ${CURRENT_USER} > /dev/null 2>&1 ; then
43- USERNAME=${CURRENT_USER}
44- break
45- fi
46- done
47- if [ " ${USERNAME} " = " " ]; then
48- USERNAME=root
49- fi
50- elif [ " ${USERNAME} " = " none" ] || ! id -u ${USERNAME} > /dev/null 2>&1 ; then
51- USERNAME=root
52- fi
53-
5481updaterc () {
82+ local _bashrc
83+ local _zshrc
5584 if [ " ${UPDATE_RC} " = " true" ]; then
56- echo " Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
57- if [[ " $( cat /etc/bash.bashrc) " != * " $1 " * ]]; then
58- echo -e " $1 " >> /etc/bash.bashrc
85+ case $ADJUSTED_ID in
86+ debian)
87+ _bashrc=/etc/bash.bashrc
88+ _zshrc=/etc/zsh/zshrc
89+ ;;
90+ rhel)
91+ _bashrc=/etc/bashrc
92+ _zshrc=/etc/zshrc
93+ ;;
94+ esac
95+ echo " Updating ${_bashrc} and ${_zshrc} ..."
96+ if [[ " $( cat ${_bashrc} ) " != * " $1 " * ]]; then
97+ echo -e " $1 " >> " ${_bashrc} "
5998 fi
60- if [ -f " /etc/zsh/zshrc " ] && [[ " $( cat /etc/zsh/zshrc ) " != * " $1 " * ]]; then
61- echo -e " $1 " >> /etc/zsh/zshrc
99+ if [ -f " ${_zshrc} " ] && [[ " $( cat ${_zshrc} ) " != * " $1 " * ]]; then
100+ echo -e " $1 " >> " ${_zshrc} "
62101 fi
63102 fi
64103}
65104
66- apt_get_update () {
67- if [ " $( find /var/lib/apt/lists/* | wc -l) " = " 0" ]; then
68- echo " Running apt-get update..."
69- apt-get update -y
70- fi
105+ pkg_mgr_update () {
106+ case $ADJUSTED_ID in
107+ debian)
108+ if [ " $( find /var/lib/apt/lists/* 2> /dev/null | wc -l) " = " 0" ]; then
109+ echo " Running apt-get update..."
110+ ${PKG_MGR_CMD} update -y
111+ fi
112+ ;;
113+ rhel)
114+ if [ ${PKG_MGR_CMD} = " microdnf" ]; then
115+ if [ " $( ls /var/cache/yum/* 2> /dev/null | wc -l) " = 0 ]; then
116+ echo " Running ${PKG_MGR_CMD} makecache ..."
117+ ${PKG_MGR_CMD} makecache
118+ fi
119+ else
120+ if [ " $( ls /var/cache/${PKG_MGR_CMD} /* 2> /dev/null | wc -l) " = 0 ]; then
121+ echo " Running ${PKG_MGR_CMD} check-update ..."
122+ set +e
123+ stderr_messages=$( ${PKG_MGR_CMD} -q check-update 2>&1 )
124+ rc=$?
125+ # centos 7 sometimes returns a status of 100 when it apears to work.
126+ if [ $rc != 0 ] && [ $rc != 100 ]; then
127+ echo " (Error) ${PKG_MGR_CMD} check-update produced the following error message(s):"
128+ echo " ${stderr_messages} "
129+ exit 1
130+ fi
131+ set -e
132+ fi
133+ fi
134+ ;;
135+ esac
71136}
72137
73138# Checks if packages are installed and installs them if not
74139check_packages () {
75- if ! dpkg -s " $@ " > /dev/null 2>&1 ; then
76- apt_get_update
77- apt-get -y install --no-install-recommends " $@ "
78- fi
140+ case ${ADJUSTED_ID} in
141+ debian)
142+ if ! dpkg -s " $@ " > /dev/null 2>&1 ; then
143+ pkg_mgr_update
144+ ${INSTALL_CMD} " $@ "
145+ fi
146+ ;;
147+ rhel)
148+ if ! rpm -q " $@ " > /dev/null 2>&1 ; then
149+ pkg_mgr_update
150+ ${INSTALL_CMD} " $@ "
151+ fi
152+ ;;
153+ esac
79154}
80155
81156# Figure out correct version of a three part version number is not passed
@@ -112,35 +187,95 @@ find_version_from_git_tags() {
112187 echo " ${variable_name} =${! variable_name} "
113188}
114189
190+ install_yarn () {
191+ if [ " ${ADJUSTED_ID} " = " debian" ]; then
192+ # for backward compatiblity with existing devcontainer features, install yarn
193+ # via apt-get on Debian systems
194+ if ! type yarn > /dev/null 2>&1 ; then
195+ # Import key safely (new method rather than deprecated apt-key approach) and install
196+ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg
197+ echo " deb [arch=$( dpkg --print-architecture) signed-by=/usr/share/keyrings/yarn-archive-keyring.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
198+ apt-get update
199+ apt-get -y install --no-install-recommends yarn
200+ else
201+ echo " Yarn is already installed."
202+ fi
203+ else
204+ local _ver=${1:- node}
205+ # on non-debian systems, prefer corepack, fallback to npm based installation of yarn...
206+ # Try to leverage corepack if possible
207+ # From https://yarnpkg.com:
208+ # The preferred way to manage Yarn is by-project and through Corepack, a tool
209+ # shipped by default with Node.js. Modern releases of Yarn aren't meant to be
210+ # installed globally, or from npm.
211+ if ! bash -c " . '${NVM_DIR} /nvm.sh' && nvm use ${_ver} && type yarn >/dev/null 2>&1" ; then
212+ if bash -c " . '${NVM_DIR} /nvm.sh' && nvm use ${_ver} && type corepack >/dev/null 2>&1" ; then
213+ su ${USERNAME} -c " umask 0002 && . '${NVM_DIR} /nvm.sh' && nvm use ${_ver} && corepack enable"
214+ fi
215+ if ! bash -c " . '${NVM_DIR} /nvm.sh' && nvm use ${_ver} && type yarn >/dev/null 2>&1" ; then
216+ # Yum/DNF want to install nodejs dependencies, we'll use NPM to install yarn
217+ su ${USERNAME} -c " umask 0002 && . '${NVM_DIR} /nvm.sh' && nvm use ${_ver} && npm install --global yarn"
218+ fi
219+ else
220+ echo " Yarn already installed."
221+ fi
222+ fi
223+ }
224+
225+ # Mariner does not have awk installed by default, this can cause
226+ # problems is username is auto* and later when we try to install
227+ # node via npm.
228+ if ! type awk > /dev/null 2>&1 ; then
229+ check_packages awk
230+ fi
231+
232+ # Determine the appropriate non-root user
233+ if [ " ${USERNAME} " = " auto" ] || [ " ${USERNAME} " = " automatic" ]; then
234+ USERNAME=" "
235+ POSSIBLE_USERS=(" vscode" " node" " codespace" " $( awk -v val=1000 -F " :" ' $3==val{print $1}' /etc/passwd) " )
236+ for CURRENT_USER in " ${POSSIBLE_USERS[@]} " ; do
237+ if id -u ${CURRENT_USER} > /dev/null 2>&1 ; then
238+ USERNAME=${CURRENT_USER}
239+ break
240+ fi
241+ done
242+ if [ " ${USERNAME} " = " " ]; then
243+ USERNAME=root
244+ fi
245+ elif [ " ${USERNAME} " = " none" ] || ! id -u ${USERNAME} > /dev/null 2>&1 ; then
246+ USERNAME=root
247+ fi
248+
115249# Ensure apt is in non-interactive to avoid prompts
116250export DEBIAN_FRONTEND=noninteractive
117251
118- . /etc/os-release
119- if [[ " bionic " = * " ${VERSION_CODENAME} " * ]] ; then
120- if [[ " ${NODE_VERSION} " =~ " 18 " ]] || [[ " ${NODE_VERSION} " = " lts " ]]; then
121- echo " (!) Unsupported distribution version '${VERSION_CODENAME} ' for Node 18. Details: https://github.com/nodejs/node/issues/42351#issuecomment-1068424442"
252+ if ( [ -n " ${VERSION_CODENAME} " ] && [[ " bionic " = * " ${VERSION_CODENAME} " * ]] ) || [[ " rhel7 " = * " ${ADJUSTED_ID}${MAJOR_VERSION_ID} " * ]] ; then
253+ node_major_version= $( echo " ${NODE_VERSION} " | cut -d . -f 1 )
254+ if [[ " ${node_major_version} " -ge 18 ]] || [[ " ${ NODE_VERSION}" = " lts " ]] || [[ " ${NODE_VERSION} " = " latest " ]]; then
255+ echo " (!) Unsupported distribution version '${VERSION_CODENAME} ' for Node >= 18. Details: https://github.com/nodejs/node/issues/42351#issuecomment-1068424442"
122256 exit 1
123257 fi
124258fi
125259
126260# Install dependencies
127- check_packages apt-transport-https curl ca-certificates tar gnupg2 dirmngr
261+ case ${ADJUSTED_ID} in
262+ debian)
263+ check_packages apt-transport-https curl ca-certificates tar gnupg2 dirmngr
264+ ;;
265+ rhel)
266+ check_packages ca-certificates tar gnupg2 which findutils util-linux tar
267+ # minimal RHEL installs may not include curl, or includes curl-minimal instead.
268+ # Install curl if the "curl" command is not present.
269+ if ! type curl > /dev/null 2>&1 ; then
270+ check_packages curl
271+ fi
272+ ;;
273+ esac
128274
129275if ! type git > /dev/null 2>&1 ; then
130276 check_packages git
131277fi
132278
133- # Install yarn
134- if type yarn > /dev/null 2>&1 ; then
135- echo " Yarn already installed."
136- else
137- # Import key safely (new method rather than deprecated apt-key approach) and install
138- curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg
139- echo " deb [arch=$( dpkg --print-architecture) signed-by=/usr/share/keyrings/yarn-archive-keyring.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
140- apt-get update
141- apt-get -y install --no-install-recommends yarn
142- fi
143-
144279# Adjust node version if required
145280if [ " ${NODE_VERSION} " = " none" ]; then
146281 export NODE_VERSION=
@@ -159,6 +294,7 @@ umask 0002
159294# Do not update profile - we'll do this manually
160295export PROFILE=/dev/null
161296curl -so- "https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION} /install.sh" | bash
297+
162298source "${NVM_DIR} /nvm.sh"
163299if [ "${NODE_VERSION} " != "" ]; then
164300 nvm alias default "${NODE_VERSION} "
204340 fi
205341fi
206342
343+ # Possibly install yarn (puts yarn in per-Node install on RHEL, uses system yarn on Debian)
344+ install_yarn
345+
207346# Additional node versions to be installed but not be set as
208347# default we can assume the nvm is the group owner of the nvm
209348# directory and the sticky bit on directories so any installed
@@ -214,6 +353,8 @@ if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
214353 read -a additional_versions <<< " $ADDITIONAL_VERSIONS"
215354 for ver in " ${additional_versions[@]} " ; do
216355 su ${USERNAME} -c " umask 0002 && . '$NVM_DIR /nvm.sh' && nvm install '${ver} '"
356+ # possibly install yarn (puts yarn in per-Node install on RHEL, uses system yarn on Debian)
357+ install_yarn " ${ver} "
217358 done
218359
219360 # Ensure $NODE_VERSION is on the $PATH
@@ -224,14 +365,17 @@ if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
224365fi
225366
226367# Install pnpm
227- if type pnpm > /dev/null 2>&1 ; then
368+ if bash -c " . ' ${NVM_DIR} /nvm.sh' && type pnpm >/dev/null 2>&1" ; then
228369 echo " pnpm already installed."
229370else
230- if type npm > /dev/null 2>&1 ; then
231- [ ! -z " $http_proxy " ] && npm set proxy=" $http_proxy "
232- [ ! -z " $https_proxy " ] && npm set https-proxy=" $https_proxy "
233- [ ! -z " $no_proxy " ] && npm set noproxy=" $no_proxy "
234- npm install -g pnpm
371+ if bash -c " . '${NVM_DIR} /nvm.sh' && type npm >/dev/null 2>&1" ; then
372+ (
373+ . " ${NVM_DIR} /nvm.sh"
374+ [ ! -z " $http_proxy " ] && npm set proxy=" $http_proxy "
375+ [ ! -z " $https_proxy " ] && npm set https-proxy=" $https_proxy "
376+ [ ! -z " $no_proxy " ] && npm set noproxy=" $no_proxy "
377+ npm install -g pnpm
378+ )
235379 else
236380 echo " Skip installing pnpm because npm is missing"
237381 fi
@@ -248,21 +392,29 @@ if [ "${INSTALL_TOOLS_FOR_NODE_GYP}" = "true" ]; then
248392 to_install=" ${to_install} gcc"
249393 fi
250394 if ! type g++ > /dev/null 2>&1 ; then
251- to_install=" ${to_install} g++"
395+ if [ ${ADJUSTED_ID} = " debian" ]; then
396+ to_install=" ${to_install} g++"
397+ elif [ ${ADJUSTED_ID} = " rhel" ]; then
398+ to_install=" ${to_install} gcc-c++"
399+ fi
252400 fi
253401 if ! type python3 > /dev/null 2>&1 ; then
254- to_install=" ${to_install} python3-minimal"
402+ if [ ${ADJUSTED_ID} = " debian" ]; then
403+ to_install=" ${to_install} python3-minimal"
404+ elif [ ${ADJUSTED_ID} = " rhel" ]; then
405+ to_install=" ${to_install} python3"
406+ fi
255407 fi
256408 if [ ! -z " ${to_install} " ]; then
257- apt_get_update
258- apt-get -y install ${to_install}
409+ pkg_mgr_update
410+ check_packages ${to_install}
259411 fi
260412fi
261413
262414
263415# Clean up
264416su ${USERNAME} -c " umask 0002 && . '$NVM_DIR /nvm.sh' && nvm clear-cache"
265- rm -rf /var/lib/apt/lists/ *
417+ clean_up
266418
267419# Ensure privs are correct for installed node versions. Unfortunately the
268420# way nvm installs node versions pulls privs from the tar which does not
0 commit comments