1+ #! /usr/bin/env bash
2+
3+ clean_download () {
4+ # The purpose of this function is to download a file with minimal impact on container layer size
5+ # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a
6+ # temporary manner, and making sure to
7+ # 1. uninstall the downloader at the return of the function
8+ # 2. revert back any changes to the package installer database/cache (for example apt-get lists)
9+ # The above steps will minimize the leftovers being created while installing the downloader
10+ # Supported distros:
11+ # debian/ubuntu/alpine
12+
13+ url=$1
14+ output_location=$2
15+ tempdir=$( mktemp -d)
16+ downloader_installed=" "
17+
18+ function _apt_get_install() {
19+ tempdir=$1
20+
21+ # copy current state of apt list - in order to revert back later (minimize contianer layer size)
22+ cp -p -R /var/lib/apt/lists $tempdir
23+ apt-get update -y
24+ apt-get -y install --no-install-recommends wget ca-certificates
25+ }
26+
27+ function _apt_get_cleanup() {
28+ tempdir=$1
29+
30+ echo " removing wget"
31+ apt-get -y purge wget --auto-remove
32+
33+ echo " revert back apt lists"
34+ rm -rf /var/lib/apt/lists/*
35+ rm -r /var/lib/apt/lists && mv $tempdir /lists /var/lib/apt/lists
36+ }
37+
38+ function _apk_install() {
39+ tempdir=$1
40+ # copy current state of apk cache - in order to revert back later (minimize contianer layer size)
41+ cp -p -R /var/cache/apk $tempdir
42+
43+ apk add --no-cache wget
44+ }
45+
46+ function _apk_cleanup() {
47+ tempdir=$1
48+
49+ echo " removing wget"
50+ apk del wget
51+ }
52+ # try to use either wget or curl if one of them already installer
53+ if type curl > /dev/null 2>&1 ; then
54+ downloader=curl
55+ elif type wget > /dev/null 2>&1 ; then
56+ downloader=wget
57+ else
58+ downloader=" "
59+ fi
60+
61+ # in case none of them is installed, install wget temporarly
62+ if [ -z $downloader ]; then
63+ if [ -x " /usr/bin/apt-get" ]; then
64+ _apt_get_install $tempdir
65+ elif [ -x " /sbin/apk" ]; then
66+ _apk_install $tempdir
67+ else
68+ echo " distro not supported"
69+ exit 1
70+ fi
71+ downloader=" wget"
72+ downloader_installed=" true"
73+ fi
74+
75+ if [ $downloader = " wget" ]; then
76+ wget -q $url -O $output_location
77+ else
78+ curl -sfL $url -o $output_location
79+ fi
80+
81+ # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because
82+ # alpine lack bash, and RETURN is not a valid signal under sh shell
83+ if ! [ -z $downloader_installed ]; then
84+ if [ -x " /usr/bin/apt-get" ]; then
85+ _apt_get_cleanup $tempdir
86+ elif [ -x " /sbin/apk" ]; then
87+ _apk_cleanup $tempdir
88+ else
89+ echo " distro not supported"
90+ exit 1
91+ fi
92+ fi
93+
94+ }
95+
96+ ensure_nanolayer () {
97+ # Ensure existance of the nanolayer cli program
98+ local variable_name=$1
99+
100+ local required_version=$2
101+ # normalize version
102+ if ! [[ $required_version == v* ]]; then
103+ required_version=v$required_version
104+ fi
105+
106+ local nanolayer_location=" "
107+
108+ # If possible - try to use an already installed nanolayer
109+ if [[ -z " ${NANOLAYER_FORCE_CLI_INSTALLATION} " ]]; then
110+ if [[ -z " ${NANOLAYER_CLI_LOCATION} " ]]; then
111+ if type nanolayer > /dev/null 2>&1 ; then
112+ echo " Found a pre-existing nanolayer in PATH"
113+ nanolayer_location=nanolayer
114+ fi
115+ elif [ -f " ${NANOLAYER_CLI_LOCATION} " ] && [ -x " ${NANOLAYER_CLI_LOCATION} " ]; then
116+ nanolayer_location=${NANOLAYER_CLI_LOCATION}
117+ echo " Found a pre-existing nanolayer which were given in env variable: $nanolayer_location "
118+ fi
119+
120+ # make sure its of the required version
121+ if ! [[ -z " ${nanolayer_location} " ]]; then
122+ local current_version
123+ current_version=$( $nanolayer_location --version)
124+ if ! [[ $current_version == v* ]]; then
125+ current_version=v$current_version
126+ fi
127+
128+ if ! [ $current_version == $required_version ]; then
129+ echo " skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version )"
130+ nanolayer_location=" "
131+ fi
132+ fi
133+
134+ fi
135+
136+ # If not previuse installation found, download it temporarly and delete at the end of the script
137+ if [[ -z " ${nanolayer_location} " ]]; then
138+
139+ if [ " $( uname -sm) " == " Linux x86_64" ] || [ " $( uname -sm) " == " Linux aarch64" ]; then
140+ tmp_dir=$( mktemp -d -t nanolayer-XXXXXXXXXX)
141+
142+ clean_up () {
143+ ARG=$?
144+ rm -rf $tmp_dir
145+ exit $ARG
146+ }
147+ trap clean_up EXIT
148+
149+ if [ -x " /sbin/apk" ]; then
150+ clib_type=musl
151+ else
152+ clib_type=gnu
153+ fi
154+
155+ tar_filename=nanolayer-" $( uname -m) " -unknown-linux-$clib_type .tgz
156+
157+ # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed
158+ clean_download https://github.com/devcontainers-extra/nanolayer/releases/download/$required_version /$tar_filename $tmp_dir /$tar_filename
159+
160+ tar xfzv $tmp_dir /$tar_filename -C " $tmp_dir "
161+ chmod a+x $tmp_dir /nanolayer
162+ nanolayer_location=$tmp_dir /nanolayer
163+
164+ else
165+ echo " No binaries compiled for non-x86-linux architectures yet: $( uname -m) "
166+ exit 1
167+ fi
168+ fi
169+
170+ # Expose outside the resolved location
171+ declare -g ${variable_name} =$nanolayer_location
172+
173+ }
0 commit comments