#!/usr/bin/env -S make -j1 -rRf

# Usage: pacman-make-keyring V=$(date -u +%Y%m%d) [ keyserver=<HKP_URL> ]

# Copyright 2014,2016 Luke Shumaker <lukeshu@sbcglobal.net>
# Copyright 2021-2022 bill-auger    <bill-auger@programmer.net>
#
# This 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 2 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 manual; if not, see
# <http://www.gnu.org/licenses/>.


# apply config
KEYRING_NAME = parabola
bin         := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
yamldir     := $(shell ruby -e "load '$(bin)/common.rb'; print cfg['yamldir']")
keyserver   := $(shell ruby -e "load '$(bin)/common.rb'; print cfg['keyring_keyserver']")
cachedir    := $(shell ruby -e "load '$(bin)/common.rb'; print cfg['keyring_cachedir']")
outputdir    = $(cachedir)/$(KEYRING_NAME)-keyring-$(V)

# sanity checks
ifeq ($(origin V),undefined)
  $(info Usage: pacman-make-keyring V=$$(date -u +%Y%m%d) [ keyserver=<HKP_URL> ]) $(info)
  $(error V= must be set in the environment, on the command line, etc)
endif
ifneq ($(findstring hkp://,${keyserver}),hkp://)
  $(error keyserver must be a valid hkp:// URL)
endif


all: $(KEYRING_NAME)-keyring-$(V).tar.gz
.PHONY: all

export SHELL = /bin/bash -o pipefail
.PHONY: FORCE
.SECONDARY:
.DELETE_ON_ERROR:

dirs = \
	$(outputdir) \
	$(cachedir) \
	$(cachedir)/gpghome \
	$(cachedir)/keys/trusted \
	$(cachedir)/keys/secondary \
	$(cachedir)/keys/revoked

$(dirs):
	mkdir -p $@

$(cachedir)/var.%: FORCE | $(cachedir)
	@$(file >$(@D)/tmp.$(@F),$($*))
	@sed -i 's|^|#|' $(@D)/tmp.$(@F)
	@if cmp -s $(@D)/tmp.$(@F) $@; then \
		rm -f $(@D)/tmp.$(@F) || :; \
	else \
		mv -f $(@D)/tmp.$(@F) $@; \
	fi
-include $(wildcard $(cachedir)/var.*)
$(cachedir)/txt.%: $(cachedir)/var.%
	sed 's|^#||' < $< > $@
var=$(cachedir)/var.

keyring-files = \
	$(outputdir)/Makefile \
	$(outputdir)/${KEYRING_NAME}.gpg \
	$(outputdir)/${KEYRING_NAME}-trusted \
	$(outputdir)/${KEYRING_NAME}-revoked

$(KEYRING_NAME)-keyring-$(V).tar.gz: %.tar.gz: $(keyring-files)
	bsdtar --format=ustar -cf - -C $(cachedir) $(addprefix $*/,$(notdir $^)) | gzip -9 > $@

define Makefile.in
V=@V@

prefix = /usr/local
PREFIX = $$(prefix)

install:
	install -dm755 $$(DESTDIR)$$(PREFIX)/share/pacman/keyrings/
	install -m0644 @KEYRING_NAME@{.gpg,-trusted,-revoked} $$(DESTDIR)$$(PREFIX)/share/pacman/keyrings/

uninstall:
	rm -f $$(DESTDIR)$$(PREFIX)/share/pacman/keyrings/@KEYRING_NAME@{.gpg,-trusted,-revoked}
	rmdir -p --ignore-fail-on-non-empty $$(DESTDIR)$$(PREFIX)/share/pacman/keyrings/

.PHONY: install uninstall
endef

$(outputdir)/Makefile: $(cachedir)/txt.Makefile.in $(var)V $(var)KEYRING_NAME | $(outputdir)
	sed $(foreach v,$(patsubst $(var)%,%,$(filter $(var)%,$^)), -e 's|@$v@|$($v)|' ) < $< > $@


users := $(sort $(shell find $(yamldir))) $(var)users

# Assemble the list of .asc files needed to generate the keyring
$(cachedir)/deps.mk: ${users} $(var)outputdir $(var)cachedir $(var)KEYRING_NAME| $(cachedir)
	{ \
		echo $(outputdir)/${KEYRING_NAME}.gpg: $$($(bin)/pgp-list-keyids | sed -r 's|(\S+) .*|$$(cachedir)/keys/\1.asc|') && \
		echo $(cachedir)/stamp.ownertrust: $$($(bin)/pgp-list-keyids | sed -rn 's|^(trusted/\S+) .*|$$(cachedir)/keys/\1.asc|p') && \
		$(bin)/pgp-list-keyids | sed -rn 's|^trusted/(\S+) (.*)|keyid.\1 = \2|p' && \
		$(bin)/uid-map | sed 's|.*|trusted:&\nsecondary:&\nrevoked:&|' | sed -r 's|(.*):(.*):(.*)|$$(cachedir)/keys/\1/\3.asc: $$(yamldir)/\2.yml|' && \
	:; }> $@
-include $(cachedir)/deps.mk

# The remainder of file is mostly just a translation of the shell
# script `update-keys`.
#
#     https://git.archlinux.org/archlinux-keyring.git/tree/update-keys

export LANG=C

# NOTE: Key fetches tend to fail if fired-off too rapidly,
#       (even 2 seconds intervals). 5 seconds intervals has not yet failed.
FETCH_IVL = 5
KEYSERVER = ${keyserver}
GPG       = gpg --quiet --batch --no-tty --no-permission-warning --keyserver ${KEYSERVER} --homedir $(cachedir)/gpghome

define gpg-init
%echo Generating Parabola Keyring keychain master key...
Key-Type: RSA
Key-Length: 1024
Key-Usage: sign
Name-Real: Parabola Keyring Keychain Master Key
Name-Email: parabola-keyring@localhost
Expire-Date: 0
%no-protection
%commit
%echo Done
endef
$(cachedir)/stamp.gpg-init: $(cachedir)/txt.gpg-init $(var)GPG | $(cachedir)/gpghome
	${GPG} --gen-key < $<
	touch $@

# The appropriate ${uid}.yml file is added as a dependency to
# ${username}.yml by deps.mk
keyid=$(keyid.$(patsubst %.asc,%,$(notdir $@)))

# In 'update-keys', this is the 'master-keyids' loop
$(outputdir)/${KEYRING_NAME}-trusted: ${users} | $(outputdir)
	$(bin)/pgp-list-keyids | sed -rn 's|^trusted/\S+ (\S+)|\1:4:|p' > $@
$(cachedir)/keys/trusted/%.asc  : $(cachedir)/stamp.gpg-init   | $(cachedir)/keys/trusted
	sleep ${FETCH_IVL} && ${GPG} --recv-keys ${keyid}
	printf 'minimize\nquit\ny\n' | ${GPG} --command-fd 0 --edit-key ${keyid}
	printf 'y\ny\n' | ${GPG} --command-fd 0 --lsign-key ${keyid}
	${GPG} --armor --no-emit-version --export ${keyid} > $@

$(cachedir)/stamp.ownertrust: $(outputdir)/${KEYRING_NAME}-trusted $(cachedir)/deps.mk
	${GPG} --import-ownertrust < $<
	touch $@

# In 'update-keys', this is the 'packager-keyids' loop
$(cachedir)/keys/secondary/%.asc: $(cachedir)/stamp.ownertrust | $(cachedir)/keys/secondary
	sleep ${FETCH_IVL} && ${GPG} --recv-keys ${keyid}
	printf 'clean\nquit\ny\n' | ${GPG} --command-fd 0 --edit-key ${keyid}
	${GPG} --list-keys --with-colons ${keyid} | grep -q '^pub:f:' # make sure it is trusted
	${GPG} --armor --no-emit-version --export ${keyid} > $@

# In 'update-keys', this is the 'packager-revoked-keyids' loop
$(outputdir)/${KEYRING_NAME}-revoked: ${users} | $(outputdir)
	$(bin)/pgp-list-keyids | sed -rn 's|^revoked/\S+ ||p' > $@
$(cachedir)/keys/revoked/%.asc  : $(cachedir)/stamp.ownertrust | $(cachedir)/keys/revoked
	sleep ${FETCH_IVL} && ${GPG} --recv-keys ${keyid}
	printf 'clean\nquit\ny\n' | ${GPG} --command-fd 0 --edit-key ${keyid}
	! ${GPG} --list-keys --with-colons ${keyid} | grep -q '^pub:f:' # make sure it isn't trusted
	${GPG} --armor --no-emit-version --export ${keyid} > $@

$(outputdir)/${KEYRING_NAME}.gpg: $(cachedir)/deps.mk | $(outputdir)
	cat $(filter %.asc,$^) > $@
