#!/bin/sh -X # no runnable script, just for editors
# set -eu is assumed.
# (Note that in ALT /bin/sh is a bash with a few features turned off.)
# (TODO: make sure that ALT's /bin/sh is enough;
# use the lightweight /bin/sh in the actual test scripts.)
#
# At least the syntax in nginxstart() requires bash >= 4 (&>>).

# TESTDIR is usually set in all the testscripts sourcing framework.
. $TESTDIR/framework-without-repo

aptcdrom() { runapt apt-cdrom "${CDROM_OPTS[@]}" "$@"; }

# Input:
# * args: orig_dir repo_dir [repo_date]
#   (orig_dir may be empty if we just need to re-generate without copying rpms.)
# * a few global vars
#
# Output/effects:
# * files in $repo_dir
# * global var REPO_COMPR_EXT (the extension for the compressed pkglists there)
generaterepository() {
	local orig_dir="$1"
	local repo_dir="$2"
	local repo_date="${3-}"

	local label="$GB_REPO_LABEL"
	if [ -z "$label" ]; then
		label="apt-tests"
	fi
	local description="$GB_REPO_DESCRIPTION"
	if [ -z "$description" ]; then
		description="ALT Linux $label"
	fi
	local date_s="$(date +%s)"
	local arch="$APT_TEST_USED_ARCH"
	local comps="${label}"

	if [ -n "$repo_date" ] ; then
		date_s="$repo_date"
	fi

	local archive="$GB_REPO_ARCHIVE"
	if [ -z "$archive" ]; then
		archive="$description"
	fi
	local codename="$GB_REPO_CODENAME"
	if [ -z "$codename" ]; then
		codename="$date_s"
	fi
	local origin="$GB_REPO_ORIGIN"
	if [ -z "$origin" ]; then
		origin="ALT Linux Team"
	fi
	local suite="$GB_REPO_SUITE"
	if [ -z "$suite" ]; then
		suite="$label"
	fi
	local version="$GB_REPO_VERSION"
	if [ -z "$version" ]; then
		version="$date_s"
	fi

	# The compression opts can be forced from the environment.
	local compression_opts="$APT_TEST_BASEDIR_COMPRESSION_OPTS"
	if [ -z "$compression_opts" ]; then
		# By default, choose minimal required compressions
		# for the chosen method to work without errors.
		# (FIXME: fix APT so that the used compression doesn't matter!)
		case "$APT_TEST_METHOD" in

			http*) compression_opts='--no-bz2 --xz'
			       REPO_COMPR_EXT=.xz
			       ;;

			cdrom*) compression_opts='--bz2 --no-xz'
				REPO_COMPR_EXT=.bz2
				;;

			*) compression_opts='--no-bz2 --no-xz'
			   REPO_COMPR_EXT=
			   ;;

		esac
	fi

	if [ -n "$orig_dir" ]; then
		# initial generation
		rm -rf "$repo_dir"
		for dir in ${arch} noarch ; do
			mkdir -p "${repo_dir}/${dir}/RPMS.${label}"
			mkdir -p "${repo_dir}/${dir}/base"
			stat "${orig_dir}/${dir}/"*.rpm &>/dev/null &&
				cp "${orig_dir}/${dir}/"*.rpm "${repo_dir}/${dir}/RPMS.${label}"/
		done
	fi

	mkdir -p "${TMPWORKINGDIRECTORY}/cache"

	for dir in ${arch} noarch ; do
		genbasedir \
			--cachedir="${TMPWORKINGDIRECTORY}/cache" \
			--architecture="$dir" \
			--architectures="$dir" \
			--archive="$archive" \
			--codename="$codename" \
			--description="$description" \
			--label="$label" \
			--origin="$origin" \
			--suite="$suite" \
			--version="$version" \
			--topdir="$repo_dir" \
			--changelog-since='@1' \
			--flat --no-oldhashfile $compression_opts --mapi \
			$APT_TEST_GENBASEDIR_OPTS \
			$dir $comps

		if [ -n "$repo_date" ] ; then
			touch -t $(date --date=@${repo_date} '+%Y%m%d%H%M.%S') \
				  "${repo_dir}/${dir}/base/"*
		fi
	done
}

# Input:
# * args ORIG_DIR [REPO_DATE]
# * files in $ORIG_DIR
# * global var APT_TEST_METHOD
#
# Output/effects:
# * server configured to give the data to apt
#   (or other actions, according to $APT_TEST_METHOD)
# * global var REPO_STORAGE -- where we physically store the data given to apt
#   (it will be set depending on $APT_TEST_METHOD)
# * files in $REPO_STORAGE
# * global vars NOARCH_DISTRO, MYARCH_DISTRO, DISTRO_COMPONENT
#   -- the paths under $REPO_STORAGE or $APT_SOURCES_URI; the final part
#   specified in sources.list after the URI with the component/"label"
# * server started to give the data to apt
#   (or other actions, according to $APT_TEST_METHOD)
# * global vars APT_SOURCES_SITE, APT_SOURCES_URI -- how apt sees its source repo:
#   - APT_SOURCES_SITE is shown as "Site:" by apt-cache dump
#   - APT_SOURCES_URI IS used in sources.list and to identify files in APT_LISTS_DIR
# * sources.list configured accordingly
#
# (The global vars are convenient for other scripts to refer to these values.)
generaterepository_and_switch_sources() {
	local -r ORIG_DIR="$1"
	local -r REPO_DATE="${2-}"

	# Configure the server to give the data to apt
	# (or other actions, according to $APT_TEST_METHOD).
	#
	# And set REPO_STORAGE accordingly.
	case "$APT_TEST_METHOD" in

		file)
			REPO_STORAGE="$TMPWORKINGDIRECTORY/usr/src/RPM/REPO"
			;;

		http)
			nginxsetuphttp
			REPO_STORAGE="$NGINX_STORAGE"
			;;

		https|https_invalid_cert_hostname)
			nginxsetuphttps
			REPO_STORAGE="$NGINX_STORAGE"
			;;

		cdrom|cdrom_missing_release)
			REPO_STORAGE="$MOCKUP_CDROM_STORAGE"
			;;

		*)
			msgdie 'unknown $APT_TEST_METHOD'
			;;

	esac

	# Put the files into $REPO_STORAGE.
	#
	# Expose the paths used under it.
	generaterepository "$ORIG_DIR" "$REPO_STORAGE" "$REPO_DATE"
	NOARCH_DISTRO=noarch
	MYARCH_DISTRO="$APT_TEST_USED_ARCH"
	DISTRO_COMPONENT=apt-tests

	# Additional configuration for the server or other methods.
	case "$APT_TEST_METHOD" in

		https*)
			# generate key
			case "$APT_TEST_METHOD" in
				https_invalid_cert_hostname)
					local -r cert_hostname=wrong-"$NGINX_HOST"
					;;
				*)
					local -r cert_hostname="$NGINX_HOST"
					;;
			esac
			openssl req -x509 \
				-newkey rsa:4096 \
				-keyout $NGINX_KEY \
				-out $NGINX_CRT \
				-nodes \
				-days 365 \
				-subj "/CN=$cert_hostname" \
			    &>/dev/null

			# add key to apt's config. Also pin the key
			cat >| $TMPWORKINGDIRECTORY/rootdir/etc/apt/apt.conf.d/80https.conf <<- END
			Acquire::https::CaInfo	"$NGINX_CRT";
			END

			cat >| $TMPWORKINGDIRECTORY/rootdir/etc/apt/apt.conf.d/81https-pinning.conf <<- END
			Acquire::https::PinnedCert	"$NGINX_CRT";
			END
			;;

		cdrom*)
			mkdir "$MOCKUP_CDROM_STORAGE"/.disk
			# trailing whitespace here might be misinterpreted
			echo "Distribution $REPO_DATE Disk" >"$MOCKUP_CDROM_STORAGE"/.disk/info

			# DEBUG: Let's have an idea of the FS tree there:
			#ls -laR "$MOCKUP_CDROM_STORAGE"

			case "$APT_TEST_METHOD" in
				cdrom_missing_release)
					find "$MOCKUP_CDROM_STORAGE"/*/base -name 'release*' -print -delete
					;;
			esac
			;;

	esac

	# Start the server.
	case "$APT_TEST_METHOD" in

		http*)
			nginxrestart
			;;

	esac

	# Overwrite old sources.list.
	#
	# And set APT_SOURCES_SITE, APT_SOURCES_URI accordingly.
	case "$APT_TEST_METHOD" in

		cdrom*)
			# overwrite old sources.list
			echo >| rootdir/etc/apt/sources.list
			aptcdrom add >&2 <<<$'\n'

			APT_SOURCES_SITE="$(<"$MOCKUP_CDROM_STORAGE"/.disk/info)"
			APT_SOURCES_URI="$APT_SOURCES_SITE"
			;;

		file)
			APT_SOURCES_SITE=''
			APT_SOURCES_URI="$APT_SOURCES_SITE$REPO_STORAGE"

			cat >| rootdir/etc/apt/sources.list <<- END
				rpm $APT_TEST_METHOD://$APT_SOURCES_URI $MYARCH_DISTRO $DISTRO_COMPONENT
				rpm $APT_TEST_METHOD://$APT_SOURCES_URI $NOARCH_DISTRO $DISTRO_COMPONENT
			END
			;;

		http*)
			APT_SOURCES_SITE="$NGINX_HOST"
			APT_SOURCES_URI="$APT_SOURCES_SITE:$NGINX_PORT"

			cat >| rootdir/etc/apt/sources.list <<- END
				rpm ${APT_TEST_METHOD%%_*}://$APT_SOURCES_URI/ $MYARCH_DISTRO $DISTRO_COMPONENT
				rpm ${APT_TEST_METHOD%%_*}://$APT_SOURCES_URI/ $NOARCH_DISTRO $DISTRO_COMPONENT
			END
			;;

	esac

	NOARCH_PKGLIST_URI="$APT_SOURCES_URI/$NOARCH_DISTRO/base/pkglist.$DISTRO_COMPONENT"
	MYARCH_PKGLIST_URI="$APT_SOURCES_URI/$MYARCH_DISTRO/base/pkglist.$DISTRO_COMPONENT"
	local encoded_noarch_pkglist_uri encoded_myarch_pkglist_uri
	encoded_noarch_pkglist_uri="$(encode_uri_for_apt_lists "$NOARCH_PKGLIST_URI")"
	encoded_myarch_pkglist_uri=$(encode_uri_for_apt_lists "$MYARCH_PKGLIST_URI")
	local -r encoded_noarch_pkglist_uri encoded_myarch_pkglist_uri
	APT_FETCHED_NOARCH_PKGLIST="$APT_LISTS_DIR/$encoded_noarch_pkglist_uri"
	APT_FETCHED_MYARCH_PKGLIST="$APT_LISTS_DIR/$encoded_myarch_pkglist_uri"
	APT_FETCHED_PARTIAL_NOARCH_PKGLIST="$APT_LISTS_DIR/partial/$encoded_noarch_pkglist_uri"
	APT_FETCHED_PARTIAL_MYARCH_PKGLIST="$APT_LISTS_DIR/partial/$encoded_myarch_pkglist_uri"
}

# Output/effects:
# * global vars representing the actual configuration of the server
#   (convenient for use in other scripts):
#   NGINX_HOST, NGINX_PORT, NGINX_STORAGE, NGINX_PIDFILE
# * the server configured, ready for nginxrestart()
nginxsetuphttp() {
	mkdir -p $TMPWORKINGDIRECTORY/nginx
	mkdir -p $TMPWORKINGDIRECTORY/nginx/tmp

	NGINX_HOST=localhost
	NGINX_PORT=$((8080+${PARALLEL_SLOT:-0}))
	NGINX_STORAGE=$TMPWORKINGDIRECTORY/nginx/repo
	NGINX_PIDFILE=$TMPWORKINGDIRECTORY/nginx/nginx.pid

	cat >| $TMPWORKINGDIRECTORY/nginx/nginx.conf << ENDCONFIG
error_log stderr;
worker_processes 1;
pid $NGINX_PIDFILE;

events {
	worker_connections  1024;
}

http {
	client_body_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/client_body;
	fastcgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/fastcgi_temp;
	proxy_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/proxy_temp;
	scgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/scgi_temp;
	uwsgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/uwsgi_temp;

	include             /etc/nginx/mime.types;
	default_type        application/octet-stream;

	sendfile off;

	keepalive_timeout   65;

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_prefer_server_ciphers on;
	access_log stderr;
	error_log stderr;

	server {
		listen $NGINX_PORT;
		server_name $NGINX_HOST localhost.localdomain;

		location / {
			root $NGINX_STORAGE;
			autoindex on;
		}
	}
}
ENDCONFIG
}

# Output/effects:
# * global vars representing the actual configuration of the server
#   (convenient for use in other scripts):
#   NGINX_HOST, NGINX_PORT, NGINX_KEY, NGINX_CRT, NGINX_STORAGE, NGINX_PIDFILE
# * the server configured, ready for nginxrestart() (except for the key)
nginxsetuphttps() {
	mkdir -p $TMPWORKINGDIRECTORY/nginx
	mkdir -p $TMPWORKINGDIRECTORY/nginx/tmp

	NGINX_HOST=localhost
	NGINX_PORT=$((8080+${PARALLEL_SLOT:-0}))
	NGINX_KEY=$TMPWORKINGDIRECTORY/nginx/cert.key
	NGINX_CRT=$TMPWORKINGDIRECTORY/nginx/cert.crt
	NGINX_STORAGE=$TMPWORKINGDIRECTORY/nginx/repo
	NGINX_PIDFILE=$TMPWORKINGDIRECTORY/nginx/nginx.pid

	cat >| $TMPWORKINGDIRECTORY/nginx/nginx.conf << ENDCONFIG
error_log stderr;
worker_processes 1;
pid $NGINX_PIDFILE;

events {
	worker_connections  1024;
}

http {
	client_body_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/client_body;
	fastcgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/fastcgi_temp;
	proxy_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/proxy_temp;
	scgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/scgi_temp;
	uwsgi_temp_path $TMPWORKINGDIRECTORY/nginx/tmp/uwsgi_temp;

	include             /etc/nginx/mime.types;
	default_type        application/octet-stream;

	sendfile off;

	keepalive_timeout   65;

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_prefer_server_ciphers on;
	access_log stderr;
	error_log stderr;

	server {
		listen $NGINX_PORT ssl;
		server_name $NGINX_HOST localhost.localdomain;

		ssl_certificate	$NGINX_CRT;
		ssl_certificate_key	$NGINX_KEY;

		ssl_session_cache	builtin:1000	shared:SSL:10m;
		ssl_protocols TLSv1.2;
		ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
		ssl_prefer_server_ciphers on;

		location / {
			root $NGINX_STORAGE;
			autoindex on;
		}
	}
}
ENDCONFIG
}

wait_for_file() {
	# The message 'Waiting...' is intentionally printed regardless of $MSGLEVEL;
	# otherwise it would be difficult to see why the process is hanging;
	# it can appear only in extra-ordinary situations (under heavy load).
	[ -s "$1" ] ||
		printf >&6 'Waiting for %s\n' "$1" &&
		while ! [ -s "$1" ]; do
			sleep 0.5
		done
}

nginxrestart() {
	local -r NGINXLOG=$TMPWORKINGDIRECTORY/nginx/process-stderr.log

	! [ -s "$NGINX_PIDFILE" ] || {
		echo 'Stopping nginx with a signal (before a restart).'
		kill -TERM "$(cat "$NGINX_PIDFILE")"
	} &>>"$NGINXLOG"
	rm -f "$NGINX_PIDFILE"

	# The wait_for_file workaround would not be needed if nginx fully conformed
	# to the "traditional UNIX forking daemon" behavior described
	# in systemd.service(5); unfortunately for us, the upstream hasn't "fixed"
	# this race[1], although a patch for synchronizing the exit of the parent
	# with the creation of the pidfile is available[2].
	# [1]: https://trac.nginx.org/nginx/ticket/1897
	# [2]: http://mailman.nginx.org/pipermail/nginx-ru/2017-November/060628.html
	/usr/sbin/nginx -c $TMPWORKINGDIRECTORY/nginx/nginx.conf -p $TMPWORKINGDIRECTORY &>>"$NGINXLOG" &&
		wait_for_file "$NGINX_PIDFILE" &&
		local -r NGINXPID="$(cat "$NGINX_PIDFILE" 2>>"$NGINXLOG")" &&
		[ -n "$NGINXPID" ] ||
			{ { echo NGINXLOG:; cat "$NGINXLOG"; } >&6 ||:
			  msgdie 'nginx failed to start normally'
			}

	addtrap 'prefix' \
			'kill -TERM %q ||:; [ "$EXIT_CODE" = 0 ] || if [ -e %q ]; then echo NGINXLOG:; cat %q ||:; fi >&6;' \
			"$NGINXPID" \
			"$NGINXLOG" \
			"$NGINXLOG"
}

# Faking pkglist or its cksum (in the release file).
#
# There are two ways to go (so that there is a mismatch with
# the checksum in the release file):
#
# 1. Faking the pkglist itself. It is more realistic, but less reliable as
# to understanding the cause of apt's failure: whether it's just the cksum or
# another error in the format of the pkglist.
#
# To overcome the issue with the format, one could generate another real repo,
# and copy the pkglist from there. But then it's the size that could mismatch...
#
# And even a simple recompression of a minimally changed pkglist
# quite probably leads to a size mismatch. So, the test
# may seemingly pass because of the other reason for the mismatch.
#
# 2. Another way could be to edit the cksum in the release file instead.
# (This way is simpler, since we'd anyway have to edit the size
# of the compressed fake pkglist.)

# Input:
# * args CMD [ARG..] -- stream editor
# * global vars REPO_STORAGE, NOARCH_DISTRO
# * file $REPO_STORAGE/$NOARCH_DISTRO/base/release
#
# Output/effects:
# * the file is edited; its time is unchanged
edit_repo_noarch_release() {
	local -r repo_noarch_release="$REPO_STORAGE/$NOARCH_DISTRO/base/release"
	mv "$repo_noarch_release"{,.orig}

	"$@" \
	    >"$repo_noarch_release" \
	    <"$repo_noarch_release".orig

	if [ $MSGLEVEL -gt 3 ]; then # info
		echo "Edited $repo_noarch_release:"
		diff -u --text "$repo_noarch_release"{.orig,} && echo '(no diff)' ||:
	fi >&6

	touch -r "$repo_noarch_release".orig -- "$repo_noarch_release"
	rm -- "$repo_noarch_release".orig
}

# Here is an implementation of way 1:

# Input:
# * args CMD [ARG..] -- stream editor (for the pkglist)
# * global vars REPO_STORAGE, NOARCH_DISTRO, DISTRO_COMPONENT, REPO_COMPR_EXT
# * files $REPO_STORAGE/$NOARCH_DISTRO/base/{pkglist.$DISTRO_COMPONENT,release}
#   and its compressed counterpart (if any)
#
# Output/effects:
# * the file (and its compressed counterpart) is edited; its time is unchanged
# * the size of the compressed counterpart in the release file is adjusted; its time is unchanged
fake_repo_noarch_pkglist() {
	local -r repo_noarch_pkglist="$REPO_STORAGE/$NOARCH_DISTRO/base/pkglist.$DISTRO_COMPONENT"
	mv "$repo_noarch_pkglist"{,.orig}
	rm -f "$repo_noarch_pkglist$REPO_COMPR_EXT"

	"$@" \
	    >"$repo_noarch_pkglist" \
	    <"$repo_noarch_pkglist".orig

	if [ $MSGLEVEL -gt 3 ]; then # info
		echo "Edited $repo_noarch_pkglist:"
		diff --report-identical-files --brief "$repo_noarch_pkglist"{.orig,} ||:
	fi >&6

	touch -r "$repo_noarch_pkglist".orig -- "$repo_noarch_pkglist"

	if [ -n "$REPO_COMPR_EXT" ]; then

	    case "$REPO_COMPR_EXT" in
		.xz) xz --keep -- "$repo_noarch_pkglist"
		     ;;
		.bz2) bzip2 --keep -- "$repo_noarch_pkglist"
		      ;;
	    esac
	    touch -r "$repo_noarch_pkglist".orig -- "$repo_noarch_pkglist$REPO_COMPR_EXT"

	    # Now, we have to edit the size of the compressed fake pkglist.
	    local new_size
	    new_size="$(stat --format '%s' -- "$repo_noarch_pkglist$REPO_COMPR_EXT")"
	    local -r new_size
	    # FIXME: the regex is not quite a regex below
	    edit_repo_noarch_release \
		sed -Ee "s:^( [^ ]* )[^ ]*( base/pkglist\.$DISTRO_COMPONENT$REPO_COMPR_EXT):\1$new_size\2:"
	fi

	rm -- "$repo_noarch_pkglist".orig
}

# Here is an implementation of way 2:

# a helper function
bad_cksum() {
	local -r cksum_type="$1"; shift

	case "$cksum_type" in

	    MD5Sum)
	        md5sum /dev/null
		;;

	    SHA1)
	        sha1sum /dev/null
		;;

	    SHA256)
	        sha256sum /dev/null
		;;

	    BLAKE2b)
	        b2sum /dev/null
		;;

	    *)
		msgdie "Unknown cksum_type $cksum_type"
		;;

	esac | cut -d' ' -f1
}

# Input:
# * args: cksum_type CMD [ARG..] -- stream editor
# * global vars REPO_STORAGE, NOARCH_DISTRO
# * file $REPO_STORAGE/$NOARCH_DISTRO/base/release
#
# Output/effects:
# * the file is edited; its time is unchanged
fake_repo_noarch_pkglist_cksum() {
	local -r cksum_type="$1"; shift

	local a_bad_cksum
	a_bad_cksum="$(bad_cksum "$cksum_type")"
	local -r a_bad_cksum

	edit_repo_noarch_release \
	    sed -Ee "/^$cksum_type:/,/^[^ ]/ { /pkglist/ s:^ [^ ]* : $a_bad_cksum :; }"
}

# Input:
# * args: cksum_type CMD [ARG..] -- stream editor
# * global vars REPO_STORAGE, NOARCH_DISTRO
# * file $REPO_STORAGE/$NOARCH_DISTRO/base/release
#
# Output/effects:
# * the file is edited; its time is unchanged
fake_repo_noarch_pkglist_size() {
	local a_bad_size
	# a big number that fits into signed 64-bit integer, but not narrower
	printf -v a_bad_size '%d' 0x7edcba9876543210
	local -r a_bad_size

	edit_repo_noarch_release \
	    sed -Ee "/pkglist/ s:^( [^ ]*) [^ ]* :\1 $a_bad_size :"
}

# Input:
# * args NAME CMD [ARG..] -- the name of the pkg and a stream editor (for the pkg file)
# * global vars REPO_STORAGE, NOARCH_DISTRO, DISTRO_COMPONENT
# * files $REPO_STORAGE/$NOARCH_DISTRO/RPMS.$DISTRO_COMPONENT/NAME-*.rpm
#
# Output/effects:
# * the file is edited; its time is unchanged
fake_repo_noarch_rpm() {
	local -r name="$1"; shift

	local pkgfile
	pkgfile="$(builtpackagefile "$name")"
	pkgfile="${pkgfile##*/}"
	local -r pkgfile

	local -r repo_noarch_pkgfile="$REPO_STORAGE/$NOARCH_DISTRO/RPMS.$DISTRO_COMPONENT/$pkgfile"
	mv "$repo_noarch_pkgfile"{,.orig}

	"$@" \
	    >"$repo_noarch_pkgfile" \
	    <"$repo_noarch_pkgfile".orig

	if [ $MSGLEVEL -gt 3 ]; then # info
		echo "Edited $repo_noarch_pkgfile:"
		diff --report-identical-files --brief "$repo_noarch_pkgfile"{.orig,} ||:
	fi >&6

	touch -r "$repo_noarch_pkgfile".orig -- "$repo_noarch_pkgfile"

	rm -- "$repo_noarch_pkgfile".orig
}

# Input:
# * args: cksum_type NAME
# * global vars REPO_STORAGE
# * files in $TMPWORKINGDIRECTORY/cache/
#
# Output/effects:
# * files in $TMPWORKINGDIRECTORY/cache/ are edited
# * the index files in $REPO_STORAGE/*/base/ are regenerated
#   with fake cksums for the NAME rpm
#   (by calling generaterepository(), with all its effects)
fake_repo_rpm_cksum() {
	local -r cksum_type="$1"; shift
	local -r name="$1"; shift

	local pkgfile
	pkgfile="$(builtpackagefile "$name")"
	pkgfile="${pkgfile##*/}"
	local -r pkgfile

	local pkgfile_re
	set_regex_quote_str pkgfile_re "$pkgfile"
	local -r pkgfile_re

	local a_bad_cksum
	a_bad_cksum="$(bad_cksum "$cksum_type")"
	local -r a_bad_cksum

	cp -a "$TMPWORKINGDIRECTORY"/cache{,.orig} -T

	local cache_ext="$cksum_type"
	cache_ext="${cache_ext%Sum}"
	cache_ext="${cache_ext,,}"
	cache_ext="${cache_ext}cache"
	local -r cache_ext
	find "$TMPWORKINGDIRECTORY"/cache/ -name "*.$cache_ext" -print0 \
	    | xargs -0 --no-run-if-empty \
		    sed -Ee "/^$pkgfile_re / { s:^([^ ]*) [^ ]* :\1 $a_bad_cksum :; }" -i --

	if [ $MSGLEVEL -gt 3 ]; then # info
		echo "Edited *.$cache_ext"
		diff -u --text -Nr "$TMPWORKINGDIRECTORY"/cache{.orig,} && echo '(no diff)' ||:
	fi >&6
	rm -r -- "$TMPWORKINGDIRECTORY"/cache.orig

	# re-generate using the same rpms, but a cache with fake cksums
	generaterepository '' "$REPO_STORAGE"
}
