Skip to content

Commit 38190da

Browse files
feat: make Rust feature compatible with Alpine
Signed-off-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
1 parent bb53d59 commit 38190da

File tree

5 files changed

+281
-270
lines changed

5 files changed

+281
-270
lines changed

src/rust/common.sh

100644100755
File mode changed.

src/rust/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// ref: https://github.com/devcontainers/spec/blob/main/schemas/devContainerFeature.schema.json
22
{
33
"id": "rust",
4-
"version": "7.1.5",
4+
"version": "8.0.0",
55
"name": "Development Container Feature - Rust",
66
"documentationURL": "https://github.com/georglauterbach/dev-container-features/tree/main/src/rust",
77
"description": "Work efficiently and effortlessly with the Rust programming language",

src/rust/install.sh

Lines changed: 7 additions & 269 deletions
Original file line numberDiff line numberDiff line change
@@ -1,273 +1,11 @@
1-
#! /usr/bin/env bash
1+
#! /bin/sh
22

3-
# -----------------------------------------------
4-
# ---- Prologue -------------------------------
5-
# -----------------------------------------------
3+
set -e
64

7-
set -eE -u -o pipefail
8-
shopt -s inherit_errexit
5+
. /etc/os-release
96

10-
CURRENT_DIR="$(realpath -eL "$(dirname "${BASH_SOURCE[0]}")")"
11-
readonly CURRENT_DIR
7+
if [ "${ID}" = "alpine" ]; then
8+
apk add --no-cache bash
9+
fi
1210

13-
# shellcheck source=./common.sh
14-
source "${CURRENT_DIR}/common.sh"
15-
16-
readonly DATA_DIR="${DATA_BASE_DIR}/rust"
17-
mkdir -p "${DATA_DIR}"
18-
19-
# -----------------------------------------------
20-
# ---- Argument Parsing -----------------------
21-
# -----------------------------------------------
22-
23-
function parse_dev_container_options() {
24-
log 'info' 'Parsing input from options'
25-
26-
readonly RUST_INSTALL="${RUST_INSTALL:?RUST_INSTALL not set or null}"
27-
readonly RUST_INSTALL_BASE_PACKAGES="${RUST_INSTALL_BASE_PACKAGES:?RUST_INSTALL_BASE_PACKAGES not set or null}"
28-
readonly RUST_RUSTUP_DEFAULT_TOOLCHAIN=${RUST_RUSTUP_DEFAULT_TOOLCHAIN:?RUST_RUSTUP_DEFAULT_TOOLCHAIN not set or null}
29-
readonly RUST_RUSTUP_DEFAULT_TOOLCHAIN_FILE=${RUST_RUSTUP_DEFAULT_TOOLCHAIN_FILE?RUST_RUSTUP_DEFAULT_TOOLCHAIN_FILE not set}
30-
readonly RUST_RUSTUP_UPDATE_DEFAULT_TOOLCHAIN=${RUST_RUSTUP_UPDATE_DEFAULT_TOOLCHAIN:?RUST_RUSTUP_UPDATE_DEFAULT_TOOLCHAIN not set or null}
31-
readonly RUST_RUSTUP_PROFILE=${RUST_RUSTUP_PROFILE:?RUST_RUSTUP_PROFILE not set or null}
32-
readonly RUST_RUSTUP_ADDITIONAL_TARGETS=${RUST_RUSTUP_ADDITIONAL_TARGETS?RUST_RUSTUP_ADDITIONAL_TARGETS not set}
33-
readonly RUST_RUSTUP_ADDITIONAL_COMPONENTS=${RUST_RUSTUP_ADDITIONAL_COMPONENTS?RUST_RUSTUP_ADDITIONAL_COMPONENTS not set}
34-
readonly RUST_RUSTUP_DIST_SERVER=${RUST_RUSTUP_DIST_SERVER:?RUST_RUSTUP_DIST_SERVER not set or null}
35-
readonly RUST_RUSTUP_UPDATE_ROOT=${RUST_RUSTUP_UPDATE_ROOT:?RUST_RUSTUP_UPDATE_ROOT not set or null}
36-
RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE=${RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE?RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE not set or null}
37-
38-
readonly SYSTEM_PACKAGES_PACKAGE_MANAGER_SET_PROXIES=${SYSTEM_PACKAGES_PACKAGE_MANAGER_SET_PROXIES:?SYSTEM_PACKAGES_PACKAGE_MANAGER_SET_PROXIES not set or null}
39-
readonly SYSTEM_PACKAGES_ADDITIONAL_PACKAGES="${SYSTEM_PACKAGES_ADDITIONAL_PACKAGES?SYSTEM_PACKAGES_ADDITIONAL_PACKAGES not set}"
40-
41-
readonly LINKER_MOLD_INSTALL=${LINKER_MOLD_INSTALL:?LINKER_MOLD_INSTALL not set or null}
42-
readonly LINKER_MOLD_VERSION=${LINKER_MOLD_VERSION?LINKER_MOLD_VERSION not set}
43-
44-
readonly DOWNLOAD_ACQUIRE_INSECURE="${DOWNLOAD_ACQUIRE_INSECURE:?DOWNLOAD_ACQUIRE_INSECURE set or null}"
45-
46-
[[ -v http_proxy ]] || export http_proxy=${PROXY_HTTP_HTTP_ADDRESS?PROXY_HTTP_HTTP_ADDRESS not set}
47-
[[ -v https_proxy ]] || export https_proxy=${PROXY_HTTP_HTTPS_ADDRESS?PROXY_HTTP_HTTPS_ADDRESS not set}
48-
[[ -v no_proxy ]] || export no_proxy=${PROXY_HTTP_NO_PROXY_ADDRESS?PROXY_HTTP_NO_PROXY_ADDRESS not set}
49-
50-
return 0
51-
}
52-
53-
# -----------------------------------------------
54-
# ---- Pre-Flight Checks ----------------------
55-
# -----------------------------------------------
56-
57-
function pre_flight_checks() {
58-
log 'info' 'Running pre-flight checks'
59-
60-
case "${LINUX_DISTRIBUTION_NAME}" in
61-
( 'debian' )
62-
if value_is_true SYSTEM_PACKAGES_PACKAGE_MANAGER_SET_PROXIES; then
63-
log 'debug' 'Setting proxies for APT'
64-
local APT_CONFIG_FILE='/etc/apt/apt.conf' ; readonly APT_CONFIG_FILE
65-
mkdir --parents "$(dirname "${APT_CONFIG_FILE}")"
66-
if [[ -n ${https_proxy} ]]; then
67-
echo "Acquire::http::Proxy \"${https_proxy}\";" >>"${APT_CONFIG_FILE}"
68-
elif [[ -n ${http_proxy} ]]; then
69-
echo "Acquire::http::Proxy \"${http_proxy}\";" >>"${APT_CONFIG_FILE}"
70-
fi
71-
fi
72-
73-
if value_is_true RUST_INSTALL_BASE_PACKAGES; then
74-
log 'debug' 'Updating APT package index and installing required base packages'
75-
apt-get --yes --quiet=2 --option=Dpkg::Use-Pty=0 update
76-
apt-get --yes --quiet=2 --option=Dpkg::Use-Pty=0 install --no-install-recommends \
77-
'build-essential' 'ca-certificates' 'curl'
78-
fi
79-
;;
80-
81-
( * ) ;;
82-
esac
83-
84-
return 0
85-
}
86-
87-
# -----------------------------------------------
88-
# ---- Actual Functionality -------------------
89-
# -----------------------------------------------
90-
91-
function install_additional_packages() {
92-
if [[ -n ${SYSTEM_PACKAGES_ADDITIONAL_PACKAGES} ]]; then
93-
local __SYSTEM_PACKAGES_ADDITIONAL_PACKAGES
94-
IFS=',' read -r -a __SYSTEM_PACKAGES_ADDITIONAL_PACKAGES <<< "${SYSTEM_PACKAGES_ADDITIONAL_PACKAGES// /}"
95-
96-
case "${LINUX_DISTRIBUTION_NAME}" in
97-
( 'debian' )
98-
log 'info' 'Installing additional packages via APT'
99-
apt-get --yes --quiet=2 --option=Dpkg::Use-Pty=0 update
100-
apt-get --yes --quiet=2 --option=Dpkg::Use-Pty=0 install --no-install-recommends \
101-
"${__SYSTEM_PACKAGES_ADDITIONAL_PACKAGES[@]}"
102-
;;
103-
104-
( * )
105-
log 'error' 'Distribution unknown - installing additional packages is not supported'
106-
exit 1
107-
;;
108-
esac
109-
fi
110-
111-
return 0
112-
}
113-
114-
function install_rustup() {
115-
if ! value_is_true RUST_INSTALL; then
116-
log 'info' 'Not installing rustup'
117-
return 0
118-
fi
119-
120-
log 'info' 'Installing rustup'
121-
log 'debug' 'Setting installation environment variables'
122-
# These directories contain metadata and files required by
123-
# `rustup` (toolchain files, components, etc.) and `cargo`
124-
# (crates, etc.).
125-
export RUSTUP_HOME="${DATA_DIR}/rustup/home"
126-
export CARGO_HOME="${DATA_DIR}/cargo/home"
127-
128-
mkdir -p "${RUSTUP_HOME}" "${CARGO_HOME}"
129-
130-
# These variables are used when acquiring and updating `rustup`.
131-
export RUSTUP_DIST_SERVER
132-
export RUST_RUSTUP_UPDATE_ROOT
133-
134-
local RUSTUP_INSTALLER_ARGUMENTS=(
135-
'-y'
136-
'--no-modify-path'
137-
'--default-toolchain' "${RUST_RUSTUP_DEFAULT_TOOLCHAIN}"
138-
'--profile' "${RUST_RUSTUP_PROFILE}"
139-
)
140-
141-
if ! value_is_true RUST_RUSTUP_UPDATE_DEFAULT_TOOLCHAIN; then
142-
# do not update any existing default toolchain after install
143-
log 'trace' 'Default toolchain will not be updated'
144-
RUSTUP_INSTALLER_ARGUMENTS+=('--no-update-default-toolchain')
145-
fi
146-
147-
if [[ -z ${RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE} ]]; then
148-
RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE="$(uname -m)-unknown-linux-gnu"
149-
log 'debug' "Host triple set to '${RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE}'"
150-
fi
151-
152-
if command -v curl &>/dev/null; then
153-
DOWNLOAD_COMMAND=('curl' '--silent' '--show-error' '--location' '--fail')
154-
value_is_true DOWNLOAD_ACQUIRE_INSECURE && DOWNLOAD_COMMAND+=('--insecure')
155-
DOWNLOAD_COMMAND+=('--output' "${RUSTUP_HOME}/rustup-init")
156-
elif command -v wget &>/dev/null; then
157-
DOWNLOAD_COMMAND=('wget')
158-
value_is_true DOWNLOAD_ACQUIRE_INSECURE && DOWNLOAD_COMMAND+=('--no-check-certificate')
159-
DOWNLOAD_COMMAND+=("--output-document=${RUSTUP_HOME}/rustup-init")
160-
else
161-
log 'error' "Neither 'curl' nor 'wget' found, but required"
162-
exit 1
163-
fi
164-
165-
# This is the point where the actual installation takes place.
166-
log 'debug' "Acquiring rustup-init"
167-
"${DOWNLOAD_COMMAND[@]}" "${RUST_RUSTUP_UPDATE_ROOT}/dist/${RUST_RUSTUP_RUSTUP_INIT_HOST_TRIPLE}/rustup-init"
168-
169-
log 'debug' "Installing rustup via rustup-init"
170-
chmod +x "${RUSTUP_HOME}/rustup-init"
171-
"${RUSTUP_HOME}/rustup-init" "${RUSTUP_INSTALLER_ARGUMENTS[@]}"
172-
173-
# This commands exports a new PATH with `${CARGO_HOME}/bin` as an additional entry
174-
# shellcheck source=/dev/null
175-
source "${CARGO_HOME}/env"
176-
}
177-
178-
function additional_rust_setup() {
179-
log 'info' 'Running additional setup steps now'
180-
181-
log 'debug' 'Installing prettifier for LLDB'
182-
cp "${CURRENT_DIR}/prettifier_for_lldb.py" "${DATA_DIR}/prettifier_for_lldb.py"
183-
184-
if ! command -v rustup &>/dev/null; then
185-
log 'warn' "Command 'rustup' could not be located but is required for the mojority of the additional setup steps"
186-
return 0
187-
fi
188-
189-
if [[ ${RUST_RUSTUP_DEFAULT_TOOLCHAIN} != 'none' ]]; then
190-
log 'debug' "Setting default toolchain to '${RUST_RUSTUP_DEFAULT_TOOLCHAIN}'"
191-
rustup default "${RUST_RUSTUP_DEFAULT_TOOLCHAIN}"
192-
fi
193-
194-
if [[ -n ${RUST_RUSTUP_ADDITIONAL_TARGETS} ]]; then
195-
local __RUST_RUSTUP_ADDITIONAL_TARGETS
196-
IFS=',' read -r -a __RUST_RUSTUP_ADDITIONAL_TARGETS <<< "${RUST_RUSTUP_ADDITIONAL_TARGETS// /}"
197-
log 'debug' "Installing additional rustup targets: ${__RUST_RUSTUP_ADDITIONAL_TARGETS[*]}"
198-
rustup target add "${__RUST_RUSTUP_ADDITIONAL_TARGETS[@]}"
199-
fi
200-
201-
if [[ -n ${RUST_RUSTUP_ADDITIONAL_COMPONENTS} ]]; then
202-
local __RUST_RUSTUP_ADDITIONAL_COMPONENTS
203-
IFS=',' read -r -a __RUST_RUSTUP_ADDITIONAL_COMPONENTS <<< "${RUST_RUSTUP_ADDITIONAL_COMPONENTS// /}"
204-
log 'debug' "Adding additional rustup components: ${__RUST_RUSTUP_ADDITIONAL_COMPONENTS[*]}"
205-
rustup component add "${__RUST_RUSTUP_ADDITIONAL_COMPONENTS[@]}"
206-
fi
207-
208-
log 'debug' 'Setting up bash completion'
209-
mkdir -p /usr/share/bash-completion/completions
210-
rustup completions bash >/usr/share/bash-completion/completions/rustup
211-
rustup completions bash cargo >/usr/share/bash-completion/completions/cargo
212-
213-
log 'trace' "Adjusting permissions for '${DATA_DIR}'"
214-
chmod -R 777 "${DATA_DIR}"
215-
216-
return 0
217-
}
218-
219-
function linker_install_mold() {
220-
value_is_true LINKER_MOLD_INSTALL || return 0
221-
log 'info' "Installing linker 'mold'"
222-
223-
local MOLD_DIR
224-
MOLD_DIR="mold-${LINKER_MOLD_VERSION}-$(uname -m)-linux"
225-
226-
if command -v curl &>/dev/null; then
227-
DOWNLOAD_COMMAND=('curl' '--silent' '--show-error' '--location' '--fail')
228-
value_is_true DOWNLOAD_ACQUIRE_INSECURE && DOWNLOAD_COMMAND+=('--insecure')
229-
elif command -v wget &>/dev/null; then
230-
DOWNLOAD_COMMAND=('wget')
231-
value_is_true DOWNLOAD_ACQUIRE_INSECURE && DOWNLOAD_COMMAND+=('--no-check-certificate')
232-
else
233-
log 'error' "Neither 'curl' nor 'wget' found but required for acquiring 'mold'"
234-
exit 1
235-
fi
236-
237-
"${DOWNLOAD_COMMAND[@]}" \
238-
"https://github.com/rui314/mold/releases/download/v${LINKER_MOLD_VERSION}/${MOLD_DIR}.tar.gz" \
239-
| tar xz -C /tmp
240-
241-
cp "/tmp/${MOLD_DIR}/"{bin/{mold,ld.mold},lib/mold/mold-wrapper.so} /usr/local/bin/
242-
rm -r "/tmp/${MOLD_DIR}"
243-
244-
return 0
245-
}
246-
247-
function setup_post_start_command() {
248-
log 'info' 'Setting up postStartCommand script'
249-
250-
local SCRIPT_FILE="${DATA_DIR}/post_start_command.sh"
251-
readonly SCRIPT_FILE
252-
253-
cp "${CURRENT_DIR}/post_start_command.sh" "${SCRIPT_FILE}"
254-
sed --in-place \
255-
"s|RUST_RUSTUP_DEFAULT_TOOLCHAIN_FILE|${RUST_RUSTUP_DEFAULT_TOOLCHAIN_FILE}|g" \
256-
"${SCRIPT_FILE}"
257-
chmod +x "${SCRIPT_FILE}"
258-
}
259-
260-
function main() {
261-
parse_dev_container_options
262-
parse_linux_distribution
263-
pre_flight_checks
264-
265-
install_additional_packages
266-
install_rustup
267-
additional_rust_setup
268-
linker_install_mold
269-
270-
setup_post_start_command
271-
}
272-
273-
main "${@}"
11+
exec /bin/bash "$(dirname "${0}")/install_actual.sh" "${@}"

0 commit comments

Comments
 (0)