# Contributor: David P. <megver83@parabola.nu>
# Contributor: André Silva <emulatorman@hyperbola.info>
# Contributor: Márcio Silva <coadde@hyperbola.info>
# Contributor: fauno <fauno@parabola.nu>
# Contributor: Sorin-Mihai Vârgolici <smv@yobicore.org>
# Contributor: Michał Masłowski <mtjm@mtjm.eu>
# Contributor: Luke R. <g4jc@openmailbox.org>
# Contributor: Andreas Grapentin <andreas@grapentin.org>
# Maintainer: Parabola Hackers <dev@lists.parabola.nu>
# Contributor: bill-auger <bill-auger@programmer.net>
# Maintainer (arch:linux): Jan Alexander Steffens (heftig) <heftig@archlinux.org>
# Maintainer (archarm:linux-armv7): Kevin Mihelich <kevin@archlinuxarm.org>
# Maintainer (arch32:linux): Andreas Baumann <mail@andreasbaumann.cc>


# CAVEATS:
#   Provides linux-libre{,-docs,-headers} but not linux{,-docs,-headers}.
#   Otherwise, it is not possible to install along-side linux-libre,
#   because linux-libre conflicts and replaces any other package which provides linux.
#   Until we get this sorted out (eg: add linux-libre provision to linux-libre{,lts,...}),
#   the trade-off is that packages which require linux{,-docs,-headers}
#   will pull in linux-libre, even if linux-libre-vanilla is installed.
#   - linux-libre:         extra/netfilter-fullconenat requires linux
#                          pcr/xtables-addons required linux - changed to linux-libre
#   - linux-libre-headers: nothing requires linux-headers (but provided for completeness)
#   - linux-libre-docs:    extra/systeroid requires linux-docs


pkgbase=linux-libre-vanilla
pkgver=6.5.8
_minor_ver=$(sed 's|\([0-9]\+\.[0-9]\+\).*|\1|' <<<${pkgver}) # eg: 6.1
_upstream_minor_ver=${_minor_ver}-gnu                         # eg: 6.1-gnu
_upstream_ver=${pkgver}-gnu                                   # eg: 6.1.5-gnu
_is_patch_release=$( [[ ${_upstream_minor_ver} != ${_upstream_ver} ]] ; echo $((!$?)) ; )
pkgrel=1
pkgdesc="Linux-libre (pristine upstream release)"
url=https://linux-libre.fsfla.org/
arch=(armv7h i686 x86_64)
license=(GPL2)
makedepends=(
  bc
  cpio
  gettext
  libelf
  pahole
  perl
  python
  tar
  xz

  # htmldocs
  graphviz
  imagemagick
  python-sphinx
  texlive-latexextra
)
makedepends_armv7h=(uboot-tools vboot-utils dtc) # required by linux-libre-chromebook
options=('!strip')
_srcname=linux-${_minor_ver}
source=(https://linux-libre.fsfla.org/pub/linux-libre/releases/${_upstream_minor_ver}/linux-libre-${_upstream_minor_ver}.tar.xz{,.sign}
        https://repo.parabola.nu/other/linux-libre/logos/logo_linux_{clut224.ppm,vga16.ppm,mono.pbm}{,.sig})
(( _is_patch_release )) && source+=(https://linux-libre.fsfla.org/pub/linux-libre/releases/${_upstream_ver}/patch-${_upstream_minor_ver}-${_upstream_ver}.xz{,.sign})
source_armv7h=(config.armv7h
               'kernel.its'
               'kernel.keyblock'
               'kernel_data_key.vbprivk'
               ${pkgbase}-armv7h.preset)
source_i686=(config.i686
             no-ultra-zstd.patch)
source_x86_64=(config.x86_64)
sha512sums=('45c8beef2e529df41f21819583ac8bdc37f6cf34434d94ae5ef08586b2d82721e3cf2a1f36a89f8627c07f3f3cc68d6e0707d09bc76a7f2c2f909d59c242eb23'
            'SKIP'
            '13cb5bc42542e7b8bb104d5f68253f6609e463b6799800418af33eb0272cc269aaa36163c3e6f0aacbdaaa1d05e2827a4a7c4a08a029238439ed08b89c564bb3'
            'SKIP'
            '7a3716bfe3b9f546da309c7492f3e08f8f506813afeb1c737a474c83313d5c313cf4582b65215c2cfce3b74d9d1021c96e8badafe8f6e5b01fe28d2b5c61ae78'
            'SKIP'
            '267295aa0cea65684968420c68b32f1a66a22d018b9d2b2c1ef14267bcf4cb68aaf7099d073cbfefe6c25c8608bdcbbd45f7ac8893fdcecbf1e621abdfe9ecc1'
            'SKIP')
(( _is_patch_release )) && sha512sums+=('9eaa0ffebe5628b8d1f67795b72a5a76f4e5ffa9d73963123e33e26380f37ce81277d6088323ff41a308ab2dea191b959a6b05e6d85d318ccba8c383ab2ff605'
                                        'SKIP')
sha512sums_armv7h=('47d16ffc94510d4a8773146a46cfb35aca8cfdae38d17283334cd62d92de36250fbec90e9892357033398ecc7d970127b1a41b703a8372972422ca4af7c90c70'
                   'f10af02f0cb2d31259d9633e1ba845f555f525789f750fc2ddc51bd18c5ff64fcdd242dae801623887f5ce5cdb5528bce890459f0fab9fd31a28868bb7f6bba5'
                   'bb6718984a7357c9b00c37e4788480e5b8b75018c172ecc1441bc3fc5d2d42444eb5d8c7f9d2e3a7d6fed6d03acb565e3c0559486e494c40a7fe6bd0570c9ede'
                   '143dea30c6da00e504c99984a98a0eb2411f558fcdd9dfa7f607d6c14e9e7dffff9cb00121d9317044b07e3e210808286598c785ee854084b993ec9cb14d8232'
                   'f01e7925b262d2874a8a991b1f27d057356a2a384d2012b61be5a631d4e4d7cf87461c8fb9e7f183831f5a829ad204897f1f0545a52df6288a0e04a5c2e31b96')
sha512sums_i686=('21c65d7466740b30f060863732e2e80bcb451b15a8d4005015eb0cab87522b5c267c71815ac5f7cdf0394f39157b16b6d223a13cd30df2b6ae7092efd4ba26bf'
                 'bca15cc96f64c38adcd13a46752866b5b30555ac21e19b3f7afcd20fcb7ec585c9d990fe8f842f44d5f69d477d72867fe6a9102729f26f93f5a80b372e41ce85')
sha512sums_x86_64=('092654fbb1b9f6c6d4eb16ada303b0d34874c65f9ca845b1c1a7c741ee972573a5ec52848bd08969a82c9f74105af674707c8bb7c44b00d84b6413f5342c695a')
validpgpkeys=('474402C8C582DAFBE389C427BCB7CF877E7D47A7'  # Alexandre Oliva
              '6DB9C4B4F0D8C0DC432CF6E4227CA7C556B2BA78') # David P.


# per-arch KARCH
case "$CARCH" in
  i686|x86_64) KARCH=x86;;
  armv7h) KARCH=arm;;
esac

# reproducibility
export KBUILD_BUILD_HOST=parabola
export KBUILD_BUILD_USER=$pkgbase
export KBUILD_BUILD_TIMESTAMP="$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})"


prepare() {
  cd $_srcname

  # upstream patch release
  if [ "${_minor_ver}" != "$pkgver" ]; then
    echo "Applying upstream patch release"
    patch -Np1 < "../patch-${_minor_ver}-gnu-${pkgver}-gnu"
  fi

  # freedo boot logo
  install -m644 -t drivers/video/logo ../logo_linux_{clut224.ppm,vga16.ppm,mono.pbm}

  echo "Setting version..."
  echo "-$pkgrel" > localversion.10-pkgrel
  echo "${pkgbase#linux}" > localversion.20-pkgname
  sed -i 's|^-libre||'      localversion.20-pkgname # minimize diff

  local src
  declare -n per_arch_source=source_${CARCH}
  for src in "${source[@]}" "${per_arch_source[@]}"; do
    src="${src%%::*}"
    src="${src##*/}"
    # *.zst n/a
    [[ $src = *.patch ]] || continue
    echo "Applying patch $src..."
    patch -Np1 < "../$src"
  done

  echo "Setting config..."
  mv ../config{.$CARCH,} # minimize diff
  cp ../config .config
  make olddefconfig
  diff -u ../config .config || :

  if [ "$CARCH" = "armv7h" ]; then
    # don't run depmod on 'make install'. We'll do this ourselves in packaging
    sed -i '2iexit 0' scripts/depmod.sh
  fi

  make -s kernelrelease > version
  echo "Prepared $pkgbase version $(<version)"
}

build() {
  [[ "$CARCH" == i686 ]] && export COMPRESSZST=(zstd -c -T0 --ultra -19 -)

  cd $_srcname
  make all
  [[ "$CARCH" =~ ^(armv7h|i686)$ ]] || # FIXME: sphinx-build returned an error at ./scripts/sphinx-pre-install line 317.
  make htmldocs
}

_package() {
  pkgdesc="The $pkgdesc kernel and modules"
  depends=(
    coreutils
    initramfs
    kmod
  )
  optdepends=(
    'wireless-regdb: to set the correct wireless channels of your country'
    'linux-firmware: firmware images needed for some devices'
  )
  optdepends=( "${optdepends[@]/linux/linux-libre}" ) # minimize diff
  provides=(
    # KSMBD-MODULE             # no parabola package requires this
    # VIRTUALBOX-GUEST-MODULES # no parabola package requires this
    # WIREGUARD-MODULE         # no parabola package requires this
  )
  provides=("linux-libre=${pkgver}")
  replaces=(
    # virtualbox-guest-modules-arch # no such parabola package since 2021
    # wireguard-arch                # no such parabola package since 2020
  )
  backup=("etc/mkinitcpio.d/${pkgbase}.preset")
  if [[ "$CARCH" == armv7h ]] ; then install=${pkgname}-armv7h.install ; fi ; # BR #3520

  cd $_srcname
  local modulesdir="$pkgdir/usr/lib/modules/$(<version)"

  echo "Installing boot image..."
  # systemd expects to find the kernel here to allow hibernation
  # https://github.com/systemd/systemd/commit/edda44605f06a41fb86b7ab8128dcf99161d2344
  install -Dm644 "$(make -s image_name)" "$modulesdir/vmlinuz"

  # Used by mkinitcpio to name the kernel
  echo "$pkgbase" | install -Dm644 /dev/stdin "$modulesdir/pkgbase"

  echo "Installing modules..."
  ZSTD_CLEVEL=19 make INSTALL_MOD_PATH="$pkgdir/usr" INSTALL_MOD_STRIP=1 \
    DEPMOD=/doesnt/exist modules_install  # Suppress depmod

  if [ "$CARCH" = "armv7h" ]; then
    echo "Installing device tree binaries..."
    make INSTALL_DTBS_PATH="${pkgdir}/boot/dtbs/${pkgbase}" dtbs_install
  fi

  # remove build and source links
  rm "$modulesdir"/{source,build}

  if [ "$CARCH" = "armv7h" ]; then
    local _kernver="$(<version)"           # minimize diff
    cp ../{${pkgbase}-armv7h,linux}.preset # minimize diff

    # now we call depmod...
    depmod -b "${pkgdir}/usr" -F System.map "${_kernver}"

    # sed expression for following substitutions
    local _subst="
      s|%PKGBASE%|${pkgbase}|g
      s|%KERNVER%|${_kernver}|g
    "

    echo "Installing mkinitcpio preset..."
    # install mkinitcpio preset file
    sed "${_subst}" ../linux.preset |
      install -Dm644 /dev/stdin "${pkgdir}/etc/mkinitcpio.d/${pkgbase}.preset"
  fi
}

_package-headers() {
  pkgdesc="Headers and scripts for building modules for the $pkgdesc kernel"
  depends=(pahole)
  provides=("linux-libre-headers=${pkgver}")

  cd $_srcname
  local builddir="$pkgdir/usr/lib/modules/$(<version)/build"

  echo "Installing build files..."
  install -Dt "$builddir" -m644 .config Makefile Module.symvers System.map \
    localversion.* version vmlinux
  install -Dt "$builddir/kernel" -m644 kernel/Makefile
  install -Dt "$builddir/arch/$KARCH" -m644 arch/$KARCH/Makefile
  if [ "$CARCH" = "i686" ]; then
    install -Dt "$builddir/arch/$KARCH" -m644 arch/$KARCH/Makefile_32.cpu
  fi
  cp -t "$builddir" -a scripts

  # required when STACK_VALIDATION is enabled
  [[ -e tools/objtool/objtool ]] &&
  install -Dt "$builddir/tools/objtool" tools/objtool/objtool

  # required when DEBUG_INFO_BTF_MODULES is enabled
  [[ -e tools/bpf/resolve_btfids/resolve_btfids ]] &&
  install -Dt "$builddir/tools/bpf/resolve_btfids" tools/bpf/resolve_btfids/resolve_btfids

  echo "Installing headers..."
  cp -t "$builddir" -a include
  cp -t "$builddir/arch/$KARCH" -a arch/$KARCH/include
  install -Dt "$builddir/arch/$KARCH/kernel" -m644 arch/$KARCH/kernel/asm-offsets.s

  # ARM-specific headers
  if [ "$CARCH" = "armv7h" ]; then
    local _builddir="${builddir}" # minimize diff
    cp -t "${_builddir}/arch/${KARCH}" -a arch/${KARCH}/include
  fi

  install -Dt "$builddir/drivers/md" -m644 drivers/md/*.h
  install -Dt "$builddir/net/mac80211" -m644 net/mac80211/*.h

  # https://bugs.archlinux.org/task/13146
  install -Dt "$builddir/drivers/media/i2c" -m644 drivers/media/i2c/msp3400-driver.h

  # https://bugs.archlinux.org/task/20402
  install -Dt "$builddir/drivers/media/usb/dvb-usb" -m644 drivers/media/usb/dvb-usb/*.h
  install -Dt "$builddir/drivers/media/dvb-frontends" -m644 drivers/media/dvb-frontends/*.h
  install -Dt "$builddir/drivers/media/tuners" -m644 drivers/media/tuners/*.h

  # https://bugs.archlinux.org/task/71392
  install -Dt "$builddir/drivers/iio/common/hid-sensors" -m644 drivers/iio/common/hid-sensors/*.h

  echo "Installing KConfig files..."
  find . -name 'Kconfig*' -exec install -Dm644 {} "$builddir/{}" \;

  echo "Removing unneeded architectures..."
  local arch
  for arch in "$builddir"/arch/*/; do
    [[ $arch = */$KARCH/ ]] && continue
    echo "Removing $(basename "$arch")"
    rm -r "$arch"
  done

  echo "Removing documentation..."
  rm -r "$builddir/Documentation"

  echo "Removing broken symlinks..."
  find -L "$builddir" -type l -printf 'Removing %P\n' -delete

  echo "Removing loose objects..."
  find "$builddir" -type f -name '*.o' -printf 'Removing %P\n' -delete

  echo "Stripping build tools..."
  local file
  while read -rd '' file; do
    case "$(file -Sib "$file")" in
      application/x-sharedlib\;*)      # Libraries (.so)
        strip -v $STRIP_SHARED "$file" ;;
      application/x-archive\;*)        # Libraries (.a)
        strip -v $STRIP_STATIC "$file" ;;
      application/x-executable\;*)     # Binaries
        strip -v $STRIP_BINARIES "$file" ;;
      application/x-pie-executable\;*) # Relocatable binaries
        strip -v $STRIP_SHARED "$file" ;;
    esac
  done < <(find "$builddir" -type f -perm -u+x ! -name vmlinux -print0)

  echo "Stripping vmlinux..."
  strip -v $STRIP_STATIC "$builddir/vmlinux"

  echo "Adding symlink..."
  mkdir -p "$pkgdir/usr/src"
  ln -sr "$builddir" "$pkgdir/usr/src/$pkgbase"
}

_package-docs() {
  pkgdesc="Documentation for the $pkgdesc kernel"
  provides=("linux-libre-docs=${pkgver}")

  cd $_srcname
  local builddir="$pkgdir/usr/lib/modules/$(<version)/build"

  echo "Installing documentation..."
  local src dst
  while read -rd '' src; do
    dst="${src#Documentation/}"
    dst="$builddir/Documentation/${dst#output/}"
    install -Dm644 "$src" "$dst"
  done < <(find Documentation -name '.*' -prune -o ! -type d -print0)

  echo "Adding symlink..."
  mkdir -p "$pkgdir/usr/share/doc"
  ln -sr "$builddir/Documentation" "$pkgdir/usr/share/doc/$pkgbase"
}

_package-chromebook() {
  pkgdesc="$pkgdesc kernel sign for Veyron Chromebooks"
  depends=("${pkgbase}=${pkgver}")
  provides=("linux-libre=${pkgver}")
  replaces=("linux-libre-armv7-chromebook")
  install=${pkgname}.install

  cd $_srcname

  cp ../kernel.its .
  mkimage -D "-I dts -O dtb -p 2048" -f kernel.its vmlinux.uimg
  dd if=/dev/zero of=bootloader.bin bs=512 count=1
  echo 'console=tty0 init=/sbin/init root=PARTUUID=%U/PARTNROFF=1 rootwait rw noinitrd' > cmdline

  echo "Creating kernel sign..."
  vbutil_kernel \
    --pack vmlinux.kpart \
    --version 1 \
    --vmlinuz vmlinux.uimg \
    --arch arm \
    --keyblock ../kernel.keyblock \
    --signprivate ../kernel_data_key.vbprivk \
    --config cmdline \
    --bootloader bootloader.bin

  echo "Installing kernel sign..."
  mkdir -p "${pkgdir}/boot"
  cp vmlinux.kpart "${pkgdir}/boot"
}

pkgname=(
  "$pkgbase"
  "$pkgbase-headers"
  "$pkgbase-docs"
)
[ "$CARCH" = "armv7h" ] && pkgname+=("$pkgbase-chromebook")
for _p in "${pkgname[@]}"; do
  eval "package_$_p() {
    $(declare -f "_package${_p#$pkgbase}")
    _package${_p#$pkgbase}
  }"
done

# FIXME: sphinx-build returned an error at ./scripts/sphinx-pre-install line 317.
if   [[ "$CARCH" =~ ^(armv7h|i686)$ ]]
then pkgname=( ${pkgname[*]/$pkgbase-docs/} )
     makedepends=( ${makedepends[*]/python-sphinx/} )
fi


# FIXME: `mkimage kernel.signed` command fails in _package-chromebook()
#        FATAL ERROR: Couldn't open "arch/arm/boot/dts/exynos5250-snow.dtb": No such file or directory
#        mkimage: Can't open vmlinux.uimg.tmp: No such file or directory
[[ "$CARCH" == armv7h ]] && pkgname=( ${pkgname[*]/$pkgbase-chromebook/} ) || :
