#! /bin/sh -eu
#
# Modified by ALT Linux Team <apt@packages.altlinux.org>.
# Last change by Sviatoslav Sviridov <svd@altlinux.ru>.
# genbasedir was rewritten as mix of genbasedir scripts
# from Connectiva's apt-0.5.4cnc9 and ALT Linux Team's
# apt-0.3.19cnc55-alt9.
#
# The previous version from apt-0.5.4cnc9 was:
# $Id: genbasedir,v 1.6 2002/09/04 22:48:37 niemeyer Exp $
#
# This script generates the contents of the base/ directory, by creating
# the pkglists and the hash file. Update the components directory to contain
# the components of your repository.
#

# This program is ALT-specific, so we expect /bin/sh to be a lightweight
# build of bash.
# shellcheck disable=SC2039
set -o pipefail

PROG="${0##*/}"

topdir=
patch_basedir=
prev_basedir=
add_list=
rm_list=

basedir_=base

signature=
listonly=
hashonly=
partial=
mapi=
compressedonly=
updateinfo=
progress=
flat=
defaultkey=
topdir=
create=
verbose=
cachedir=
useful_files=

maybe_unchanged=
unchanged=1

# bloat is necessary for non-Conectiva distros, at least RH,
# because they use file dependencies with a non-predictable
# heuristic. So we can't strip-off paths that will probably
# never appear in dependencies.
bloat=
noscan=

# Global release file sections
origin="Unknown"
label="Unknown"
suite="Unknown"
codename="Unknown"
date="`date -R`"
architectures="Unknown"
description="Not Available"

# Component release file sections
archive="Unknown"
version="Unknown"
architecture="Unknown"
notautomatic="false"

changelog_since=

preferred_prev_compression="zstd none xz bz2"

make_bz2=1
make_xz=1
make_zst=

disable_hash_caching=
add_blake2b=1

Fatal()
{
	echo "${0##*/}: $*" >&2
	exit 1
}

Verbose()
{
	if [ -n "$verbose" ]; then
		echo "$@"
	fi
}

USAGE()
{
	cat >&2 <<EOF
Usage: ${0##*/} [<options>] <distribution> [<comp1> [<comp2> ...]]

Options:
   --basedir=DIR      Write basedir contents to a different subdirectory.
   -s, --sign         Generate and sign hashfile
   --default-key=ID   Use ID as gnupg secret key
   --hashonly         Do hash stuff only
   --listonly         Generate pkglists/srclists and quit
   --partial          Update just some of the already existent components
   --compressedonly   Generate only compressed lists
   --no-compression   Do not generate any compressed lists
   --bz2              Generate bz2-compressed lists
   --no-bz2           Do not generate bz2-compressed lists
   --xz               Generate xz-compressed lists
   --no-xz            Do not generate xz-compressed lists
   --zstd             Generate zstd-compressed lists
   --no-zstd          Do not generate zstd-compressed lists
   --progress         Show progress bars for genpkglist/gensrclist;
                      implies --verbose
   -v, --verbose      Be more talkative
   --silent           Be less talkative (default)
   --topdir=dir       Top directory of repository
   --updateinfo=FILE  Update information file
   --mapi             List only those pkgs in srclist which generate
                      some binaries
   --flat             Use flat repository, where SRPMS and RPMS are in
                      the topdir (SRPMS are usually in 'topdir/..')
   --no-scan          Do not scan for useful files.
   --bloat            Do not strip the package file list. Needed for some
                      distributions that use non-automatically generated
                      file dependencies
   --useful-files=FILE
                      Read the list of useful files from FILE.
                      Do not strip these files from the package file list.
   --create           Create base directory if needed

   --origin=ORIGIN    Set "Origin" field in global release file
   --label=LABEL      Set "Label" field in global release file
   --suite=SUITE      Set "Suite" field in global release file
   --codename=CODENAME
                      Set "Codename" field in global release file
   --architectures=ARCHITECTURES
                      Set "Architectures" field in global release file
   --description=DESCRIPTION
                      Set "Description" field in global release file

   --archive=ARCHIVE  Set "Archive" field in component release file
   --version=VERSION  Set "Version" field in component release file
   --architecture=ARCHITECTURE
                      Set "Architecture" field in component release file
   --notautomatic=true|false  Set "NotAutomatic" field in component release file
   --blake2b          Add package file BLAKE2b to pkglist
   --no-blake2b       Do not add package file BLAKE2b to pkglist
   --disable-hash-caching    Do not cache package hashsums
   --cachedir=DIR     Use a custom md5sum cache directory for package list
   --changelog-since=DATE     Save package changelogs; copy changelog entries
                              newer than DATE, and also one preceding entry
   --maybe-unchanged  Skip the update if pkglist is unchanged.

   -h,--help          Show this help screen

Examples:

   ${0##*/} --topdir=/var/ftp/pub/distributions/ALTLinux/Sisyphus i586
   ${0##*/} --topdir=/var/ftp/pub/distributions/ALTLinux/Sisyphus i586 base kernel castle junior master contrib classic non-free
EOF
	[ -n "$1" ] && exit "$1" || exit
}

phashstuff()
{
	local htype="$1"; shift
	local path="$1"; shift
	local name="$1"; shift
	local size="$(stat -c "%s" "$path")"
	local hash="$("$htype" "$path" | cut -f1 -d" ")"

	printf " %s %s %s\n" "$hash" "$size" "$name"
}

TEMP=`getopt -n $PROG -o vhs -l help,basedir:,mapi,listonly,bz2only,compressedonly,hashonly,updateinfo:,bloat,no-scan,topdir:,sign,default-key:,progress,verbose,silent,oldhashfile,newhashfile,no-oldhashfile,no-newhashfile,partial,flat,create,origin:,label:,suite:,codename:,architectures:,description:,archive:,version:,architecture:,notautomatic:,disable-hash-caching,cachedir:,useful-files:,changelog-since:,patch-basedir,prev-basedir:,add-list:,rm-list:,preferred-prev_compression: \
	-l bz2,no-bz2,xz,no-xz,zst,zstd,no-zst,no-zstd,no-compression,maybe-unchanged \
	-l blake2b,no-blake2b -- "$@"` || USAGE 1
eval set -- "$TEMP"

while :; do
	case "$1" in
		--listonly) shift; listonly=1
			;;
		--basedir) shift; basedir_="$1"; shift
			;;
		--bz2only) shift; compressedonly=1	# legacy option
			;;
		--compressedonly) shift; compressedonly=1
			;;
		--hashonly) shift; hashonly=1
			;;
		-s|--sign) shift; signature=1
			;;
		--bloat) shift; bloat="--bloat"
			;;
		--no-scan) shift; noscan="--no-scan"
			;;
		--mapi) shift; mapi="--mapi"
			;;
		--updateinfo) shift; updateinfo="$1"; shift
			;;
		--default-key) shift; defaultkey="$1"; shift
			;;
		--topdir) shift; topdir="$1"; shift
			;;
		--flat) shift; flat="--flat"
			;;
		--progress) shift; progress="--progress"; verbose=1
			;;
		-v|--verbose) shift; verbose=1
			;;
		--silent) shift; verbose=
			;;
		--partial) shift; partial=1
			;;
		--oldhashfile)		shift ;;	# legacy option
		--no-oldhashfile)	shift ;;	# legacy option
		--newhashfile)		shift ;;	# legacy option
		--no-newhashfile)	shift ;;	# legacy option
		-h|--help) USAGE 0
			;;
		--create) shift; create=1
			;;
		--origin) shift; origin="$1"; shift
			;;
		--label) shift; label="$1"; shift
			;;
		--suite) shift; suite="$1"; shift
			;;
		--codename) shift; codename="$1"; shift
			;;
		--architectures) shift; architectures="$1"; shift;
			;;
		--description) shift; description="$1"; shift;
			;;
		--archive) shift; archive="$1"; shift;
			;;
		--version) shift; version="$1"; shift;
			;;
		--architecture) shift; architecture="$1"; shift;
			;;
		--notautomatic) shift; notautomatic="$1"; shift;
			;;
		--changelog-since) shift
			if ! changelog_since="$(date -d "$1" +%s)" || [ "$changelog_since" -le 0 ]; then
				Fatal "invalid --changelog-since date: $1"
			fi
			shift ;;
		--disable-hash-caching) shift; disable_hash_caching=1 ;;
		--cachedir) shift; cachedir="$1"; disable_hash_caching=; shift;
			;;
		--useful-files) shift; useful_files="$1"; shift;
			;;
		--patch-basedir) shift; patch_basedir=1 ;;
		--prev-basedir) shift; patch_basedir=1; prev_basedir="$1"; shift;
			;;
		--preferred-prev-compression) shift
			preferred_prev_compression="$(echo "$1" | tr ',' ' ')"
			shift ;;
		--add-list) shift; add_list="$1"; shift;
			;;
		--rm-list) shift; rm_list="$1"; shift;
			;;
		--blake2b) shift; add_blake2b=1 ;;
		--no-blake2b) shift; add_blake2b= ;;
		--no-compression) shift; make_bz2=; make_xz=; make_zst= ;;
		--bz2) shift; make_bz2=1 ;;
		--no-bz2) shift; make_bz2= ;;
		--xz) shift; make_xz=1 ;;
		--no-xz) shift; make_xz= ;;
		--zst|--zstd) shift; make_zst=1 ;;
		--no-zst|--no-zstd) shift; make_zst= ;;
		--maybe-unchanged) shift; maybe_unchanged=1 ;;
		--) shift; break
			;;
		*) echo "$PROG: unrecognized option: $1" >&2; exit 1
			;;
	esac
done

if [ -n "$compressedonly" ] && [ -z "$make_xz$make_bz2$make_zst" ]; then
    Fatal '--compressed-only option is specified, but all compression types are disabled'
fi

topdir="`echo -n "$topdir" |tr -s /`"

[ -n "$topdir" ] || Fatal 'TOPDIR not specified.'

if [ -n "$prev_basedir" ]; then
	cd "$prev_basedir" || Fatal "Invalid --prev-basedir specified: $prev_basedir"
fi

cd "$topdir" || Fatal "Invalid TOPDIR specified: $topdir"

# this will fix the path if it was relative
topdir="$(pwd)"

distro="$(echo "$1" | tr -s /)"
shift

components="$*"

[ -n "${basedir_##*/*}" ] ||
	Fatal '--basedir argument is expected to be a directory name'

basedir="$topdir/$distro/$basedir_"

pkglist=$basedir/pkglist
srclist=$basedir/srclist
release=$basedir/release

if [ -z "$flat" ]; then
	srctopdir=`cd "$topdir/$distro"/..; pwd`
else
	srctopdir=`cd "$topdir/$distro"; pwd`
fi

WORKDIR=
exit_handler()
{
	[ -z "$WORKDIR" ] || rm -rf -- "$WORKDIR"
	exit "$1"
}
trap 'exit_handler $?' EXIT
trap 'exit 143' HUP PIPE INT QUIT TERM
WORKDIR="$(mktemp -dt "$PROG.XXXXXXXXXX")" || exit

if [ -n "$add_list" ]; then
	if [ ! -f "$add_list" ]; then
		Fatal "Specified add-list $add_list is not a file"
	else
		LC_ALL=C sort -u "$add_list" -o "$WORKDIR"/add-list
	fi
fi

if [ -n "$rm_list" ]; then
	if [ ! -f "$rm_list" ]; then
		Fatal "Specified rm-list $rm_list is not a file"
	else
		LC_ALL=C sort -u "$rm_list" -o "$WORKDIR"/rm-list
	fi
fi


if [ ! -d "$basedir" ]; then
	if [ -n "$create" ]; then
		Verbose -n 'Creating base directory... '
		if ! mkdir -p "$basedir" >/dev/null 2>&1; then
			Fatal 'Unable to create base directory'
		fi
		Verbose 'done'
	else
		Fatal 'Base directory does not exist!'
	fi
fi

if [ -z "$components" ]; then
	# Try to guess components
	comps="$WORKDIR"/components
	: >"$comps"
	for dir in "$topdir/$distro"/RPMS.* $srctopdir/SRPMS.*; do
		if [ -d "$dir" ]; then
			echo "$dir" | sed 's/.*\.//' >> "$comps"
		fi
	done
	components=`sort "$comps" | uniq`
	components=`echo $components` # eat newlines
	rm -f "$comps"
fi

if [ -z "$components" ]; then
	Fatal 'No components found'
else
	Verbose "Components: $components"
fi

saved_list=

save_file()
{
	saved_list="$1"

	if [ -f "$saved_list" ]; then
		mv -f "$saved_list" "$saved_list.old"
	else
		saved_list=
	fi
}

compare_file()
{
	if [ -n "$saved_list" ] && [ -f "$saved_list.old" ]; then
		if cmp -s "$saved_list.old" "$saved_list"; then
			mv -f "$saved_list.old" "$saved_list"
		else
			rm -f "$saved_list.old"
		fi
	fi
}

compress_file()
{
	local filesize halfsize pid pxz=

	rm -f "$1.xz" "$1.yz"
	if [ -n "$make_xz" ]; then
		filesize=$(stat -c '%s' "$1")
		if [ "$filesize" -ge $((4*8*1024*1024)) ]; then
			# The file is large enough (as compared to typical dictionary size).
			# Note that .xz files can be concatenated, so it's nice to have
			# 2-way parallel compression here.
			pxz=1
		fi
		if [ -n "$pxz" ]; then
			halfsize=$(($filesize/2))
			dd if="$1" bs="$halfsize" count=1 2>/dev/null |xz >"$1.xz" & pid=$!
			dd if="$1" bs="$halfsize"  skip=1 2>/dev/null |xz >"$1.yz"
			wait "$pid"
			cat "$1.yz" >>"$1.xz"
			rm -f "$1.yz"
		else
			xz -k "$1"
		fi &
	fi

	rm -f "$1.bz2"
	if [ -n "$make_bz2" ]; then
		if [ -n "$pxz" ]; then
			bzip2 -k "$1"
		else
			# Assuming non-parallel xz is expensive...
			nice bzip2 -k "$1"
		fi &
	fi

	rm -f "$1".zst
	if [ -n "$make_zst" ]; then
		zstd -q "$1"
	fi &
}

if [ -n "$cachedir" ] && [ -z "$disable_hash_caching" ]; then
	mkdir -p "$cachedir/genpkglist" "$cachedir/gensrclist"
fi

choose_prev_list() {
	if [ -z "$patch_basedir" ]; then
		printf ':'
		return
	fi

	local from_basedir="$1"; shift
	local list="$1"; shift
	local component="$1"; shift

	local path="${from_basedir:-$basedir}/$list.$component"

	for compr in $preferred_prev_compression; do
		case "$compr" in
			zst|zstd)
				if [ -s "$path".zst ]; then
					printf 'zstd -d < %q' "$path".zst
					return
				fi
				;;
			none)
				# The output file which is about to be written to.
				local -r output_file="$basedir/$list.$component"
				touch "$output_file" # prereq for the -ef check
				if [ "$path" -ef "$output_file" ]; then
					# We shouldn't read from $output_file. But if it was saved
					# (only $basedir/$list.$component could have been saved),
					# then the data we need is there. (And there is no need to
					# look for other (compressed) variants.)
					if [ -n "$saved_list" ]; then
						printf 'cat %q' "$saved_list".old
						return
					fi
				else
					if [ -e "$path" ]; then
						printf 'cat %q' "$path"
						return
					fi
				fi
				;;
			xz)
				if [ -s "$path".xz ]; then
					printf 'xz -d < %q' "$path".xz
					return
				fi
				;;
			bz2)
				if [ -s "$path".bz2 ]; then
					printf 'bzip2 -d < %q' "$path".bz2
					return
				fi
				;;
		esac
	done
}

if [ -z "$hashonly" ]; then
	Verbose -n 'Processing packages...'

	for comp in $components; do
		comp_add_list=
		comp_add_list_src=
		comp_rm_list=
		comp_rm_list_src=
		if [ -s "$WORKDIR"/add-list ]; then
			sed -r -n "s/^$comp\t//p" "$WORKDIR"/add-list > \
				"$WORKDIR"/add-list.$comp
			cut -f1 "$WORKDIR"/add-list.$comp | sort -u > \
				"$WORKDIR"/add-list.src.$comp
		fi
		if [ -s "$WORKDIR"/rm-list ]; then
			sed -r -n "s/^$comp\t//p" "$WORKDIR"/rm-list > \
				"$WORKDIR"/rm-list.$comp
			cut -f1 "$WORKDIR"/rm-list.$comp | sort -u > \
				"$WORKDIR"/rm-list.src.$comp
		fi
		if [ -s "$WORKDIR"/add-list.$comp ]; then
			comp_add_list="$WORKDIR"/add-list.$comp
			comp_add_list_src="$WORKDIR"/add-list.src.$comp
		fi
		if [ -s "$WORKDIR"/rm-list.$comp ]; then
			comp_rm_list="$WORKDIR"/rm-list.$comp
			comp_rm_list_src="$WORKDIR"/rm-list.src.$comp
		fi

		SRCIDX_COMP="$WORKDIR/$comp"

		# pkglist
		if [ ! -d "$topdir/$distro/RPMS.$comp" ]; then
			# remove stale lists
			rm -f "$pkglist.$comp" "$pkglist.$comp".{bz2,xz,zst}
			rm -f "$srclist.$comp" "$srclist.$comp".{bz2,xz,zst}
			continue
		fi
		Verbose -n " RPMS.$comp"
		save_file "$pkglist.$comp"
		cat_prev_list_if_patching="$(choose_prev_list "$prev_basedir" pkglist "$comp")" ||
			Fatal 'Failed to find the previous pkglist, but patching it was requested.'
		eval "$cat_prev_list_if_patching" |
			if ! genpkglist $progress $bloat $noscan \
					--index "$SRCIDX_COMP" \
					${patch_basedir:+--prev-stdin} \
					${comp_add_list:+--add-list "$comp_add_list"} \
					${comp_rm_list:+--rm-list "$comp_rm_list"} \
					--basedir "$basedir_" \
					${updateinfo:+--info "$updateinfo"} \
					${add_blake2b:+--blake2b} \
					${disable_hash_caching:+--disable-hash-caching} \
					${cachedir:+--cachedir "$cachedir"} \
					${useful_files:+--useful-files "$useful_files"} \
					${changelog_since:+--changelog-since "$changelog_since"} \
					"$topdir/$distro" "$comp"; then
				Verbose
				Fatal 'Error executing genpkglist.'
			fi
		compare_file
		if [ -n "$maybe_unchanged" ]; then
			htype=md5sum
			[ -z "$add_blake2b" ] ||
				htype=b2sum
			hash=$(phashstuff "$htype" "$pkglist.$comp" "base/pkglist.$comp")
			if LC_ALL=C grep -F -qs -x "$hash" "$release"; then
				Verbose "pkglist.$comp is unchanged"
				continue
			else
				Verbose "pkglist.$comp is going to be changed despite --maybe-unchanged"
			fi
			unchanged=
		fi
		compress_file "$pkglist.$comp"

		# srclist
		if [ ! -d "$srctopdir/SRPMS.$comp" ]; then
			# remove stale lists
			rm -f "$srclist.$comp" "$srclist.$comp".{bz2,xz,zst}
			continue
		fi
		save_file "$srclist.$comp"
		cat_prev_list_if_patching="$(choose_prev_list "$prev_basedir" srclist "$comp")" ||
			Fatal 'Failed to find the previous srclist, but patching it was requested.'
		eval "$cat_prev_list_if_patching" |
			if ! gensrclist $progress $flat $mapi \
					${patch_basedir:+--prev-stdin} \
					${comp_add_list_src:+--add-list "$comp_add_list_src"} \
					${comp_rm_list_src:+--rm-list "$comp_rm_list_src"} \
					--basedir "$basedir_" \
					${add_blake2b:+--blake2b} \
					${disable_hash_caching:+--disable-hash-caching} \
					${cachedir:+--cachedir "$cachedir"} \
					"$topdir/$distro" "$comp" "$SRCIDX_COMP"; then
				Verbose
				Fatal 'Error executing gensrclist.'
			fi
		compare_file
		if [ -n "$maybe_unchanged" ]; then
			htype=md5sum
			[ -z "$add_blake2b" ] ||
				htype=b2sum
			hash=$(phashstuff "$htype" "$srclist.$comp" "base/srclist.$comp")
			if LC_ALL=C grep -F -qs -x "$hash" "$release"; then
				Verbose "$srclist.$comp is unchanged"
				continue
			else
				Verbose "$srclist.$comp is going to be changed despite --maybe-unchanged"
			fi
			unchanged=
		fi
		compress_file "$srclist.$comp"

	done
	Verbose ' done'

	Verbose -n 'Waiting for bzip2 and xz to finish...'
	wait
	Verbose ' done'
fi

remove_uncompressed()
{
	if [ -n "$compressedonly" ]; then
		for comp in $components; do
			rm -f "$pkglist.$comp" "$srclist.$comp"
		done
	fi
}

if [ -n "$maybe_unchanged" ] && [ -n "$unchanged" ]; then
	remove_uncompressed
	Verbose "release is unchanged"
	exit 0
fi

phash()
{
	local htype="$1"; shift
	local path="$1"; shift
	local name="$1"; shift
	local outfile="$1"; shift

	if [ -f "$path" ]; then
		phashstuff "$htype" "$path" "$name" >> "$outfile"
	fi
}

print_hashes()
{
	local htype="$1"; shift
	local outfile="$1"; shift

	phash "$htype" "$pkglist.$comp" "base/pkglist.$comp" "$outfile"
	phash "$htype" "$srclist.$comp" "base/srclist.$comp" "$outfile"
	phash "$htype" "$pkglist.$comp.bz2" "base/pkglist.$comp.bz2" "$outfile"
	phash "$htype" "$srclist.$comp.bz2" "base/srclist.$comp.bz2" "$outfile"
	phash "$htype" "$pkglist.$comp.xz" "base/pkglist.$comp.xz" "$outfile"
	phash "$htype" "$srclist.$comp.xz" "base/srclist.$comp.xz" "$outfile"
	phash "$htype" "$pkglist.$comp.zst" "base/pkglist.$comp.zst" "$outfile"
	phash "$htype" "$srclist.$comp.zst" "base/srclist.$comp.zst" "$outfile"
	phash "$htype" "$release.$comp" "base/release.$comp" "$outfile"
}

# Create hashfile
if [ -z "$listonly" ]; then
	Verbose -n 'Creating component releases...'
	for comp in $components; do
		Verbose -n " $comp"
		save_file "$release.$comp"
		cat > "$release.$comp" <<- __EOF__
			Archive: $archive
			Component: $comp
			Version: $version
			Origin: $origin
			Label: $label
			Architecture: $architecture
			NotAutomatic: $notautomatic
		__EOF__
		compare_file
	done
	Verbose ' done'

	Verbose -n 'Updating global release file... '
	save_file "$release"
	if [ -f "$release" ] && [ -n "$partial" ]; then
		sed -n -e "/^\$/q" \
			-e "s/^Date:.*\$/Date: $date/" \
			-e "p" "$release.old" > "$release.pre"
		for comp in $components; do
			sed -e "\#^ .* base/pkglist.$comp\(.bz2\)\?\$#d" \
			    -e "\#^ .* base/srclist.$comp\(.bz2\)\?\$#d" \
			    -e "\#^ .* base/release.$comp\(.bz2\)\?\$#d" \
			    -e "\#^ .* base/pkglist.$comp\(.xz\)\?\$#d" \
			    -e "\#^ .* base/srclist.$comp\(.xz\)\?\$#d" \
			    -e "\#^ .* base/release.$comp\(.xz\)\?\$#d" \
			    -e "\#^ .* base/pkglist.$comp\(.zst\)\?\$#d" \
			    -e "\#^ .* base/srclist.$comp\(.zst\)\?\$#d" \
			    -e "\#^ .* base/release.$comp\(.zst\)\?\$#d" \
			    -e "s/^\(Components:.*\) $comp\(.*\)\$/\1\2/" \
				"$release.pre" > "$release.tmp"
			mv -f "$release.tmp" "$release.pre"
		done
		sed -e "s/^\(Components:.*\)\$/\1 $components/" \
			"$release.pre" > "$release"
		rm -f "$release.pre"
	else
		cat > "$release" <<- __EOF__
			Origin: $origin
			Label: $label
			Suite: $suite
			Codename: $codename
			Date: `date -R`
			Architectures: $architectures
			Components: $components
			Description: $description
		__EOF__
	fi
	compare_file
	Verbose 'done'

	Verbose -n 'Appending MD5Sum...'
	echo 'MD5Sum:' >> "$release"
	for comp in $components; do
		Verbose -n " $comp"
		print_hashes md5sum "$release"
	done
	Verbose ' done'

	if [ -n "$add_blake2b" ]; then
		Verbose -n 'Appending BLAKE2b...'
		echo 'BLAKE2b:' >> "$release"
		for comp in $components; do
			Verbose -n " $comp"
			print_hashes b2sum "$release"
		done
		Verbose ' done'
	fi

	echo >> "$release"

	if [ -n "$signature" ]; then
		if [ -n "$defaultkey" ]; then
			gpg -armour --quiet --detach-sign --yes --default-key "$defaultkey" "$release"
		else
			gpg -armour --quiet --detach-sign --yes "$release"
		fi

		cat "$release.asc" >>"$release"
		rm -f "$release.asc"
	fi

	# Compare with older release
	compare_file
fi

remove_uncompressed

Verbose 'All your base are belong to us!!!'

# vim:ts=4:sw=4
