2022-05-10 01:16:15 +03:00
# If in automatic mode, determine if a user already exists, if not use root
detect_user( ) {
local user_variable_name = ${ 1 :- username }
local possible_users = ${ 2 :- ( "vscode" "node" "codespace" " $( awk -v val = 1000 -F ":" '$3==val{print $1}' /etc/passwd) " ) }
if [ " ${ !user_variable_name } " = "auto" ] || [ " ${ !user_variable_name } " = "automatic" ] ; then
declare -g ${ user_variable_name } = ""
2022-06-03 17:46:25 +03:00
for current_user in " ${ POSSIBLE_USERS [@] } " ; do
2022-05-10 01:16:15 +03:00
if id -u " ${ current_user } " > /dev/null 2>& 1; then
declare -g ${ user_variable_name } = " ${ current_user } "
break
fi
done
fi
if [ " ${ !user_variable_name } " = "" ] || [ " ${ !user_variable_name } " = "none" ] || ! id -u " ${ !user_variable_name } " > /dev/null 2>& 1; then
declare -g ${ user_variable_name } = root
fi
}
# Use Oryx to install something using a partial version match
oryx_install( ) {
local platform = $1
local requested_version = $2
local target_folder = ${ 3 :- none }
local ldconfig_folder = ${ 4 :- none }
echo " (*) Installing ${ platform } ${ requested_version } using Oryx... "
check_packages jq
# Soft match if full version not specified
if [ " $( echo " ${ requested_version } " | grep -o "." | wc -l) " != "2" ] ; then
local version_list = " $( oryx platforms --json | jq -r " .[] | select(.Name == \" ${ platform } \") | .Versions | sort | reverse | @tsv " | tr '\t' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' ) "
if [ " ${ requested_version } " = "latest" ] || [ " ${ requested_version } " = "current" ] || [ " ${ requested_version } " = "lts" ] ; then
requested_version = " $( echo " ${ version_list } " | head -n 1) "
else
set +e
requested_version = " $( echo " ${ version_list } " | grep -E -m 1 " ^ ${ requested_version //./ \\ . } ([\\.\\s]| $) " ) "
set -e
fi
if [ -z " ${ requested_version } " ] || ! echo " ${ version_list } " | grep " ^ ${ requested_version //./ \\ . } $" > /dev/null 2>& 1; then
echo -e " (!) Oryx does not support ${ platform } version $2 \nValid values:\n ${ version_list } " >& 2
return 1
fi
echo " (*) Using ${ requested_version } in place of $2 . "
fi
export ORYX_ENV_TYPE = vsonline-present ORYX_PREFER_USER_INSTALLED_SDKS = true ENABLE_DYNAMIC_INSTALL = true DYNAMIC_INSTALL_ROOT_DIR = /opt
oryx prep --skip-detection --platforms-and-versions " ${ platform } = ${ requested_version } "
local opt_folder = " /opt/ ${ platform } / ${ requested_version } "
if [ " ${ target_folder } " != "none" ] && [ " ${ target_folder } " != " ${ opt_folder } " ] ; then
ln -s " ${ opt_folder } " " ${ target_folder } "
fi
# Update library path add to conf
if [ " ${ ldconfig_folder } " != "none" ] ; then
echo " /opt/ ${ platform } / ${ requested_version } /lib " >> " /etc/ld.so.conf.d/ ${ platform } .conf "
ldconfig
fi
}
# Use SDKMAN to install something using a partial version match
sdk_install( ) {
local install_type = $1
local requested_version = $2
local prefix = $3
local suffix = " ${ 4 :- "\\s*" } "
local full_version_check = ${ 5 :- ".*-[a-z]+" }
if [ " ${ requested_version } " = "none" ] ; then return ; fi
# Blank will install latest stable version
if [ " ${ requested_version } " = "lts" ] || [ " ${ requested_version } " = "default" ] ; then
requested_version = ""
elif echo " ${ requested_version } " | grep -oE " ${ full_version_check } " > /dev/null 2>& 1; then
echo " ${ requested_version } "
else
local regex = " ${ prefix } \\K[0-9]+\\.[0-9]+\\.[0-9]+ ${ suffix } "
local version_list = " $( . ${ SDKMAN_DIR } /bin/sdkman-init.sh && sdk list ${ install_type } 2>& 1 | grep -oP " ${ regex } " | tr -d ' ' | sort -rV) "
if [ " ${ requested_version } " = "latest" ] || [ " ${ requested_version } " = "current" ] ; then
requested_version = " $( echo " ${ version_list } " | head -n 1) "
else
set +e
requested_version = " $( echo " ${ version_list } " | grep -E -m 1 " ^ ${ requested_version //./ \\ . } ([\\.\\s]| $) " ) "
set -e
fi
if [ -z " ${ requested_version } " ] || ! echo " ${ version_list } " | grep " ^ ${ requested_version //./ \\ . } $" > /dev/null 2>& 1; then
echo -e " Version $2 not found. Available versions:\n ${ version_list } " >& 2
exit 1
fi
fi
su ${ USERNAME } -c " umask 0002 && . ${ SDKMAN_DIR } /bin/sdkman-init.sh && sdk install ${ install_type } ${ requested_version } && sdk flush archives && sdk flush temp "
}
updaterc( ) {
if [ " ${ UPDATE_RC } " = "true" ] ; then
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
if [ [ " $( cat /etc/bash.bashrc) " != *" $1 " * ] ] ; then
echo -e " $1 " >> /etc/bash.bashrc
fi
if [ -f "/etc/zsh/zshrc" ] && [ [ " $( cat /etc/zsh/zshrc) " != *" $1 " * ] ] ; then
echo -e " $1 " >> /etc/zsh/zshrc
fi
fi
}
# Get central common setting
get_common_setting( ) {
if [ " ${ common_settings_file_loaded } " != "true" ] ; then
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
common_settings_file_loaded = true
fi
if [ -f "/tmp/vsdc-settings.env" ] ; then
local multi_line = ""
if [ " $2 " = "true" ] ; then multi_line = "-z" ; fi
local result = " $( grep ${ multi_line } -oP " $1 =\"?\K[^\"]+ " /tmp/vsdc-settings.env | tr -d '\0' ) "
if [ ! -z " ${ result } " ] ; then declare -g $1 = " ${ result } " ; fi
fi
echo " $1 = ${ !1 } "
}
# Import the specified key in a variable name passed in as
receive_gpg_keys( ) {
get_common_setting $1
local keys = ${ !1 }
get_common_setting GPG_KEY_SERVERS true
local keyring_args = ""
if [ ! -z " $2 " ] ; then
keyring_args = " --no-default-keyring --keyring $2 "
fi
# Use a temporary locaiton for gpg keys to avoid polluting image
export GNUPGHOME = "/tmp/tmp-gnupg"
mkdir -p ${ GNUPGHOME }
chmod 700 ${ GNUPGHOME }
echo -e " disable-ipv6\n ${ GPG_KEY_SERVERS } " > ${ GNUPGHOME } /dirmngr.conf
# GPG key download sometimes fails for some reason and retrying fixes it.
local retry_count = 0
local gpg_ok = "false"
set +e
until [ " ${ gpg_ok } " = "true" ] || [ " ${ retry_count } " -eq "5" ] ;
do
echo "(*) Downloading GPG key..."
( echo " ${ keys } " | xargs -n 1 gpg -q ${ keyring_args } --recv-keys) 2>& 1 && gpg_ok = "true"
if [ " ${ gpg_ok } " != "true" ] ; then
echo "(*) Failed getting key, retring in 10s..."
( ( retry_count++ ) )
sleep 10s
fi
done
set -e
if [ " ${ gpg_ok } " = "false" ] ; then
echo "(!) Failed to get gpg key."
exit 1
fi
}
# Figure out correct version of a three part version number is not passed
find_version_from_git_tags( ) {
local variable_name = $1
local requested_version = ${ !variable_name }
if [ " ${ requested_version } " = "none" ] ; then return ; fi
local repository = $2
local prefix = ${ 3 :- "tags/v" }
local separator = ${ 4 :- "." }
local last_part_optional = ${ 5 :- "false" }
if [ " $( echo " ${ requested_version } " | grep -o "." | wc -l) " != "2" ] ; then
local escaped_separator = ${ separator //./ \\ . }
local last_part
if [ " ${ last_part_optional } " = "true" ] ; then
last_part = " ( ${ escaped_separator } [0-9]+)? "
else
last_part = " ${ escaped_separator } [0-9]+ "
fi
local regex = " ${ prefix } \\K[0-9]+ ${ escaped_separator } [0-9]+ ${ last_part } $"
local version_list = " $( git ls-remote --tags ${ repository } | grep -oP " ${ regex } " | tr -d ' ' | tr " ${ separator } " "." | sort -rV) "
if [ " ${ requested_version } " = "latest" ] || [ " ${ requested_version } " = "current" ] || [ " ${ requested_version } " = "lts" ] ; then
declare -g ${ variable_name } = " $( echo " ${ version_list } " | head -n 1) "
else
set +e
declare -g ${ variable_name } = " $( echo " ${ version_list } " | grep -E -m 1 " ^ ${ requested_version //./ \\ . } ([\\.\\s]| $) " ) "
set -e
fi
fi
if [ -z " ${ !variable_name } " ] || ! echo " ${ version_list } " | grep " ^ ${ !variable_name//./ \\ . } $" > /dev/null 2>& 1; then
echo -e " Invalid ${ variable_name } value: ${ requested_version } \nValid values:\n ${ version_list } " >& 2
exit 1
fi
echo " ${ variable_name } = ${ !variable_name } "
}
# Function to run apt-get if needed
apt_get_update_if_needed( )
{
if [ ! -d "/var/lib/apt/lists" ] || [ " $( ls /var/lib/apt/lists/ | wc -l) " = "0" ] ; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Checks if packages are installed and installs them if not
check_packages( ) {
if ! dpkg -s " $@ " > /dev/null 2>& 1; then
apt_get_update_if_needed
apt-get -y install --no-install-recommends " $@ "
fi
}
# Soft version matching that resolves a version for a given package in the *current apt-cache*
# Return value is stored in first argument (the unprocessed version)
apt_cache_version_soft_match( ) {
# Version
local variable_name = " $1 "
local requested_version = ${ !variable_name }
# Package Name
local package_name = " $2 "
# Exit on no match?
local exit_on_no_match = " ${ 3 :- true } "
# Ensure we've exported useful variables
. /etc/os-release
local architecture = " $( dpkg --print-architecture) "
dot_escaped = " ${ requested_version //./ \\ . } "
dot_plus_escaped = " ${ dot_escaped //+/ \\ + } "
# Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/
version_regex = " ^(.+:)? ${ dot_plus_escaped } ([\\.\\+ ~:-]| $) "
set +e # Don't exit if finding version fails - handle gracefully
fuzzy_version = " $( apt-cache madison ${ package_name } | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 " ${ version_regex } " ) "
set -e
if [ -z " ${ fuzzy_version } " ] ; then
echo " (!) No full or partial for package \" ${ package_name } \" match found in apt-cache for \" ${ requested_version } \" on OS ${ ID } ${ VERSION_CODENAME } ( ${ architecture } ). "
if $exit_on_no_match ; then
echo "Available versions:"
apt-cache madison ${ package_name } | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+'
exit 1 # Fail entire script
else
echo "Continuing to fallback method (if available)"
return 1;
fi
fi
# Globally assign fuzzy_version to this value
# Use this value as the return value of this function
declare -g ${ variable_name } = " = ${ fuzzy_version } "
echo " ${ variable_name } = ${ !variable_name } "
}