#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2025 GNOME Foundation, Inc.
set -e

toplevel=$(realpath _sysext)
SOURCE_DIR="${toplevel}/source"
BUILD_DIR="${toplevel}/build"
HOME_SYSEXT_DIR="${toplevel}/install"
RUN_SYSEXT_DIR=/run/extensions/malcontent

usage() {
  cat <<-EOF
Usage: $(basename "${0}") [OPTION…]

Build and install a systemd-sysext extension for malcontent

Options:
  --setup                 Pull and setup the sources from fresh
  --no-merge              Don’t merge the sysext after building
  --source-dir            Use the given malcontent.git source directory
                          (e.g. your local project directory with changes to test)
  -h, --help              Display this help
EOF
}

die() {
  echo "$@" >&2
  exit 1
}

setup() {
  mkdir -p "${SOURCE_DIR}"

  # Clone malcontent.git
  if [[ ! -d "${malcontent_source_dir}" ]]; then
    git clone --depth 1 --no-tags git@ssh.gitlab.freedesktop.org:pwithnall/malcontent.git "${malcontent_source_dir}"
  fi
  meson setup --prefix=/usr "${BUILD_DIR}/malcontent" "${malcontent_source_dir}"

  # Clone libgsystemservice.git; we need to build this as a non-subproject so
  # it can be installed in the sysext
  libgsystemservice_branch="$(awk '/^revision/{print $NF}' "${malcontent_source_dir}/subprojects/libgsystemservice.wrap")"

  git clone --depth 1 --no-tags --branch "${libgsystemservice_branch}" https://gitlab.gnome.org/pwithnall/libgsystemservice.git "${libgsystemservice_source_dir}"
  meson setup --prefix=/usr "${BUILD_DIR}/libgsystemservice" "${libgsystemservice_source_dir}"
}

compile_and_install() {
  # Compile and install to a local install tree
  meson compile -C "${BUILD_DIR}/libgsystemservice"
  meson install --destdir="${HOME_SYSEXT_DIR}" -C "${BUILD_DIR}/libgsystemservice"

  meson compile -C "${BUILD_DIR}/malcontent"
  meson install --destdir="${HOME_SYSEXT_DIR}" -C "${BUILD_DIR}/malcontent"
}

merge() {
  # Restore the right SELinux permissions for the files, if necessary.
  if [[ -x $(which setfiles) ]]; then
    setfiles -F -r "${HOME_SYSEXT_DIR}" /etc/selinux/targeted/contexts/files/file_contexts "${HOME_SYSEXT_DIR}/usr"
  fi

  # Link the sysext tree into where systemd expects it
  sudo mkdir -p "$(dirname "${RUN_SYSEXT_DIR}")"
  sudo ln -Tsf "${HOME_SYSEXT_DIR}" "${RUN_SYSEXT_DIR}"

  # Merge the sysext into the system
  sudo systemd-sysext refresh --force

  # Trigger creation of any directories and users.
  sudo systemctl restart systemd-sysusers.service systemd-tmpfiles-clean.service

  # Apparently inotify watches don’t trigger on some systems when a sysext is
  # installed, so manually reload various services which watch for drop-in
  # files. See https://gitlab.freedesktop.org/pwithnall/malcontent/-/issues/95#note_3028842
  sudo systemctl reload dbus.service polkit.service
  sudo systemctl reload-or-restart accounts-daemon.service  # doesn’t support reload
}

args=$(getopt \
  --name "$(basename "${0}")" \
  --options 'h' \
  --longoptions 'setup' \
  --longoptions 'no-merge' \
  --longoptions 'source-dir:' \
  --longoptions 'help' \
  -- "$@") || die "Run $(basename "${0}") --help to see available options"
eval set -- "$args"

run_setup=0
run_merge=1
malcontent_source_dir="${SOURCE_DIR}/malcontent"
libgsystemservice_source_dir="${SOURCE_DIR}/libgsystemservice"

while true; do
  case $1 in
    --setup)
      run_setup=1
      shift
    ;;

    --no-merge)
      run_merge=0
      shift
    ;;

    --source-dir)
      malcontent_source_dir=$(realpath "${2}")
      shift 2
    ;;

    -h|--help)
      usage
      exit 0
    ;;

    --)
      shift
      break
    ;;
  esac
done

if [[ ! -d "${SOURCE_DIR}" || $run_setup == 1 ]]; then
  setup
fi
compile_and_install
if [[ $run_merge == 1 ]]; then
  merge
fi