#!/bin/sh
################################################################
#
# Enable docker build support in container.
#
# Author: Marco Strigl
#
################################################################
#
# Copyright (c) 2017 SUSE Linux Products GmbH
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################


LOCAL_REPOS_D="/etc/repos_obs_dockersupport.d/"
LOCAL_APTREPOS_D="/etc/aptrepos_obs_dockersupport.d/"
LOCAL_APKREPOS="/etc/apkrepos_obs_dockersupport"
DATA_DIR=

sentinel="oBs-d--s--"
testmode=

setup_repos() {
    local data_url="$1"
    mkdir -p "$LOCAL_REPOS_D"
    cat >$LOCAL_REPOS_D/obs_repository.repo <<EOF
[obs_repository]
name=obs_repository
enabled=1
autorefresh=0
baseurl=$data_url
type=rpm-md
gpgcheck=0
EOF
    test -x /usr/bin/zypper && /usr/bin/zypper -D $LOCAL_REPOS_D ref
}

finish_repos() {
    rm -rf "$LOCAL_REPOS_D"
}

setup_aptrepos() {
    mkdir -p "$LOCAL_APTREPOS_D"
    local data_url="$1"
    echo "deb [trusted=yes] $data_url ./" > $LOCAL_APTREPOS_D/obssource
    test -e /var/lib/apt && mv /var/lib/apt /var/lib/apt.obssave
    test -e /usr/bin/apt-get && /usr/bin/apt-get -o Dir::Etc::SourceList=$LOCAL_APTREPOS_D/obssource -o Dir::Etc::SourceParts=$LOCAL_APTREPOS_D update
}

finish_aptrepos() {
    rm -rf "$LOCAL_APTREPOS_D"
    if test -e /var/lib/apt.obssave ; then
	rm -rf /var/lib/apt
	mv /var/lib/apt.obssave /var/lib/apt
    fi
}

setup_apkrepos() {
    echo "$data_url" > "$LOCAL_APKREPOS"
}

finish_apkrepos() {
    rm -f "$LOCAL_APKREPOS"
}

testdone() {
    local i
    test exec = "$1" && shift
    echo -n $1
    shift
    for i ; do echo -n ' "'"$i"'"' ; done
    echo
    exit 0
}


# add a -C after the ar command and replace remove "/*.repo" from
# the args
zypper_ar() {
    set -- "$@" "$sentinel"
    local o
    while test "$sentinel" != "$1" ; do
	o="$1" ; shift ; set -- "$@" $o
	test "$sentinel" = "$1" && break
	case "$o" in
        -R|--root|--installroot)
	    o="$1" ; shift ; set -- "$@" $o
	    ;;
	ar|addrepo)
	    set -- "$@" -C
	    break
	    ;;
	esac
    done
    while test "$sentinel" != "$1" ; do
	o="$1"
	shift
	set -- "$@" "${o%/*.repo}"
    done
    shift
    $testmode exec /usr/bin/zypper "$@"
}

zypper() {
    local cmd skip i
    # try to find the command
    for i ; do
	case "$skip$i" in
	-R|--root|--installroot) skip='-x' ;;
	-*) skip= ;;
	*) cmd="$i" ; break ;;
	esac
    done
    case $cmd in
    in|install|rm|remove|up|update|if|info)
	$testmode /usr/bin/zypper -D $LOCAL_REPOS_D "$@"
	setup_links_and_exit $?
	;;
    ar|addrepo)
	zypper_ar "$@"
	;;
    ref|refresh)
	echo "skipping zypper refresh"
	exit 0
	;;
    *)
	$testmode exec /usr/bin/zypper "$@"
	;;
    esac
}

obs_pkg_mgr() {
    case "$1" in
    install|remove)
	shift
	$testmode /usr/bin/zypper -D $LOCAL_REPOS_D --no-gpg-checks -n in "$@"
	setup_links_and_exit $?
	;;
    add_repo)
	shift
	$testmode exec /usr/bin/zypper ar -C "$@"
	;;
    *)
	echo "Usage: obs_pkg_mgr (install|add_repo) args" >&2
	exit 1
	;;
    esac
}

apt_get() {
    local cmd i
    # try to find the command
    for i ; do
	case "$i" in
        -*) ;;
	*) cmd="$i" ; break ;;
	esac
    done
    case $cmd in
    update)
	exit 0
	;;
    install|upgrade)
	$testmode /usr/bin/apt-get -o Dir::Etc::SourceList=$LOCAL_APTREPOS_D/obssource -o Dir::Etc::SourceParts=$LOCAL_APTREPOS_D --allow-unauthenticated "$@"
	setup_links_and_exit $?
	;;
    *)
	$testmode exec /usr/bin/apt-get "$@"
	;;
    esac
}

dnf() {
    local cmd i
    # try to find the command
    for i ; do
	case "$i" in
        -*) ;;
	*) cmd="$i" ; break ;;
	esac
    done
    case $cmd in
    in|install|up|update)
	$testmode /usr/bin/dnf --setopt=reposdir=$LOCAL_REPOS_D "$@"
	setup_links_and_exit $?
	;;
    *)
	$testmode exec /usr/bin/dnf "$@"
	;;
    esac
}

yum() {
    local cmd i
    # try to find the command
    for i ; do
	case "$i" in
        -*) ;;
	*) cmd="$i" ; break ;;
	esac
    done
    case $cmd in
    in|install|up|update)
	$testmode /usr/bin/yum --setopt=reposdir=$LOCAL_REPOS_D "$@"
	setup_links_and_exit $?
	;;
    *)
	$testmode exec /usr/bin/yum "$@"
	;;
    esac
}

apk() {
    local cmd i
    # try to find the command
    for i ; do
	case "$i" in
        -*) ;;
	*) cmd="$i" ; break ;;
	esac
    done
    case $cmd  in
    add|del)
	$testmode /sbin/apk --repositories-file ../../../../$LOCAL_APKREPOS --allow-untrusted "$@"
	setup_links_and_exit $?
	;;
    *)
	$testmode exec /sbin/apk "$@"
	;;
    esac
}

curl() {
    local o
    local coopt fname
    set -- "$@" "$sentinel"
    while test "$sentinel" != "$1" ; do
	o="$1" ; shift
	case "$o" in
	http://* | https://*)
	    fname="${o%%\?*}"
	    fname="${o##*/}"
	    urlsha256=$(echo -n "$o" | sha256sum -)
	    urlsha256="${urlsha256%% *}"
	    if test -n "$DATA_DIR" ; then
		o="file:$DATA_DIR/build-webcache/$urlsha256"
	    else
		o="localhost:80/build-webcache/$urlsha256"
	    fi
	    set -- "$@" "$o"
	    ;;
	-O)
	    coopt=true
	    ;;
	*) set -- "$@" "$o" ;;
	esac
    done
    shift
    if test -n "$coopt" -a -n "$fname" ; then
	set "$@" "-o" "$fname"
    fi
    $testmode exec /usr/bin/curl "$@"
}

wget() {
    local o
    local oopt fname
    set -- "$@" "$sentinel"
    while test "$sentinel" != "$1" ; do
	o="$1" ; shift
	case "$o" in
	http://* | https://*)
            fname="${o%%\?*}"
            fname="${o##*/}"
	    urlsha256=$(echo -n "$o" | sha256sum -)
	    urlsha256="${urlsha256%% *}"
	    if test -n "$DATA_DIR" ; then
		o="file:$DATA_DIR/build-webcache/$urlsha256"
	    else
		o="localhost:80/build-webcache/$urlsha256"
	    fi
	    set -- "$@" "$o"
	    ;;
	-O|--output-document)
	    oopt=true
	    set -- "$@" "$o"
	    ;;
	*) set -- "$@" "$o" ;;
	esac
    done
    shift
    if test -z "$oopt" -a -n "$fname" ; then
	set "$@" "-O" "$fname"
    fi
    $testmode exec /usr/bin/wget "$@"
}

upload_with_perl='
use Socket;
$/ = undef;
my $data = <STDIN>;
my ($size, $ans) = length($data);
socket(S, PF_INET, SOCK_STREAM, getprotobyname("tcp")) || die;
connect(S, sockaddr_in(80, inet_aton("127.0.0.1"))) || die("connect: $!\n");
select(S);
$| = 1;
print S "PUT $ARGV[0] HTTP/1.1\r\nContent-Length: ".length($data)."\r\n\r\n$data";
read(S, $ans, 1024);
die($ans) unless $ans =~ / 200 /;
'

upload_packages() {
    local n=$1
    local ans
    if test -x /usr/bin/rpm -o -x /bin/rpm ; then
	case $n in
	   *pkgsummaries) rpm -qa --qf '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|%{SUMMARY}\n' > /tmp/packages ;;
	   *) rpm -qa --qf '%{NAME}|%{EPOCH}|%{VERSION}|%{RELEASE}|%{ARCH}|%{DISTURL}|%{LICENSE}\n' > /tmp/packages ;;
	esac
	if test -n "$DATA_DIR" ; then
	    cp /tmp/packages "$DATA_DIR/UPLOAD/$n"
	elif test -x /usr/bin/curl ; then
	    /usr/bin/curl "http://localhost:80/$n" -T /tmp/packages > /dev/null
	elif test -x /usr/bin/perl ; then
	    /usr/bin/perl -e "$upload_with_perl" "/$n" < /tmp/packages
        else
	    (echo -n -e "PUT /$n HTTP/1.1\r\nContent-Length: $(wc -c < /tmp/packages)\r\n\r\n" | cat - /tmp/packages && read -t 600 ans ; case "$ans" in *\ 200\ *) ;; *) echo "$ans" >&2 ;; esac) <>/dev/tcp/localhost/80 1>&0
	fi
	rm -f /tmp/packages
    fi
}

setup_links() {
    test -e /usr/bin/zypper -a ! -e /usr/local/sbin/zypper && ln -s obs-docker-support /usr/local/sbin/zypper
    test -e /usr/bin/yum -a ! -e /usr/local/sbin/yum && ln -s obs-docker-support /usr/local/sbin/yum
    test -e /usr/bin/dnf -a ! -e /usr/local/sbin/dnf && ln -s obs-docker-support /usr/local/sbin/dnf
    test -e /usr/bin/apt-get -a ! -e /usr/local/sbin/apt-get && ln -s obs-docker-support /usr/local/sbin/apt-get
    test -e /sbin/apk -a ! -e /usr/local/sbin/apk && ln -s obs-docker-support /usr/local/sbin/apk
    test -e /usr/bin/curl -a ! -e /usr/local/sbin/curl && ln -s obs-docker-support /usr/local/sbin/curl
    test -e /usr/bin/wget -a ! -e /usr/local/sbin/wget && ln -s obs-docker-support /usr/local/sbin/wget
}

setup_links_and_exit() {
    setup_links
    exit $1
}

remove_links() {
    rm -f /usr/local/sbin/zypper
    rm -f /usr/local/sbin/yum
    rm -f /usr/local/sbin/dnf
    rm -f /usr/local/sbin/apt-get
    rm -f /usr/local/sbin/apk
    rm -f /usr/local/sbin/curl
    rm -f /usr/local/sbin/wget
}

obs_docker_support() {
    local do_upload_packages
    if test "x$1" = x--upload-packages ; then
	do_upload_packages=true
	shift
    fi
    case "$1" in
    --install|-i)
	data_url=http://localhost:80
	test -n "$DATA_DIR" && data_url="file:$DATA_DIR"
	setup_links
	ln -s obs-docker-support /usr/local/sbin/obs_pkg_mgr
	if test -e /usr/bin/zypper -o -e /usr/bin/yum -o -e /usr/bin/dnf ; then
	    setup_repos "$data_url"
	fi
	if test -e /usr/bin/apt-get ; then
	    setup_aptrepos "$data_url"
	fi
	if test -e /sbin/apk ; then
	    setup_apkrepos "$data_url"
	fi
	if test -n "$do_upload_packages" ; then
	    upload_packages basepackages
	fi
    ;;
    --uninstall|-u)
	remove_links
	rm -f /usr/local/sbin/obs_pkg_mgr
	finish_repos
	finish_aptrepos
	finish_apkrepos
	if test -n "$do_upload_packages" ; then
	    upload_packages packages
	    upload_packages pkgsummaries
	fi
	rm -f /usr/local/sbin/obs-docker-support
    ;;
    esac
}

prg=${0##*/}
if test "$prg" = obs-docker-support -a "x$1" = x--testmode ; then
    testmode=testdone
    prg="$2"
    shift 2
fi

if test `id -u` != 0 && test -z "$testmode" ; then
    cat <<EOF
obs-docker-support: not executed as root user!

This can happen if your base container (see FROM line) is setting USER already, then builds in dependent container run as that user/group.
EOF
    exit 1
fi

case "$prg" in
obs-docker-support)
    obs_docker_support "$@"
    ;;
obs_pkg_mgr)
    obs_pkg_mgr "$@"
    ;;
zypper)
    zypper "$@"
    ;;
apt-get)
    apt_get "$@"
    ;;
curl)
    curl "$@"
    ;;
wget)
    wget "$@"
    ;;
dnf)
    dnf "$@"
    ;;
yum)
    yum "$@"
    ;;
apk)
    apk "$@"
    ;;
*)
    echo "obs-docker-support: unsupported mode ${0##*/}" >&2
    exit 1
esac

