Skip to content

Commit 058d31c

Browse files
fix: address reviewer feedback and fix Alpine musl detection bug
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 15db101 commit 058d31c

3 files changed

Lines changed: 30 additions & 162 deletions

File tree

src/bun/install.sh

Lines changed: 26 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,14 @@ set -e
44

55
source ./library_scripts.sh
66

7-
# Helper function for consistent logging (robust for container environments)
8-
log() {
9-
local level="$1"
10-
shift
11-
local message="$*"
12-
local timestamp
13-
14-
# Try to get timestamp, fallback if date command fails
15-
if timestamp=$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null); then
16-
timestamp="[$timestamp]"
17-
else
18-
timestamp="[$(date 2>/dev/null || echo 'unknown')]"
19-
fi
20-
21-
case "$level" in
22-
INFO) echo "$timestamp INFO: $message" ;;
23-
SUCCESS) echo "$timestamp SUCCESS: $message" ;;
24-
WARNING) echo "$timestamp WARNING: $message" ;;
25-
ERROR) echo "$timestamp ERROR: $message" >&2 ;;
26-
*) echo "$timestamp $level: $message" ;;
27-
esac
28-
}
29-
30-
# Debug logging helper (enabled when BUN_FEATURE_DEBUG is set)
31-
debug_log() {
32-
if [ -n "$BUN_FEATURE_DEBUG" ]; then
33-
log INFO "$@"
34-
fi
35-
}
36-
37-
log INFO "Starting Bun installation"
7+
echo "Starting Bun installation"
388

399
# nanolayer is a cli utility which keeps container layers as small as possible
4010
# source code: https://github.com/devcontainers-extra/nanolayer
4111
# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations,
4212
# and if missing - will download a temporary copy that automatically get deleted at the end
4313
# of the script
44-
log INFO "Ensuring nanolayer is available"
14+
echo "Ensuring nanolayer is available"
4515
# Initialize variable to suppress shellcheck warning (assigned by ensure_nanolayer function)
4616
nanolayer_location=""
4717
ensure_nanolayer nanolayer_location "v0.5.6"
@@ -82,12 +52,14 @@ canonicalize_version() {
8252
fi
8353

8454
# Invalid version format
85-
log WARNING "Invalid version format: '$version'. Using 'latest' instead."
55+
echo "WARNING: Invalid version format: '$version'. Using 'latest' instead." >&2
8656
echo "latest"
8757
}
8858

59+
# shellcheck disable=SC2153
60+
# VERSION is provided by the devcontainer features framework
8961
version_for_release="$(canonicalize_version "$VERSION")"
90-
log INFO "Using Bun version: $version_for_release"
62+
echo "Using Bun version: $version_for_release"
9163

9264
# Figure out arch and libc to disambiguate Bun's multiple Linux assets
9365
detect_arch() {
@@ -111,62 +83,50 @@ detect_arch() {
11183
esac
11284
}
11385

114-
log INFO "Detecting system architecture"
86+
echo "Detecting system architecture"
11587
if ! arch_segment="$(detect_arch)"; then
116-
log ERROR "Failed to detect architecture"
88+
echo "ERROR: Failed to detect architecture" >&2
11789
exit 1
11890
fi
11991

12092
# Detect musl vs glibc (robust detection across multiple distros)
12193
detect_libc() {
12294
# Method 1: Check for apk (Alpine)
12395
if [ -x "/sbin/apk" ]; then
124-
log INFO "Detected musl libc (Alpine package manager found)" >&2
12596
echo "-musl"
12697
return 0
12798
fi
12899

129100
# Method 2: Check ldd output for musl
130101
if command -v ldd >/dev/null 2>&1; then
131102
if ldd --version 2>&1 | grep -qi musl; then
132-
log INFO "Detected musl libc (ldd output)" >&2
133103
echo "-musl"
134104
return 0
135105
fi
136106
fi
137107

138108
# Method 3: Check for musl library files
139109
if [ -f "/lib/ld-musl-x86_64.so.1" ] || [ -f "/lib/ld-musl-aarch64.so.1" ]; then
140-
log INFO "Detected musl libc (library files)" >&2
141110
echo "-musl"
142111
return 0
143112
fi
144113

145114
# Method 4: Check /proc/mounts for musl
146115
if grep -qi musl /proc/mounts 2>/dev/null; then
147-
log INFO "Detected musl libc (proc mounts)" >&2
148116
echo "-musl"
149117
return 0
150118
fi
151119

152120
# Default to glibc
153-
log INFO "Using glibc (default)" >&2
154121
echo ""
155122
}
156123

157-
log INFO "Detecting libc implementation"
124+
echo "Detecting libc implementation"
158125
if ! libc_suffix="$(detect_libc)"; then
159-
log ERROR "Failed to detect libc implementation"
126+
echo "ERROR: Failed to detect libc implementation" >&2
160127
exit 1
161128
fi
162129

163-
# Set human-readable libc name for error messages
164-
if [ "$libc_suffix" = "-musl" ]; then
165-
libc_name="musl"
166-
else
167-
libc_name="glibc"
168-
fi
169-
170130
# Build asset regex based on architecture and libc
171131
# - x64: Use baseline builds for widest CPU compatibility
172132
# - aarch64: Use non-baseline builds since baseline doesn't exist for ARM64
@@ -219,19 +179,12 @@ build_asset_patterns() {
219179
}
220180

221181
# Build asset patterns for current architecture
222-
log INFO "Building asset patterns for arch=$arch_segment, libc=${libc_suffix:-glibc}"
223182
if ! asset_patterns_output=$(build_asset_patterns "$arch_segment" "$libc_suffix"); then
224-
log ERROR "Failed to build asset patterns for arch=$arch_segment, libc_suffix=$libc_suffix"
183+
echo "ERROR: Failed to build asset patterns for arch=$arch_segment, libc_suffix=$libc_suffix" >&2
225184
exit 1
226185
fi
227186

228-
# Convert to array (with debugging)
229-
log INFO "Asset patterns built: $asset_patterns_output"
230-
231187
# Convert to array - use a more reliable method
232-
debug_log "Debug: asset_patterns_output='$asset_patterns_output'"
233-
debug_log "Debug: asset_patterns_output contains newline: $([[ "$asset_patterns_output" == *$'\n'* ]] && echo 'YES' || echo 'NO')"
234-
235188
# Split by newlines and create array
236189
asset_patterns=()
237190
while IFS= read -r line; do
@@ -240,100 +193,51 @@ while IFS= read -r line; do
240193
fi
241194
done <<< "$asset_patterns_output"
242195

243-
debug_log "Debug: asset_patterns array has ${#asset_patterns[@]} elements"
244-
for i in "${!asset_patterns[@]}"; do
245-
debug_log "Debug: asset_patterns[$i] = '${asset_patterns[$i]}'"
246-
done
247-
248196
# Verify we have asset patterns
249197
if [ ${#asset_patterns[@]} -eq 0 ]; then
250-
log ERROR "No asset patterns generated for arch=$arch_segment, libc_suffix=$libc_suffix"
251-
log ERROR "asset_patterns_output was: '$asset_patterns_output'"
198+
echo "ERROR: No asset patterns generated for arch=$arch_segment, libc_suffix=$libc_suffix" >&2
199+
echo "ERROR: asset_patterns_output was: '$asset_patterns_output'" >&2
252200
exit 1
253201
fi
254202

255203
# Try each asset pattern until one succeeds
256204
install_bun() {
257-
log INFO "install_bun function called with ${#asset_patterns[@]} asset patterns"
258-
259205
if [ ${#asset_patterns[@]} -eq 0 ]; then
260-
log ERROR "install_bun: No asset patterns provided!"
206+
echo "ERROR: install_bun: No asset patterns provided!" >&2
261207
return 1
262208
fi
263209

264210
for asset_regex in "${asset_patterns[@]}"; do
265-
log INFO "Attempting to install Bun with asset regex: $asset_regex"
266-
debug_log "Debug: asset_regex = '$asset_regex'"
267-
268-
log INFO "Running nanolayer installation command..."
269-
log INFO "Command: $nanolayer_location install devcontainer-feature ghcr.io/devcontainers-extra/features/gh-release:1"
270-
log INFO "Options: repo=oven-sh/bun, binaryNames=bun, version=$version_for_release"
271-
log INFO "Options: assetRegex=$asset_regex, releaseTagRegex=$release_tag_regex"
272-
273-
# Verify nanolayer_location is set
274-
if [ -z "$nanolayer_location" ]; then
275-
log ERROR "nanolayer_location is not set!"
276-
return 1
277-
fi
278-
279-
debug_log "Debug: nanolayer_location = '$nanolayer_location'"
280-
debug_log "Debug: nanolayer_location exists: $([ -x "$nanolayer_location" ] && echo 'YES' || echo 'NO')"
281-
282-
debug_log "Debug: About to execute nanolayer command for asset: $asset_regex"
283-
284-
if nanolayer_output=$($nanolayer_location \
211+
if $nanolayer_location \
285212
install \
286213
devcontainer-feature \
287214
"ghcr.io/devcontainers-extra/features/gh-release:1" \
288215
--option repo='oven-sh/bun' \
289216
--option binaryNames='bun' \
290217
--option version="$version_for_release" \
291218
--option assetRegex="$asset_regex" \
292-
--option releaseTagRegex="$release_tag_regex" 2>&1); then
293-
294-
log INFO "Nanolayer command succeeded"
295-
log INFO "Nanolayer output: $nanolayer_output"
296-
297-
# Check if bun binary was actually installed
298-
if [ -f "/usr/local/bin/bun" ]; then
299-
log INFO "Bun binary found at /usr/local/bin/bun"
300-
log INFO "Bun binary permissions: $(ls -la /usr/local/bin/bun)"
301-
else
302-
log ERROR "Bun binary NOT found at /usr/local/bin/bun after installation"
303-
log ERROR "Checking /usr/local/bin contents: $(ls -la /usr/local/bin/ 2>/dev/null || echo 'Directory not accessible')"
304-
305-
# Try to find where bun might have been installed
306-
log INFO "Searching for bun binary in common locations..."
307-
find /usr/local -name "*bun*" -type f 2>/dev/null || log INFO "No bun binaries found in /usr/local"
308-
fi
309-
log SUCCESS "Successfully installed Bun with asset regex: $asset_regex"
219+
--option releaseTagRegex="$release_tag_regex" 2>&1; then
310220
return 0
311-
else
312-
log WARNING "Failed to install Bun with asset regex: $asset_regex, trying next pattern..."
313-
log WARNING "Nanolayer output: $nanolayer_output"
314221
fi
315222
done
316223

317-
log ERROR "Failed to install Bun. No asset patterns matched."
318-
log ERROR "Troubleshooting information:"
319-
log ERROR "- Architecture: $arch_segment"
320-
log ERROR "- Libc: ${libc_name}"
321-
log ERROR "- Version: $version_for_release"
322-
log ERROR "- Asset patterns tried: ${asset_patterns[*]}"
323-
log ERROR "Check https://github.com/oven-sh/bun/releases for available assets"
224+
echo "ERROR: Failed to install Bun. No asset patterns matched." >&2
225+
echo "ERROR: Troubleshooting information:" >&2
226+
echo "ERROR: - Architecture: $arch_segment" >&2
227+
echo "ERROR: - Libc suffix: ${libc_suffix:-(none/glibc)}" >&2
228+
echo "ERROR: - Version: $version_for_release" >&2
229+
echo "ERROR: - Asset patterns tried: ${asset_patterns[*]}" >&2
230+
echo "ERROR: Check https://github.com/oven-sh/bun/releases for available assets" >&2
324231
return 1
325232
}
326233

327234
# Attempt installation
328-
log INFO "Starting Bun installation process..."
329-
log INFO "About to call install_bun function with ${#asset_patterns[@]} patterns"
330-
331235
if ! install_bun; then
332-
log ERROR "install_bun function failed"
236+
echo "ERROR: install_bun function failed" >&2
333237
exit 1
334238
fi
335239

336-
log INFO "Bun installation process completed"
240+
echo "Bun installation process completed"
337241

338242
# Provide a convenient bunx shim
339243
if [ -x "/usr/local/bin/bun" ] && ! [ -x "/usr/local/bin/bunx" ]; then
@@ -344,42 +248,4 @@ EOF
344248
chmod +x /usr/local/bin/bunx
345249
fi
346250

347-
log SUCCESS "Bun installation completed successfully"
348-
349-
# Verify the installation worked
350-
log INFO "Verifying Bun installation..."
351-
if [ -x "/usr/local/bin/bun" ]; then
352-
log INFO "Bun binary is executable at /usr/local/bin/bun"
353-
if bun_binary_version=$(/usr/local/bin/bun --version 2>&1); then
354-
log INFO "Bun version check successful: $bun_binary_version"
355-
else
356-
log INFO "Bun binary exists but version check failed - this may be environment-specific"
357-
log INFO "Binary info: $(file /usr/local/bin/bun 2>/dev/null || echo 'file command failed')"
358-
log INFO "Library dependencies: $(ldd /usr/local/bin/bun 2>/dev/null || echo 'ldd command failed')"
359-
360-
# Try to run with explicit library path for debugging
361-
if [ -d "/lib" ] && [ -d "/usr/lib" ]; then
362-
log INFO "Attempting to run bun with library path for debugging..."
363-
if bun_binary_version=$(LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib /usr/local/bin/bun --version 2>&1); then
364-
log INFO "Bun version check successful with LD_LIBRARY_PATH: $bun_binary_version"
365-
else
366-
log INFO "Bun version check still failed with LD_LIBRARY_PATH"
367-
fi
368-
fi
369-
fi
370-
else
371-
log ERROR "Bun binary not found or not executable at /usr/local/bin/bun"
372-
log ERROR "Checking if bun exists: $([ -f "/usr/local/bin/bun" ] && echo 'YES' || echo 'NO')"
373-
if [ -f "/usr/local/bin/bun" ]; then
374-
log ERROR "Bun file exists but is not executable. Permissions: $(ls -la /usr/local/bin/bun)"
375-
log ERROR "Attempting to make executable..."
376-
chmod +x /usr/local/bin/bun
377-
if [ -x "/usr/local/bin/bun" ]; then
378-
log INFO "Fixed: Bun binary is now executable"
379-
else
380-
log ERROR "Failed to make Bun binary executable"
381-
fi
382-
else
383-
log ERROR "Bun binary file does not exist at /usr/local/bin/bun"
384-
fi
385-
fi
251+
echo "Bun installation completed successfully"

test/bun/scenarios.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"image": "mcr.microsoft.com/devcontainers/base:debian",
2222
"features": {
2323
"bun": {
24-
"version": "1.2.20"
24+
"version": "1.3.8"
2525
}
2626
}
2727
}

test/bun/test_specific_version.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
set -e
44

5+
# shellcheck disable=SC1091
6+
# dev-container-features-test-lib is provided by the test framework at runtime
57
source dev-container-features-test-lib
68

7-
check "bun version is equal to 1.2.20" sh -c "bun --version | grep '^1.2.20'"
9+
check "bun version is equal to 1.3.8" sh -c "bun --version | grep '^1.3.8'"
810

911
reportResults

0 commit comments

Comments
 (0)