2222# Unless the --disable-confirmation flag is set, this script will allow the runner to
2323# configure either of those two directory paths.
2424#
25+ # Unless the --no-install-system-deps flag is set, this script will attempt to install Swift's
26+ # system dependencies using the system package manager.
27+ #
2528# curl is required to run this script.
2629
2730set -o errexit
@@ -48,6 +51,47 @@ read_input_with_default () {
4851 fi
4952}
5053
54+ yn_prompt () {
55+ if [[ " $1 " == " true" ]]; then
56+ echo " (Y/n)"
57+ else
58+ echo " (y/N)"
59+ fi
60+ }
61+
62+ # Read a y/n input.
63+ # First argument is the default value (must be "true" or "false").
64+ #
65+ # Sets READ_INPUT_RETURN to "true" for an input of "y" or "Y", "false" for an input
66+ # of "n" or "N", or the default value for a blank input
67+ #
68+ # For all other inputs, a message is printed and the user is prompted again.
69+ read_yn_input () {
70+ while [[ true ]]; do
71+ read_input_with_default " $1 "
72+
73+ case " $READ_INPUT_RETURN " in
74+ " y" | " Y" )
75+ READ_INPUT_RETURN=" true"
76+ return
77+ ;;
78+
79+ " n" | " N" )
80+ READ_INPUT_RETURN=" false"
81+ return
82+ ;;
83+
84+ " $1 " )
85+ return
86+ ;;
87+
88+ * )
89+ echo " Please input either \" y\" or \" n\" , or press ENTER to use the default."
90+ ;;
91+ esac
92+ done
93+ }
94+
5195# Replaces the actual path to $HOME at the beginning of the provided string argument with
5296# the string "$HOME". This is used when printing to stdout.
5397# e.g. "home/user/.local/bin" => "$HOME/.local/bin"
@@ -71,9 +115,68 @@ bold () {
71115 echo " $( tput bold) $1 $( tput sgr0) "
72116}
73117
118+ # Fetch the list of required system dependencies from the apple/swift-docker
119+ # repository and attempt to install them using the system's package manager.
120+ #
121+ # $docker_platform_name, $docker_platform_version, and $package manager need
122+ # to be set before calling this function.
123+ install_system_deps () {
124+ if [[ " $( id --user) " != " 0" ]] && ! has_command sudo ; then
125+ echo " Warning: sudo not installed and current user is not root, skipping system dependency installation."
126+ return
127+ elif ! has_command " $package_manager " ; then
128+ echo " Warning: package manager \" $package_manager \" not found, skipping system dependency installation."
129+ return
130+ fi
131+
132+ dockerfile_url=" https://raw.githubusercontent.com/apple/swift-docker/main/nightly-main/$docker_platform_name /$docker_platform_version /Dockerfile"
133+ dockerfile=" $( curl --silent --retry 3 --location --fail $dockerfile_url ) "
134+ if [[ " $? " -ne 0 ]]; then
135+ echo " Error enumerating system dependencies, skipping installation of system dependencies."
136+ fi
137+
138+ # Find the line number of the RUN command associated with installing system dependencies.
139+ beg_line_num=$( printf " $dockerfile " | grep -n --max-count=1 " $package_manager .*install" | cut -d " :" -f1)
140+
141+ # Starting from there, find the first line that starts with an & or doesn't end in a backslash.
142+ relative_end_line_num=$( printf " $dockerfile " |
143+ tail --lines=+" $(( beg_line_num + 1 )) " |
144+ grep -n --max-count=1 --invert-match ' [[:space:]]*[^&].*\\$' | cut -d " :" -f1)
145+ end_line_num=$(( beg_line_num + relative_end_line_num))
146+
147+ # Read the lines between those two, deleting any spaces and backslashes.
148+ readarray -t package_list < <( printf " $dockerfile " | sed -n " $(( beg_line_num + 1 )) ,${end_line_num} p" | sed -r ' s/[\ ]//g' )
149+
150+ # If the installation command from the Dockerfile included some cleanup as part of a second command, drop that.
151+ if [[ " ${package_list[-1]} " =~ ^\&\& ]]; then
152+ unset ' package_list[-1]'
153+ fi
154+
155+ install_args=(--quiet)
156+ if [[ " $DISABLE_CONFIRMATION " == " true" ]]; then
157+ install_args+=(-y)
158+ fi
159+
160+ # Disable errexit since failing to install system dependencies is not swiftly installation-fatal.
161+ set +o errexit
162+ if [[ " $( id --user) " == " 0" ]]; then
163+ " $package_manager " install " ${install_args[@]} " " ${package_list[@]} "
164+ else
165+ sudo " $package_manager " install " ${install_args[@]} " " ${package_list[@]} "
166+ fi
167+ if [[ " $? " -ne 0 ]]; then
168+ echo " System dependency installation failed."
169+ if [[ " $package_manager " == " apt-get" ]]; then
170+ echo " You may need to run apt-get update before installing system dependencies."
171+ fi
172+ fi
173+ set -o errexit
174+ }
175+
74176SWIFTLY_INSTALL_VERSION=" 0.1.0"
75177
76178MODIFY_PROFILE=" true"
179+ SWIFTLY_INSTALL_SYSTEM_DEPS=" true"
77180
78181for arg in " $@ " ; do
79182 case " $arg " in
@@ -89,6 +192,7 @@ FLAGS:
89192 -y, --disable-confirmation Disable confirmation prompt.
90193 --no-modify-profile Do not attempt to modify the profile file to set environment
91194 variables (e.g. PATH) on login.
195+ --no-install-system-deps Do not attempt to install Swift's required system dependencies.
92196 -h, --help Prints help information.
93197 --version Prints version information.
94198EOF
103207 MODIFY_PROFILE=" false"
104208 ;;
105209
210+ " --no-install-system-deps" )
211+ SWIFTLY_INSTALL_SYSTEM_DEPS=" false"
212+ ;;
213+
106214 " --version" )
107215 echo " $SWIFTLY_INSTALL_VERSION "
108216 exit 0
@@ -134,23 +242,31 @@ case "$ID" in
134242 fi
135243 PLATFORM_NAME=" amazonlinux2"
136244 PLATFORM_NAME_FULL=" amazonlinux2"
245+ docker_platform_name=" amazonlinux"
246+ docker_platform_version=" 2"
247+ package_manager=" yum"
137248 ;;
138249
139250 " ubuntu" )
251+ docker_platform_name=" ubuntu"
252+ package_manager=" apt-get"
140253 case " $UBUNTU_CODENAME " in
141254 " jammy" )
142255 PLATFORM_NAME=" ubuntu2204"
143256 PLATFORM_NAME_FULL=" ubuntu22.04"
257+ docker_platform_version=" 22.04"
144258 ;;
145259
146260 " focal" )
147261 PLATFORM_NAME=" ubuntu2004"
148262 PLATFORM_NAME_FULL=" ubuntu20.04"
263+ docker_platform_version=" 20.04"
149264 ;;
150265
151266 " bionic" )
152267 PLATFORM_NAME=" ubuntu1804"
153268 PLATFORM_NAME_FULL=" ubuntu18.04"
269+ docker_platform_version=" 18.04"
154270 ;;
155271
156272 * )
@@ -167,6 +283,9 @@ case "$ID" in
167283 fi
168284 PLATFORM_NAME=" ubi9"
169285 PLATFORM_NAME_FULL=" ubi9"
286+ docker_platform_name=" rhel-ubi"
287+ docker_platform_version=" 9"
288+ package_manager=" yum"
170289 ;;
171290
172291 * )
@@ -243,6 +362,7 @@ while [ -z "$DISABLE_CONFIRMATION" ]; do
243362 printf " %40s: $( bold $( replace_home_path $HOME_DIR ) ) \n" " Data and configuration files directory"
244363 printf " %40s: $( bold $( replace_home_path $BIN_DIR ) ) \n" " Executables installation directory"
245364 printf " %40s: $( bold $MODIFY_PROFILE ) \n" " Modify login config ($( replace_home_path $PROFILE_FILE ) )"
365+ printf " %40s: $( bold $SWIFTLY_INSTALL_SYSTEM_DEPS ) \n" " Install system dependencies"
246366 echo " "
247367 echo " Select one of the following:"
248368 echo " 1) Proceed with the installation (default)"
@@ -265,30 +385,17 @@ while [ -z "$DISABLE_CONFIRMATION" ]; do
265385 read_input_with_default " $BIN_DIR "
266386 BIN_DIR=" $( expand_home_path $READ_INPUT_RETURN ) "
267387
268- if [[ " $MODIFY_PROFILE " == " true" ]]; then
269- MODIFY_PROFILE_PROMPT=" (Y/n)"
270- else
271- MODIFY_PROFILE_PROMPT=" (y/N)"
272- fi
273- echo " Modify login config ($( replace_home_path $PROFILE_FILE ) )? $MODIFY_PROFILE_PROMPT "
274- read_input_with_default " $MODIFY_PROFILE "
275-
276- case " $READ_INPUT_RETURN " in
277- " y" | " Y" )
278- MODIFY_PROFILE=" true"
279- ;;
280-
281- " n" | " N" )
282- MODIFY_PROFILE=" false"
283- ;;
388+ echo " Modify login config ($( replace_home_path $PROFILE_FILE ) )? $( yn_prompt $MODIFY_PROFILE ) "
389+ read_yn_input " $MODIFY_PROFILE "
390+ MODIFY_PROFILE=" $READ_INPUT_RETURN "
284391
285- * )
286- ;;
287- esac
392+ echo " Install system dependencies? $( yn_prompt $SWIFTLY_INSTALL_SYSTEM_DEPS ) "
393+ read_yn_input " $SWIFTLY_INSTALL_SYSTEM_DEPS "
394+ SWIFTLY_INSTALL_SYSTEM_DEPS= " $READ_INPUT_RETURN "
288395 ;;
289396
290397 * )
291- echo " Cancelling installation"
398+ echo " Cancelling installation. "
292399 exit 0
293400 ;;
294401 esac
@@ -300,23 +407,11 @@ if [[ -d "$HOME_DIR" ]]; then
300407 else
301408 echo " Existing swiftly installation detected at $( replace_home_path $HOME_DIR ) , overwrite? (Y/n)"
302409
303- while [[ true ]]; do
304- read_input_with_default " y"
305- case " $READ_INPUT_RETURN " in
306- " y" | " Y" )
307- break
308- ;;
309-
310- " n" | " N" | " q" )
311- echo " Cancelling installation"
312- exit 0
313- ;;
314-
315- * )
316- echo " Please input \" y\" or \" n\" ."
317- ;;
318- esac
319- done
410+ read_yn_input " true"
411+ if [[ " $READ_INPUT_RETURN " == " false" ]]; then
412+ echo " Cancelling installation."
413+ exit 0
414+ fi
320415 fi
321416
322417 rm -r $HOME_DIR
@@ -343,10 +438,6 @@ echo "$JSON_OUT" > "$HOME_DIR/config.json"
343438# Verify the downloaded executable works. The script will exit if this fails due to errexit.
344439SWIFTLY_HOME_DIR=" $HOME_DIR " SWIFTLY_BIN_DIR=" $BIN_DIR " " $BIN_DIR /swiftly" --version > /dev/null
345440
346- echo " "
347- echo " swiftly has been succesfully installed!"
348- echo " "
349-
350441ENV_OUT=$( cat << EOF
351442export SWIFTLY_HOME_DIR="$( replace_home_path $HOME_DIR ) "
352443export SWIFTLY_BIN_DIR="$( replace_home_path $BIN_DIR ) "
@@ -367,6 +458,16 @@ if [[ "$MODIFY_PROFILE" == "true" ]]; then
367458 fi
368459fi
369460
461+ if [[ " $SWIFTLY_INSTALL_SYSTEM_DEPS " != " false" ]]; then
462+ echo " "
463+ echo " Installing Swift's system dependencies via $package_manager (note: this may require root access)..."
464+ install_system_deps
465+ fi
466+
467+ echo " "
468+ echo " swiftly has been succesfully installed!"
469+ echo " "
470+
370471if ! has_command " swiftly" || [[ " $HOME_DIR " != " $DEFAULT_HOME_DIR " || " $BIN_DIR " != " $DEFAULT_BIN_DIR " ]] ; then
371472 echo " Once you log in again, swiftly should be accessible from your PATH."
372473 echo " To begin using swiftly from your current shell, first run the following command:"
0 commit comments