File: /var/chroot/sbin/setup-apkrepos
#!/bin/sh
PROGRAM=setup-apkrepos
PREFIX=
: ${LIBDIR=$PREFIX/lib}
. "$LIBDIR/libalpine.sh"
: ${MIRRORS_URL:=https://mirrors.alpinelinux.org/mirrors.txt}
if [ "$ROOT" != "/" ]; then
apk_root_opt="--root $ROOT"
fi
get_hostname_from_url() {
local n="${1#*://}"
echo ${n%%/*}
}
get_mirror_count() {
set -- $MIRRORS
echo $#
}
ask_setup_method() {
local cstate="enable"
if [ -z "$community_prefix" ]; then
cstate="disable"
fi
cat <<-__EOF__
(f) Find and use fastest mirror
(s) Show mirrorlist
(r) Use random mirror
(e) Edit ${ROOT}etc/apk/repositories with text editor
(c) Community repo $cstate
(skip) Skip setting up apk repositories
__EOF__
ask "Enter mirror number or URL:" $1
printf "\n"
}
add_random_mirror() {
local i=0
local count=$(get_mirror_count)
if [ ${count:-0} -eq 0 ]; then
echo "Warning! no mirror found" >&2
return 1
fi
local random_mirror_index="$(awk -v count=$count 'BEGIN {srand(); printf("%.0f", rand() * count)}')"
printf %s "Picking random mirror..."
for mirror in $MIRRORS; do
if [ $i -eq $random_mirror_index ]; then
break
fi
i=$(( $i + 1 ))
done
add_mirror $mirror
}
time_cmd() {
local start="$(cut -d ' ' -f1 /proc/uptime)"
$@ >&2 || return
awk -v start=$start -v end=$(cut -d ' ' -f1 /proc/uptime) \
'BEGIN {print end - start; exit}'
}
find_fastest_mirror() {
local url=
local arch="$(apk --print-arch)"
for url in $MIRRORS; do
# warm up the dns cache
$MOCK nslookup $(get_hostname_from_url $url) >/dev/null 2>&1
local time="$(time_cmd wget --spider -q -T 5 -t 1 \
${url%/}/edge/main/$arch/APKINDEX.tar.gz)"
if [ -n "$time" ]; then
echo "$time $url"
fi
done | tee /dev/stderr | sort -nk1,1 | head -n1 | cut -d' ' -f2
}
add_fastest_mirror() {
echo "Finding fastest mirror... "
local fastest="$(find_fastest_mirror)"
if [ -z "$fastest" ]; then
echo "Warning! No mirror found" >&2
return 1
fi
add_mirror "$fastest"
}
# For every main/ repo, enable corresponding community/ repo
add_community_mirrors() {
for repo in $(grep '^[^#].*/main$' "$APKREPOS_PATH" 2>/dev/null); do
crepo="${repo%%/main}/community"
if ! grep -qx -- "$crepo" "$APKREPOS_PATH"; then
echo ">>> Enabling repository $crepo"
echo "$crepo" >> "$APKREPOS_PATH"
fi
done
}
# show mirrors
show_mirror_list() {
local mirror i=0
[ -z "$MIRRORS" ] && return
echo ""
echo "Available mirrors:"
for mirror in $MIRRORS; do
i=$(($i + 1))
echo "$i) $(get_hostname_from_url $mirror)"
done
echo ""
}
add_from_list() {
local mirror_index="$1"
if [ $mirror_index -lt 1 ] || [ $mirror_index -gt $(get_mirror_count) ]; then
return 1
fi
set $MIRRORS
eval "mirror=\${$mirror_index}"
add_mirror "$mirror"
}
get_alpine_release() {
# use the main version already configured, or get the version from /etc/alpine-release
local version="$(grep -Eom1 '[^/]+/main/?$' "${ROOT}"etc/apk/repositories 2>/dev/null | grep -Eo '^[^/]+' \
|| cat "${ROOT}"etc/alpine-release 2>/dev/null)"
case "$version" in
*_git*|*_alpha*) release="edge";;
[0-9]*.[0-9]*.[0-9]*)
# release in x.y.z format, cut last digit
release=v${version%.[0-9]*};;
v[0-9]*.[0-9]*)
# release in vx.y format, keep as is
release="${version}";;
*) # fallback to edge
release="edge";;
esac
}
add_mirror() {
local mirror="$1"
mkdir -p "${APKREPOS_PATH%/*}"
echo "${mirror%/}/${release}/main" >> $APKREPOS_PATH
echo "${community_prefix}${mirror%/}/${release}/community" >> $APKREPOS_PATH
echo "Added mirror $(get_hostname_from_url $mirror)"
}
add_from_url() {
mkdir -p "${APKREPOS_PATH%/*}"
echo "$1" >> $APKREPOS_PATH
echo "" >> $APKREPOS_PATH
}
edit_repositories() {
local md5="$(md5sum $APKREPOS_PATH 2>/dev/null)"
mkdir -p "${APKREPOS_PATH%/*}"
${EDITOR:-vi} "$APKREPOS_PATH"
# return true if file changed
test "$(md5sum $APKREPOS_PATH 2>/dev/null)" != "$md5"
}
usage() {
cat <<-__EOF__
usage: setup-apkrepos [-ch] [-f|-r|-1|REPO...]
setup-apkrepos -o
Setup apk repositories
options:
-c Enable the community repo
-f Detect and add fastest mirror
-h Show this help
-o Only enable a community repo for every defined repo
-r Add a random mirror and do not prompt
-1 Add first mirror on the list (normally a CDN)
Option -o cannot be used with options -c, -f, -r or -1.
__EOF__
exit $1
}
community_prefix="#"
add_fastest=false
add_first=false
add_random=false
add_community_repos=false
while getopts "c1fhor" opt; do
case $opt in
c) community_prefix=""
if $add_community_repos; then
usage "1" >&2
fi
;;
f) add_fastest=true
if $add_first || $add_random || $add_community_repos; then
usage "1" >&2
fi
;;
1) add_first=true
if $add_fastest || $add_random || $add_community_repos; then
usage "1" >&2
fi
;;
h) usage 0;;
o) add_community_repos=true
if $add_first || $add_fastest || $add_random \
|| [ $community_prefix != "#" ]; then
usage "1" >&2
fi
;;
r) add_random=true
if $add_first || $add_fastest || $add_community_repos; then
usage "1" >&2
fi
;;
'?') usage "1" >&2;;
esac
done
shift $(($OPTIND - 1))
if [ -z "$MIRRORS" ]; then
MIRRORS=$(wget -qO- $MIRRORS_URL)
fi
APKREPOS_PATH="${ROOT}"etc/apk/repositories
if [ -r "$APKREPOS_PATH" ]; then
APKREPOS=$(cat "$APKREPOS_PATH")
fi
get_alpine_release
changed=false
if [ $# -gt 0 ] && ! $add_community_repos; then
# replace the apk repos with the specified ones
rm -f "$APKREPOS_PATH"
mkdir -p "${APKREPOS_PATH%/*}"
for i; do
echo "$i" >> "$APKREPOS_PATH" && changed=true
done
fi
if $add_first; then
set -- $MIRRORS
if [ $# -eq 0 ]; then
echo "Warning! No mirror found" >&2
exit 1
fi
add_mirror "$1" || exit
changed=true
fi
if $add_random; then
add_random_mirror || exit
changed=true
fi
if $add_fastest; then
add_fastest_mirror || exit
changed=true
fi
if $add_community_repos; then
add_community_mirrors || exit
changed=true
fi
if $add_first || $add_random || $add_fastest || $add_community_repos; then
interactive=false
else
interactive=true
fi
while $interactive && ! $changed; do
if [ -z "$MIRRORS" ]; then
MIRRORS=$(wget -qO- $MIRRORS_URL)
fi
ask_setup_method ${APKREPO_DEFAULT_ANSWER:-1}
case "$resp" in
skip) break;;
[0-9]*) add_from_list $resp && changed=true;;
/*|http://*|ftp://*|https://*) add_from_url "$resp" \
&& changed=true;;
s) show_mirror_list | more;;
r|"r c") add_random_mirror && changed=true;;
f|"f c") add_fastest_mirror && changed=true;;
e) edit_repositories && changed=true;;
c) case "$community_prefix" in
"#") community_prefix=""; cstate="enabled";;
"") community_prefix="#"; cstate="disabled";;
esac
printf "Community repository %s\n\n" "$cstate"
;;
esac
case "$resp" in
*c) community_prefix=""; printf "Community repository enabled\n";;
esac
done
if $changed; then
printf %s "Updating repository indexes... "
apk update --quiet $apk_root_opt && echo "done."
fi