#!/bin/bash
# This script load zfs kernel module for any archiso.
# github.com/eoli3n
# Thanks to CalimeroTeknik on #archlinux-fr, FFY00 on #archlinux-projects, JohnDoe2 on #regex

set -e

exec &> >(tee "debug.log")

### Functions

print () {
    echo -e "\n\033[1m> $1\033[0m"
}

get_running_kernel_version () {
# Returns running kernel version

    # Get running kernel version
    kernel_version=$(uname -r)
    
    print "Current kernel version is $kernel_version"
}

init_archzfs () {
    if pacman -Sl archzfs >/dev/null 2>&1; then
        print "archzfs repo was already added"
        return
    fi
    print "Adding archzfs repo"
    
    # Disable Sig check
    pacman -Syy archlinux-keyring --noconfirm &>/dev/null
    pacman-key --populate archlinux &>/dev/null
    pacman-key --recv-keys F75D9D76 &>/dev/null
    pacman-key --lsign-key F75D9D76 &>/dev/null
    cat >> /etc/pacman.conf <<"EOF"
[archzfs]
Server = http://archzfs.com/archzfs/x86_64
Server = http://mirror.sum7.eu/archlinux/archzfs/archzfs/x86_64
Server = https://mirror.biocrafting.net/archlinux/archzfs/archzfs/x86_64
EOF
    pacman -Sy &>/dev/null
}

init_archlinux_archive () {
# $1 is date formated as 'YYYY/MM/DD'
# Returns False if repo does not exists

    # Archlinux Archive workaround for 2022/02/01
    if [[ "$1" == "2022/02/01" ]]
    then
        version="2022/02/02"
    else
        version="$1"
    fi

    # Set repo
    repo="https://archive.archlinux.org/repos/$version/"

    # If repo exists, set it
    curl -s "$repo" &>/dev/null && echo "Server=$repo\$repo/os/\$arch" > /etc/pacman.d/mirrorlist

}

search_package () {
# $1 is package name to search
# $2 is version to match

    # Set regex to match package
    local regex='href="\K(?![^"]*\.sig)'"$1"'-(?=\d)[^"]*'"$2"'[^"]*x86_64[^"]*'
    # href="               # match href="
    # \K                   # don't return anything matched prior to this point
    # (?![^"]*\.sig)       # remove .sig matches
    # '"$1"'-(?=\d)        # find me '$package-' escaped by shell and ensure that after "-" is a digit
    # [^"]*                # match anything between '"'
    # '"$2"'               # match version escaped by shell
    # [^"]*                # match anything between '"'
    # x86_64               # now match architecture
    # [^"]*                # match anything between '"'
    
    # Set archzfs URLs list
    local urls="http://archzfs.com/archzfs/x86_64/ http://archzfs.com/archive_archzfs/"
    
    # Loop search
    for url in $urls
    do
    
        print "Searching $1 on $url..."
    
        # Query url and try to match package
        local package=$(curl -s "$url" | grep -Po "$regex" | tail -n 1)
    
        # If a package is found
        if [[ -n $package ]]
        then
    
            print "Package \"$package\" found"
    
            # Build package url
            package_url="$url$package"

            # Break loop
            break
        fi
    done
}

download_package () {
# $1 is package url to download in tmp
# It returns downloaded file path

    local filename="${1##*/}"

    # Download package in tmp
    cd /tmp
    curl -sO "$1"
    cd -

    # Set out file
    package_file="/tmp/$filename"

    print "Downloading to $package_file ..."
}

dkms_init () {
# Init everything to be able to install zfs-dkms

    print "Init Archlinux Archive repository"
    archiso_version=$(sed 's-\.-/-g' /version)
    init_archlinux_archive "$archiso_version"

    print "Download Archlinux Archives package lists and upgrade"
    pacman -Syyuu --noconfirm &>/dev/null

    print "Install base-devel"
    pacman -S --noconfirm base-devel linux-headers git &>/dev/null

}

### Main

print "Testing if archiso is running"

grep 'arch.*iso' /proc/cmdline >/dev/null

print "Increasing cowspace to half of RAM"

mount -o remount,size=50% /run/archiso/cowspace

# Init archzfs repository
init_archzfs

# Search kernel package
# https://github.com/archzfs/archzfs/issues/337#issuecomment-624312576
get_running_kernel_version
kernel_version_fixed="${kernel_version//-/\.}"

# Search zfs-linux package matching running kernel version
search_package "zfs-linux" "$kernel_version_fixed"
zfs_linux_url="$package_url"

# If a package is found
if [[ -n $zfs_linux_url ]]
then

    # Download package
    download_package $zfs_linux_url
    zfs_linux_package="$package_file"

    print "Extracting zfs-utils version from zfs-linux PKGINFO"

    # Extract zfs-utils version from zfs-linux PKGINFO
    zfs_utils_version=$(bsdtar -qxO -f "$zfs_linux_package" .PKGINFO | grep -Po 'depend = zfs-utils=\K.*')

    # Search zfs-utils package matching zfs-linux package dependency
    search_package "zfs-utils" "$zfs_utils_version"
    zfs_utils_url="$package_url"

    if [[ -n $zfs_utils_url ]]
    then

        print "Installing zfs-utils and zfs-linux"

        # Install packages
        pacman -U "$zfs_utils_url" --noconfirm &>/dev/null
        pacman -U "$zfs_linux_package" --noconfirm &>/dev/null && zfs=1
    fi
else

    # DKMS fallback
    print "No zfs-linux package was found for current running kernel, fallback on DKMS method"
    dkms_init

    print "Install zfs-dkms"
    
    # Install package
    pacman -S zfs-dkms --noconfirm &>/dev/null && zfs=1

fi

# Load kernel module
if [[ "$zfs" == "1" ]]
then

    modprobe zfs && echo -e "\n\e[32mZFS is ready\n"

else
    print "No ZFS module found"
fi
