#!/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/>.

## imagine images

vars+=(image_name bootpart rootpart loopdevice filesystem)
arrs+=(fsargs)

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

	notice "creating raw image file from zeroes..."

	dd if=/dev/zero \
		of=$workdir/${image_name}.img \
		bs=1M \
		count=$size
}

image_format_partitions() {
	fn image_format_partitions
	req=(bootfs bootpart rootpart)
	ckreq || return 1

	notice "formatting partitions..."
	case "$bootfs" in
		none)
			act "skipping boot partition"
			;;
		vfat|fat|dos)
			act "formatting boot as vfat"
			sudo mkfs.vfat ${=bootopts} ${bootpart}
			;;
		ext4)
			act "formatting boot as ext4"
			sudo mkfs.ext4 ${=bootopts} ${bootpart}
			;;
		ext2)
			act "formating boot as ext2"
			sudo mkfs.ext2 ${=bootopts} ${bootpart}
			;;
		*)
			error "unknown parted_bootfs type '$bootfs'"
			zerr
			;;
	esac

	# default to ext4
	[[ -z "$rootfs" ]] && rootfs=ext4

	case "$rootfs" in
		none)
			act "skipping root partition"
			;;
		vfat|fat|dos)
			act "formatting root as vfat"
			sudo mkfs.vfat ${=rootopts} ${rootpart}
			;;
		ext4)
			act "formatting root as ext4"
			sudo mkfs.ext4 ${=rootopts} ${rootpart}
			;;
		ext2)
			act "formating root as ext2"
			sudo mkfs.ext2 ${=rootopts} ${rootpart}
			;;
		btrfs)
			act "formatting root as btrfs"
			sudo mfks.btrfs ${=rootopts} ${rootpart}
			;;
		*)
			error "unknown parted_rootfs type '$rootfs'"
			zerr
			;;
	esac
}

image_partition_raw_dos() {
	fn image_partition_raw_dos
	req=(workdir image_name parted_boot parted_root)
	ckreq || return 1

	notice "partitioning raw dos image..."

	parted $workdir/${image_name}.img --script -- mklabel msdos
	parted $workdir/${image_name}.img --script -- mkpart primary ${parted_boot}
	parted $workdir/${image_name}.img --script -- mkpart primary ${parted_root}
	[ -n "$bootable_part" ] && \
	    parted "$workdir/${image_name}.img" --script -- set "$bootable_part" boot on

	## get loopdevice (see ./helpers)
	findloopdev

	bootpart=${loopdevice}p1
	rootpart=${loopdevice}p2

	image_format_partitions
}

image_partition_raw_gpt() {
	fn image_partition_raw_gpt
	req=(workdir image_name gpt_boot gpt_root)
	ckreq || return 1

	notice "partitioning raw gpt image..."

	parted $workdir/${image_name}.img --script -- mklabel gpt || zerr
	cgpt create -z $workdir/${image_name}.img || zerr
	cgpt create    $workdir/${image_name}.img || zerr

	cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \
		-s ${gpt_boot[2]} \
		-l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img

	cgpt add -i 2 -t data -b ${gpt_root[1]} \
		-s $(expr $(cgpt show $workdir/${image_name}.img | \
		awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \
		-l Root $workdir/${image_name}.img

	findloopdev

	bootpart="${loopdevice}p1"
	rootpart="${loopdevice}p2"

	image_format_partitions
}

image_pack_dist() {
	fn image_pack_dist
	req=(loopdevice image_name strapdir workdir)
	ckreq || return 1

	notice "packaging image for dist"

	act "rechecking filesystem"
	sudo e2fsck -fy ${loopdevice}p2
	sudo resize2fs ${loopdevice}p2

	sleep 2

	[[ $parted_type = gpt ]] && {
		sudo cgpt repair $loopdevice
		sleep 1
	}

	sudo partx -dv $loopdevice || {
		die "partx failed to remove $loopdevice"
		zerr
	}
	sudo losetup -d $loopdevice || {
		die "losetup failed to remove $loopdevice"
		zerr
	}

	if [[ -n "$nocompressimage" ]]; then
		_suffix="img"
	else
		_suffix="img.xz"
	fi

	pushd $workdir

	[[ -n "$nocompressimage" ]] || {
		notice "compressing image with xz"
		silly
		xz -zv "${image_name}.img"
	}

	mkdir -p "$R/dist"
	mv -v ${image_name}.${_suffix} $R/dist/

	pushd "$R/dist"
	notice "generating sha256 for ${image_name}.${_suffix}"
	sha256sum ${image_name}.${_suffix} > ${image_name}.${_suffix}.sha
	notice "generating sha256 for ${image_name}.tar.gz"
	sha256sum ${image_name}.tar.gz > ${image_name}.tar.gz.sha
	popd

	popd

	[[ $DEBUG = 1 ]] || sudo rm -r $workdir

	notice "finished packing $image_name"
	act "find it in $R/dist/"
	act "thanks for being patient!"
}

image_raw_mount() {
	fn image_raw_mount
	req=(workdir bootpart rootpart bootfs)
	ckreq || return 1

	mkdir -p $workdir/mnt
	sudo mount $rootpart $workdir/mnt && \
		act "mounted root partition" || zerr

	[[ "$bootfs" == none ]] || {
		sudo mkdir -p $workdir/mnt/boot
		sudo mount $bootpart $workdir/mnt/boot && \
			act "mounted boot partition" || zerr
	}
}

image_raw_umount() {
	fn image_raw_umount
	req=(workdir bootpart rootpart)
	ckreq || return 1

	[[ "$bootfs" == none ]] || {
		sudo umount $workdir/mnt/boot && act "unmounted boot partition" || zerr
		sleep 1
	}
	sudo umount $workdir/mnt      && act "unmounted root partition" || zerr
}

image_raw_as_strapdir() {
	fn image_raw_as_strapdir
	req=(workdir strapdir size)
	ckreq || return 1

	pushd "$workdir"

	notice "creating raw image of $size MB"
	sudo rm -f base.raw
	sudo qemu-img create -f raw base.raw ${size}M   || zerr
	notice "partitioning"
	sudo parted base.raw mktable msdos              || zerr
	sudo parted base.raw mkpart primary '0%' '100%' || zerr
	loopdevice=$(losetup --find)
	sudo losetup -P $loopdevice base.raw || zerr
	sudo mkfs.ext4 ${loopdevice}p1       || zerr

	notice "mounting raw image to strapdir"
	sudo mount ${loopdevice}p1 $strapdir
	echo 1 | sudo tee ${strapdir}/.keep >/dev/null
	popd
}

image_qcow2_as_strapdir() {
	fn image_qcow2_as_strapdir
	req=(workdir strapdir size)
	ckreq || return 1

	pushd "$workdir"

	# default filesystem fallback to ext4
	filesystem=${filesystem:-ext4}

	notice "creating qcow2 image of $size MB formatted with $filesystem"
	rm -f base.qcow2
	qemu-img create -f qcow2 base.qcow2 ${size}M     || zerr
	sudo modprobe nbd max_part=8                     || zerr
	loopdevice="$(findfreenbd)"
	[ -n "$loopdevice" ]                             || zerr
	act "$loopdevice"
	sudo qemu-nbd --connect=${loopdevice} base.qcow2 || zerr

	notice "partitioning"
	sudo parted ${loopdevice} mktable msdos              || zerr
	sudo parted ${loopdevice} mkpart primary '0%' '100%' || zerr

	notice "formatting with $filesystem"
	command -v mkfs.${filesystem} >/dev/null || {
		error "filesystem tools not found in path: mkfs.${filesystem}"
		zerr }
	sudo mkfs.${filesystem} ${=fsargs} ${loopdevice}p1 || zerr

	notice "mounting qcow2 image to strapdir"
	sudo mount ${loopdevice}p1 $strapdir || zerr
	echo 1 | sudo tee ${strapdir}/.keep >/dev/null
	popd
}

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

	notice "creating a tarbomb of the rootfs..."
	mkdir -p "$R/dist"
	silly
	pushd "$strapdir"
	sudo tar czf "$R/dist/${image_name}.tar.gz" . || zerr
	popd
}
