Skip to content

Commit 67e27ee

Browse files
Copilotabdurriq
andcommitted
Deploy common-setup.sh to each feature's _lib directory
The devcontainer CLI packages each feature independently and doesn't include parent directories or hidden directories in the build context. The helper script must be copied into each feature's _lib/ directory to be accessible at runtime. Co-authored-by: abdurriq <[email protected]>
1 parent 33e2e26 commit 67e27ee

37 files changed

Lines changed: 1442 additions & 141 deletions

src/.common/README.md

Lines changed: 0 additions & 122 deletions
This file was deleted.

src/anaconda/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ chmod +x /etc/profile.d/00-restore-env.sh
8383

8484
# Source common helper functions
8585
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
86-
source "${SCRIPT_DIR}/../.common/common-setup.sh"
86+
source "${SCRIPT_DIR}/_lib/common-setup.sh"
8787

8888
# Determine the appropriate non-root user
8989
USERNAME=$(determine_user_from_input "${USERNAME}" "root")
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
#-------------------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information.
5+
#-------------------------------------------------------------------------------------------------------------------------
6+
#
7+
# Helper script for common feature setup tasks, including user selection logic.
8+
# Maintainer: The Dev Container spec maintainers
9+
10+
# Determine the appropriate non-root user
11+
# Usage: determine_user_from_input USERNAME [FALLBACK_USER]
12+
#
13+
# This function resolves the USERNAME variable based on the input value:
14+
# - If USERNAME is "auto" or "automatic", it will detect an existing non-root user
15+
# - If USERNAME is "none" or doesn't exist, it will fall back to root
16+
# - Otherwise, it validates the specified USERNAME exists
17+
#
18+
# Arguments:
19+
# USERNAME - The username input (typically from feature configuration)
20+
# FALLBACK_USER - Optional fallback user when no user is found in automatic mode (defaults to "root")
21+
#
22+
# Returns:
23+
# The resolved username is printed to stdout
24+
#
25+
# Examples:
26+
# USERNAME=$(determine_user_from_input "automatic")
27+
# USERNAME=$(determine_user_from_input "vscode")
28+
# USERNAME=$(determine_user_from_input "auto" "vscode")
29+
#
30+
determine_user_from_input() {
31+
local input_username="${1:-automatic}"
32+
local fallback_user="${2:-root}"
33+
local resolved_username=""
34+
35+
if [ "${input_username}" = "auto" ] || [ "${input_username}" = "automatic" ]; then
36+
# Automatic mode: try to detect an existing non-root user
37+
38+
# First, check if _REMOTE_USER is set and is not root
39+
if [ -n "${_REMOTE_USER:-}" ] && [ "${_REMOTE_USER}" != "root" ]; then
40+
# Verify the user exists before using it
41+
if id -u "${_REMOTE_USER}" > /dev/null 2>&1; then
42+
resolved_username="${_REMOTE_USER}"
43+
else
44+
# _REMOTE_USER doesn't exist, fall through to normal detection
45+
resolved_username=""
46+
fi
47+
fi
48+
49+
# If we didn't resolve via _REMOTE_USER, try to find a non-root user
50+
if [ -z "${resolved_username}" ]; then
51+
# Try to find a non-root user from a list of common usernames
52+
# The list includes: devcontainer, vscode, node, codespace, and the user with UID 1000
53+
local possible_users=("devcontainer" "vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd 2>/dev/null || echo '')")
54+
55+
for current_user in "${possible_users[@]}"; do
56+
# Skip empty entries
57+
if [ -z "${current_user}" ]; then
58+
continue
59+
fi
60+
61+
# Check if user exists
62+
if id -u "${current_user}" > /dev/null 2>&1; then
63+
resolved_username="${current_user}"
64+
break
65+
fi
66+
done
67+
68+
# If no user found, use the fallback
69+
if [ -z "${resolved_username}" ]; then
70+
resolved_username="${fallback_user}"
71+
fi
72+
fi
73+
elif [ "${input_username}" = "none" ]; then
74+
# Explicit "none" means use root
75+
resolved_username="root"
76+
else
77+
# Specific username provided - validate it exists
78+
if id -u "${input_username}" > /dev/null 2>&1; then
79+
resolved_username="${input_username}"
80+
else
81+
# User doesn't exist, fall back to root
82+
resolved_username="root"
83+
fi
84+
fi
85+
86+
echo "${resolved_username}"
87+
}

src/common-utils/main.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ esac
393393

394394
# Source common helper functions
395395
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
396-
source "${SCRIPT_DIR}/../.common/common-setup.sh"
396+
source "${SCRIPT_DIR}/_lib/common-setup.sh"
397397

398398
# Handle the special "none" case for common-utils before user determination
399399
# The "none" case sets USER_UID and USER_GID to 0

src/conda/_lib/common-setup.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
#-------------------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information.
5+
#-------------------------------------------------------------------------------------------------------------------------
6+
#
7+
# Helper script for common feature setup tasks, including user selection logic.
8+
# Maintainer: The Dev Container spec maintainers
9+
10+
# Determine the appropriate non-root user
11+
# Usage: determine_user_from_input USERNAME [FALLBACK_USER]
12+
#
13+
# This function resolves the USERNAME variable based on the input value:
14+
# - If USERNAME is "auto" or "automatic", it will detect an existing non-root user
15+
# - If USERNAME is "none" or doesn't exist, it will fall back to root
16+
# - Otherwise, it validates the specified USERNAME exists
17+
#
18+
# Arguments:
19+
# USERNAME - The username input (typically from feature configuration)
20+
# FALLBACK_USER - Optional fallback user when no user is found in automatic mode (defaults to "root")
21+
#
22+
# Returns:
23+
# The resolved username is printed to stdout
24+
#
25+
# Examples:
26+
# USERNAME=$(determine_user_from_input "automatic")
27+
# USERNAME=$(determine_user_from_input "vscode")
28+
# USERNAME=$(determine_user_from_input "auto" "vscode")
29+
#
30+
determine_user_from_input() {
31+
local input_username="${1:-automatic}"
32+
local fallback_user="${2:-root}"
33+
local resolved_username=""
34+
35+
if [ "${input_username}" = "auto" ] || [ "${input_username}" = "automatic" ]; then
36+
# Automatic mode: try to detect an existing non-root user
37+
38+
# First, check if _REMOTE_USER is set and is not root
39+
if [ -n "${_REMOTE_USER:-}" ] && [ "${_REMOTE_USER}" != "root" ]; then
40+
# Verify the user exists before using it
41+
if id -u "${_REMOTE_USER}" > /dev/null 2>&1; then
42+
resolved_username="${_REMOTE_USER}"
43+
else
44+
# _REMOTE_USER doesn't exist, fall through to normal detection
45+
resolved_username=""
46+
fi
47+
fi
48+
49+
# If we didn't resolve via _REMOTE_USER, try to find a non-root user
50+
if [ -z "${resolved_username}" ]; then
51+
# Try to find a non-root user from a list of common usernames
52+
# The list includes: devcontainer, vscode, node, codespace, and the user with UID 1000
53+
local possible_users=("devcontainer" "vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd 2>/dev/null || echo '')")
54+
55+
for current_user in "${possible_users[@]}"; do
56+
# Skip empty entries
57+
if [ -z "${current_user}" ]; then
58+
continue
59+
fi
60+
61+
# Check if user exists
62+
if id -u "${current_user}" > /dev/null 2>&1; then
63+
resolved_username="${current_user}"
64+
break
65+
fi
66+
done
67+
68+
# If no user found, use the fallback
69+
if [ -z "${resolved_username}" ]; then
70+
resolved_username="${fallback_user}"
71+
fi
72+
fi
73+
elif [ "${input_username}" = "none" ]; then
74+
# Explicit "none" means use root
75+
resolved_username="root"
76+
else
77+
# Specific username provided - validate it exists
78+
if id -u "${input_username}" > /dev/null 2>&1; then
79+
resolved_username="${input_username}"
80+
else
81+
# User doesn't exist, fall back to root
82+
resolved_username="root"
83+
fi
84+
fi
85+
86+
echo "${resolved_username}"
87+
}

src/conda/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ chmod +x /etc/profile.d/00-restore-env.sh
2929

3030
# Source common helper functions
3131
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
32-
source "${SCRIPT_DIR}/../.common/common-setup.sh"
32+
source "${SCRIPT_DIR}/_lib/common-setup.sh"
3333

3434
# Determine the appropriate non-root user
3535
USERNAME=$(determine_user_from_input "${USERNAME}" "root")

0 commit comments

Comments
 (0)