#!/usr/bin/env zsh
# Copyright (c) 2016-2017 Dyne.org Foundation
# libdevuansdk is maintained by Ivan J. <parazyd@dyne.org>
#
# This file is part of libdevuansdk
#
# This source code is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software 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 source code. If not, see <http://www.gnu.org/licenses/>.

## helper functions that make my life easier

vars+=(loopdevice)

build_image_dist() {
	fn build_image_dist
	req=(arch size parted_type)
	if [[ $parted_type = gpt ]]; then
		req+=(gpt_boot gpt_root)
	elif [[ $parted_type = dos ]]; then
		req+=(parted_root parted_boot)
	fi
	req+=(workdir strapdir image_name)
	ckreq || return 1

	notice "building complete dist image"
	act "$image_name"

	bootstrap_complete_base            || { zerr; wrapup }
	blend_preinst                      || { zerr; wrapup }
	image_prepare_raw                  || { zerr; wrapup }
	image_partition_raw_${parted_type} || { zerr; wrapup }
	build_kernel_${arch}               || { zerr; wrapup }
	blend_postinst                     || { zerr; wrapup }
	rsync_to_raw_image                 || { zerr; wrapup }
	image_pack_dist                    || { zerr; wrapup }
}

build_iso_dist() {
	fn build_iso_dist
	req=(workdir strapdir os arch)
	ckreq || return 1

	notice "building complete iso image"

	bootstrap_complete_base     || { zerr; wrapup }
	bootstrap_thirdstage        || { zerr; wrapup }
	build_kernel_${arch}        || { zerr; wrapup }
	iso_prepare_strap           || { zerr; wrapup }
	install-custdebs            || { zerr; wrapup }
	blend_preinst               || { zerr; wrapup }
	blend_postinst              || { zerr; wrapup }
	fill_apt_cache              || { zerr; wrapup }
	iso_setup_isolinux          || { zerr; wrapup }
	iso_write_isolinux_cfg      || { zerr; wrapup }
	di_disk_info                || { zerr; wrapup }
	di_debmirror                || { zerr; wrapup }
	di_localudebs               || { zerr; wrapup }
	di_banudebs                 || { zerr; wrapup }
	di_reprepro                 || { zerr; wrapup }
	di_debian_installer         || { zerr; wrapup }
	iso_squash_strap            || { zerr; wrapup }
	iso_xorriso_build           || { zerr; wrapup }
}

build_vagrant_dist() {
	fn build_vagrant_dist
	req=(workdir strapdir os arch imageformat)
	ckreq || return 1

	notice "building complete vagrant image"

	image_${imageformat}_as_strapdir   || { zerr; wrapup }
	bootstrap_complete_base            || { zerr; wrapup }
	vm_inject_overrides                || { zerr; wrapup }
	blend_preinst                      || { zerr; wrapup }
	vm_setup_grub                      || { zerr; wrapup }
	blend_postinst                     || { zerr; wrapup }
	vm_umount_${imageformat}           || { zerr; wrapup }
	vm_vbox_setup                      || { zerr; wrapup }
	vm_vagrant_package                 || { zerr; wrapup }
	vm_init_cloud                      || { zerr; wrapup }
	vm_pack_dist                       || { zerr; wrapup }
}

getfield() {
	fn getfield $*
	print "$1" | \
		grep "^$2=" | \
		sed -e 's:.*=\(.*\)$:\1:g' | \
		sed -e 's:^"\(.*\)"$:\1:g'
}

add-user() {
	fn add-user $* | sudo tee $strapdir/thirdstage >/dev/null
	local user="$1"
	local pass="$2"
	req=(strapdir user pass)
	ckreq || return 1

	notice "adding user $user:$pass"

	cat <<EOF | sudo tee ${strapdir}/adduser
#!/bin/sh
useradd -m ${user}
echo "${user}:${pass}" | chpasswd
EOF
	chroot-script adduser || zerr
}

devprocsys() {
	fn devprocsys "$@"
	local watdo="$1"
	local werdo="$2"
	req=(watdo werdo)
	ckreq || return 1

	if [[ $watdo = mount ]]; then
		sudo mount -o bind /sys     $werdo/sys     && act "mounted sys"    && \
		sudo mount -t proc proc     $werdo/proc    && act "mounted proc"   && \
		sudo mount -o bind /dev     $werdo/dev     && act "mounted dev"    && \
		sudo mount -o bind /dev/pts $werdo/dev/pts && act "mounted devpts" && \
		return 0
	elif [[ $watdo = umount ]]; then
		sudo umount -l $werdo/dev/pts  && act "umounted devpts" && sleep 1
		sudo umount -l $werdo/dev      && act "umounted dev"    && sleep 1
		sudo umount -l $werdo/proc     && act "umounted proc"   && sleep 1
		sudo umount -l $werdo/sys      && act "umounted sys"    && sleep 1
		return 0
	fi
	return 1
}

wrapup() {
	# a hopefully clean exit
	fn wrapup
	req=(strapdir)
	ckreq || {
		die "something is very wrong" | sudo tee $strapdir/thirdstage >/dev/null
		die "cleanup yourself, sorry"
		exit 1
	}

	devprocsys umount $strapdir
	exit 1
}

findloopdev() {
	fn findloopdev
	req=(workdir image_name)
	ckreq || return 1

	notice "finding a free loopdevice"

	loopdevice=$(sudo losetup -f --show $workdir/${image_name}.img)
	sudo partx -av $loopdevice || zerr

	func "loopdevice: $loopdevice"
	silly sleep 2
}

findfreenbd() {
	fn findfreenbd

	notice "looking for a free /dev/nbd"

	for i in $(seq 0 8); do
		grep "^/dev/nbd${i}" /proc/mounts >/dev/null || {
			print "/dev/nbd${i}"
			break
		}
	done
}

qemu_install_user() {
	fn qemu_install_user
	req=(arch strapdir)
	ckreq || return 1

	[[ "$(uname -m)" =~ "arm" ]]   && return
	[[ "$(uname -m)" =~ "aarch" ]] && return

	notice "installing qemu-user-static"
	case "$arch" in
		armel)
			sudo cp -a "$armel_qemu_bin" "$strapdir/usr/bin"
			;;
		armhf)
			sudo cp -a "$armhf_qemu_bin" "$strapdir/usr/bin"
			;;
		arm64)
			sudo cp -a "$arm64_qemu_bin" "$strapdir/usr/bin"
			;;
	esac
} | sudo tee $strapdir/thirdstage >/dev/null

dpkgdivert() {
	fn dpkgdivert "$@"
	req=(watdo werdo)
	local watdo="$1"
	local werdo="$2"
	ckreq || return 1

	if [[ $watdo = on ]]; then
		cat <<EOF | sudo tee ${werdo}/dpkgdivert >/dev/null
#!/bin/sh
dpkg-divert --add --local \
	--divert /usr/sbin/invoke-rc.d.chroot \
	--rename /usr/sbin/invoke-rc.d
cp /bin/true /usr/sbin/invoke-rc.d
echo -e "#!/bin/sh\nexit 101" > /usr/sbin/policy-rc.d
chmod +x /usr/sbin/policy-rc.d
EOF
	elif [[ $watdo = off ]]; then
		cat <<EOF | sudo tee ${werdo}/dpkgdivert >/dev/null
#!/bin/sh
rm -f /usr/sbin/policy-rc.d
rm -f /usr/sbin/invoke-rc.d
dpkg-divert --remove --rename /usr/sbin/invoke-rc.d
EOF
	fi
	
	chroot-script dpkgdivert  || { zerr; wrapup }
}

enableserv() {
	fn enableserv "$@"
	local service="$1"
	req=(service strapdir)
	ckreq || return 1

	cat <<EOF | sudo tee -a ${strapdir}/enserv >/dev/null
#!/bin/sh
update-rc.d ${service} enable
EOF

	notice "enabling $service service"
	chroot-script enserv
}

disableserv() {
	fn disableserv "$@"
	local service="$1"
	req=(service strapdir)
	ckreq || return 1

	cat <<EOF | sudo tee -a ${strapdir}/disserv >/dev/null
#!/bin/sh
update-rc.d ${service} disable
EOF | sudo tee $strapdir/thirdstage >/dev/null

	notice "disabling $service service"
	chroot-script disserv  || { zerr; wrapup }
}

prepare_strap() {
	fn prepare_strap
	req=(strapdir)
	ckreq || return 1

	notice "preparing strapdir for livecd"

	cat <<EOF | sudo tee ${strapdir}/isoprep >/dev/null
#!/bin/sh
apt-get update
apt-get --yes --force-yes install dialog live-boot live-boot-initramfs-tools live-tools live-config live-config-sysvinit
##apt-get --yes --force-yes autoremove
EOF

	chroot-script -d isoprep  || { zerr; wrapup }
}

install-custdebs() {
	fn install-custdebs
	req=(R strapdir blendlib custom_deb_packages)
	ckreq || return 1

	mkdir -p $strapdir/tmp/debs
	find $custom_deb_packages -type f -name "*_${arch}.deb" -exec cp {} $strapdir/tmp/debs \;
	find $custom_deb_packages -type f -name "*_all.deb"     -exec cp {} $strapdir/tmp/debs \;

	cat <<EOF | sudo tee ${strapdir}/install-debs >/dev/null
#!/bin/sh
cd /debs
yes | find /tmp/debs -type f -name "*.deb" -exec dpkg --force-depends -i {} \+
yes | apt-get -f install
cd /
##apt-get --yes --force-yes autoremove
##rm -rf /tmp/debs
EOF
	chroot-script -d install-debs  || { zerr; wrapup }
}

chroot-script() {
	fn chroot-script "$@"
	req=(strapdir)
	ckreq || return 1

	mkdir -p "$R/log"

	case "x$1" in
		x-d)
			local script="$2"
			devprocsys mount "$strapdir" || zerr
			dpkgdivert on "$strapdir"    || zerr
			[[ "$APT_CACHE" = 1 ]] && { aptcache on "$strapdir/mnt"  || zerr }

			## logging
			sudo sed -i "$strapdir/$script" \
				-e 's@#!/bin/sh@#!/bin/sh\'$'\nset -x ; exec 2>/'$script'.log ; export DEBIAN_FRONTEND=noninteractive@'

			notice "chrooting to execute $script..."
			sudo chmod +x  "$strapdir/$script"    || zerr
			sudo chroot "$strapdir" "/$script" || zerr
			sudo mv -f "$strapdir/${script}.log" "$R/log/"

			[[ "$APT_CACHE" = 1 ]] && { aptcache off "$strapdir/mnt" || zerr }
			dpkgdivert off "$strapdir"    || zerr
			devprocsys umount "$strapdir" || zerr
			;;
		*)
			local script="$1"
			[[ "$APT_CACHE" = 1 ]] && { aptcache on "$strapdir/mnt"  || zerr }

			## logging
			sudo sed -i "$strapdir/$script" \
				-e 's@#!/bin/sh@#!/bin/sh\'$'\nset -x ; exec 2>/'$script'.log@'

			notice "chrooting to execute $script..."
			sudo chmod +x  "$strapdir/$script"    || zerr
			sudo chroot "$strapdir" "/$script" || zerr
			sudo mv -f "$strapdir/${script}.log" "$R/log/"

			[[ "$APT_CACHE" = 1 ]] && { aptcache off "$strapdir/mnt" || zerr }
			;;
	esac

	sudo rm -f $strapdir/$script
}

install_fake_package() {
	fn install_fake_package "$@"
	req=(strapdir pkgname pkgver section)
	local pkgname="$1"
	local pkgver="$2"
	local section="$3"
	ckreq || return 1

	local _tmp="$strapdir/tmp"
	sudo mkdir -p "$_tmp/$pkgname"

	cat <<EOF | sudo tee ${_tmp}/${pkgname}/${pkgname}_${pkgver}.control >/dev/null
Section: ${section}
Priority: optional
Homepage: https://devuan.org/
Standards-Version: 3.9.6

Package: ${pkgname}
Version: ${pkgver}
Maintainer: Devuan developers <onelove@devuan.org>
Architecture: all
Description: (Fake) ${pkgname}
  Dummy package used to meet some dependencies without installing the
  real ${pkgname} package.
EOF

	cat <<EOF | sudo tee ${strapdir}/install-fake-package >/dev/null
#!/bin/sh
cd /tmp/${pkgname}
equivs-build ${pkgname}_${pkgver}.control \
	&& dpkg -i ${pkgname}_${pkgver}_all.deb || exit 1
cd /tmp
rm -rf ${pkgname}
EOF
	chroot-script install-fake-package  || { zerr; wrapup }
}

blend_preinst() {
	fn blend_preinst
	func "not overriden"
	return 0
}

blend_postinst() {
	fn blend_postinst
	func "not overriden"
	return 0
}

syslinux() {
	fn blend_syslinux
	req=(strapdir pkgname pkgver section)
	local pkgname="$1"
	local pkgver="$2"
	local section="$3"
	ckreq || return 1	
	
	
}

silly() {
	fn silly "$@"
	local arg1="$1"
	local arg2="$2"
	## cheers mailpile!
	funneh=("do not think of purple hippos"
		"increasing entropy & scrambling bits"
		"indexing kittens..."
		"patching bugs..."
		"spinning violently around the y-axis"
		"warming up particle accelerator"
		"this server is powered by a lemon and two electrodes"
		"becoming self-aware"
		"BCC-ing ALL THE SPIES!"
		"all of your config settings & passwords are encrypted with AES256"
		"the most common password is 123456, hopefully yours is different"
		"good things come to those who wait"
		"Make Free Software and be happy"
		"We like volcanos, do you like volcanos?"
		"Crossing out swear words..."
		"Informing David Cameron of suspicious ac^H^H^H ... naaah :)"
		"Abandon all hope, ye who enter here"
		"Compiling bullshit bingo grid..."
		"Estimating chance of asteroid hitting Earth"
		"Applying coupons..."
		"Backing up the entire Internet..."
		"Making you wait for no reason"
		"Doing nothing"
		"Pay no attention to the man behind the curtain"
		"You are great just the way you are"
		"Supplying monkeys with typewriters"
		"Swapping time and space"
		"Self potato"
		"god is porco"
		"A million hamsters are spinning their wheels right now"
	)
	local rnd=$(shuf -i1-$#funneh -n 1)
	act "${funneh[$rnd]}"
	[[ $arg1 = sleep ]] && sleep $arg2 || true
}
