Skip to content

Commit 7e312a1

Browse files
Node.js Feature installs from prebuilt binaries (#14)
The Nodesource APT repository has been misbehaving recently (e.g. a recent version of Node.js just went missing…?), so this change switches to installing Node.js from prebuilt binaries directly from the Node.js project.
2 parents 8edaf64 + 577b51c commit 7e312a1

4 files changed

Lines changed: 78 additions & 51 deletions

File tree

src/node/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
# node
22

3-
Install [Node.js](https://nodejs.org) from [Nodesource's DEB repository](https://deb.nodesource.com).
3+
Install [Node.js](https://nodejs.org) from prebuilt binaries.
44

55
## Usage
66

77
```json
88
"features": {
9-
"ghcr.io/CargoSense/devcontainer-features/node:3": {}
9+
"ghcr.io/CargoSense/devcontainer-features/node:4": {}
1010
}
1111
```
1212

1313
## Options
1414

1515
| Option ID | Description | Type | Default Value |
1616
|:----------|:--------------------------------|:-------|:--------------|
17-
| `version` | The Node.js version to install. | string | `automatic` |
17+
| `version` | The Node.js version to install. | string | `latest` |
1818

1919
## OS Support
2020

21-
This Feature should work on recent versions of Debian/Ubuntu and Linux distributions using the [apt](https://wiki.debian.org/AptCLI) management tool.
21+
This Feature should work on recent versions of Debian/Ubuntu and Linux distributions using the [apt](https://wiki.debian.org/AptCLI) management tool and on architectures for which Node.js provides prebuilt binaries.

src/node/devcontainer-feature.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
{
22
"name": "Node.js",
33
"id": "node",
4-
"version": "3.0.0",
5-
"description": "Install Node.js from Nodesource's DEB repository.",
4+
"version": "4.0.0",
5+
"description": "Install Node.js from prebuilt binaries.",
66
"documentationURL": "https://github.com/CargoSense/devcontainer-features/tree/main/src/node",
77
"licenseURL": "https://github.com/CargoSense/devcontainer-features/blob/main/LICENSE",
88
"options": {
99
"version": {
1010
"type": "string",
11-
"default": "automatic",
11+
"default": "latest",
1212
"description": "The Node.js version to install."
1313
}
1414
},
1515
"containerEnv": {
16-
"NPM_CONFIG_CACHE": "/usr/local/npm"
16+
"NPM_CONFIG_CACHE": "/usr/local/npm",
17+
"NODE_HOME": "/usr/local/share/node",
18+
"PATH": "/usr/local/share/node/bin:${PATH}"
19+
},
20+
"dependsOn": {
21+
"ghcr.io/CargoSense/devcontainer-features/apt-packages:1": {
22+
"packages": "libatomic1"
23+
}
1724
},
1825
"installsAfter": [
1926
"ghcr.io/devcontainers/features/common-utils"

src/node/install.sh

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,31 @@
22

33
set -e
44

5-
NODE_VERSION="${VERSION:-"automatic"}"
6-
NODE_MAJOR_VERSION="24"
7-
8-
pkg="nodejs"
9-
10-
if [[ "${NODE_VERSION}" != "automatic" ]]; then
11-
NODE_MAJOR_VERSION="$(echo "${NODE_VERSION}" | cut -d. -f1)"
12-
pkg="${pkg}=${NODE_VERSION}-1nodesource1"
5+
NODE_VERSION="${VERSION:-"latest"}"
6+
7+
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
8+
9+
# Determine the appropriate non-root user.
10+
if [[ "${USERNAME}" = "automatic" ]]; then
11+
USERNAME=""
12+
POSSIBLE_USERS=("vscode" "node" "$(getent passwd 1000 | cut -d: -f1)")
13+
14+
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
15+
if id -u "${CURRENT_USER}" >/dev/null 2>&1; then
16+
USERNAME="${CURRENT_USER}"
17+
break
18+
fi
19+
done
20+
21+
if [[ "${USERNAME}" = "" ]]; then
22+
USERNAME="root"
23+
fi
24+
elif ! id -u "${USERNAME}" >/dev/null 2>&1; then
25+
USERNAME="root"
1326
fi
1427

1528
curl_installed=""
16-
gpg_installed=""
29+
xz_installed=""
1730

1831
if ! type curl >/dev/null 2>&1; then
1932
apt update --yes
@@ -22,49 +35,56 @@ if ! type curl >/dev/null 2>&1; then
2235
curl_installed="true"
2336
fi
2437

25-
if ! type gpg >/dev/null 2>&1; then
38+
if ! type xz >/dev/null 2>&1; then
2639
apt update --yes
27-
apt install --yes gnupg
40+
apt install --yes xz-utils
2841

29-
gpg_installed="true"
42+
xz_installed="true"
3043
fi
3144

32-
apt_sources_snippet="$(cat << EOF
33-
Types: deb
34-
URIs: https://deb.nodesource.com/node_${NODE_MAJOR_VERSION}.x
35-
Suites: nodistro
36-
Components: main
37-
Signed-By: /etc/apt/keyrings/nodesource.gpg
38-
EOF
39-
)"
40-
41-
install -dm 755 /etc/apt/keyrings
42-
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
43-
echo "${apt_sources_snippet}" | tee /etc/apt/sources.list.d/nodesource.sources
45+
# Normalize architecture
46+
arch="$(dpkg --print-architecture)"
47+
if [[ "${arch}" = "amd64" ]] || [[ "${arch}" = "x86_64" ]] || [[ "${arch}" = "i386" ]]; then
48+
arch="x64"
49+
fi
4450

45-
if [[ -n "${curl_installed}" ]]; then
46-
apt purge curl --autoremove --yes
47-
rm -rf /var/lib/apt/lists/*
51+
# Normalize Node.js version string
52+
if [[ "${NODE_VERSION}" != "latest" ]] && [[ "${NODE_VERSION}" != "v"* ]]; then
53+
NODE_VERSION="v${NODE_VERSION}"
4854
fi
4955

50-
if [[ -n "${gpg_installed}" ]]; then
51-
apt purge gnupg --autoremove --yes
52-
rm -rf /var/lib/apt/lists/*
56+
# Configure "node" group
57+
if ! grep -e "^node:" /etc/group >/dev/null 2>&1; then
58+
groupadd --system node
5359
fi
60+
usermod --append --groups node "${USERNAME}"
61+
62+
# Install Node.js
63+
umask 0002
64+
mkdir -p "${NODE_HOME:?}"
65+
curl -fsSL "https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-${arch}.tar.xz" | tar xf - -C "${NODE_HOME}" -J --strip-components 1
5466

55-
apt update --yes
56-
apt install --yes "${pkg}"
57-
rm -rf /var/lib/apt/lists/*
67+
chown -R "${USERNAME}:node" "${NODE_HOME}"
68+
chmod g+rws "${NODE_HOME}"
5869

59-
node_rc_snippet="$(cat << EOF
60-
export NODE_VERSION="$(node -v | cut -c2-)"
61-
EOF
62-
)"
70+
# Configure shell
71+
rc_snippet="export NODE_VERSION=\"$(node -v | cut -c2-)\""
6372

64-
if [[ "$(cat /etc/bash.bashrc)" != *"${node_rc_snippet}"* ]]; then
65-
echo "${node_rc_snippet}" >> /etc/bash.bashrc
73+
if [[ -f /etc/bash.bashrc ]] && ! grep -q "${rc_snippet}" /etc/bash.bashrc; then
74+
echo "${rc_snippet}" >>/etc/bash.bashrc
6675
fi
6776

68-
if [[ -f "/etc/zsh/zshrc" ]] && [[ "$(cat /etc/zsh/zshrc)" != *"${node_rc_snippet}"* ]]; then
69-
echo "${node_rc_snippet}" >> /etc/zsh/zshrc
77+
if [[ -f /etc/zsh/zshrc ]] && ! grep -q "${rc_snippet}" /etc/zsh/zshrc; then
78+
echo "${rc_snippet}" >>/etc/zsh/zshrc
79+
fi
80+
81+
# Cleanup
82+
if [[ -n "${curl_installed}" ]]; then
83+
apt purge curl --autoremove --yes
84+
rm -rf /var/lib/apt/lists/*
85+
fi
86+
87+
if [[ -n "${xz_installed}" ]]; then
88+
apt purge xz-utils --autoremove --yes
89+
rm -rf /var/lib/apt/lists/*
7090
fi

test/node/test.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ set -e
77
source dev-container-features-test-lib
88

99
# Feature-specific tests
10-
check "version" bash -c "node --version | grep -E 'v24\..+'"
11-
check "which node" bash -c "which node | grep /usr/bin/node"
10+
check "version" bash -c "node --version | grep -E 'v25\..+'"
11+
check "which node" bash -c "which node | grep /usr/local/share/node/bin/node"
1212

1313
# Report result
1414
reportResults

0 commit comments

Comments
 (0)