#! /bin/bash

USAGE="--format=srpm [-v] [-f] [--show-spec] [--release=<num>] [<flavour>|source|headers|firmware]

   <flavour>         Package the kernel using the specified flavour
   source            Package the kernel sources
   headers           Package the kernel header files
   firmware          Package the firmware

   --show-spec       Show the generated spec file and exit
   --release         Specify the distribution release number
"

rpm_variety=srpm

source $libexecdir/kdist-package--rpm-common

#
# In any cases we need a temporary directory.
#
cleanup_on_exit () {
	rm -fr $tmpdir
}
trap cleanup_on_exit 0

tmpdir=$(mktemp -d)

say () {
	if test $verbose; then
		echo >&2 $*
	fi
}

package_source () {
	mkdir -p $tmpdir/specfile

	say "Extracting kernel $KERNEL_VERSION$scmversion source code"
	git archive --format=tar --prefix=$uname_r/ HEAD | \
		bzip2 -9 >$tmpdir/$rpm_archive.tar.bz2 &&
	show_spec source >$tmpdir/specfile/$rpm_name.spec &&

	cd $tmpdir &&
	tar -cf  specfile.tar specfile
	rpmbuild -ts specfile.tar
}

package_firmware () {
	mkdir -p $tmpdir/specfile

	# Firmware is not particular for an arch
	make -s INSTALL_MOD_PATH=$tmpdir/$rpm_archive firmware_install &&
	show_spec firmware >$tmpdir/specfile/$rpm_name.spec &&

	cd $tmpdir &&
	tar -cjf $rpm_archive.tar.bz2 $rpm_archive &&
	tar -cf  specfile.tar specfile
	rpmbuild -ts specfile.tar
}

package_headers () {
	mkdir -p $tmpdir/specfile

	say "Extracting kernel $KERNEL_VERSION$scmversion source code"
	git archive --format=tar --prefix=$uname_r/ HEAD | \
		bzip2 -9 >$tmpdir/$rpm_archive.tar.bz2 &&
	show_spec headers >$tmpdir/specfile/$rpm_name.spec &&

	cd $tmpdir &&
	tar -cf  specfile.tar specfile &&
	rpmbuild -ts specfile.tar
}

package_flavour () {
	#
	# uname_r is resolved latter once we'll have a config file at
	# hand.
	#
	uname_r=

	#
	# Extract the kernel source. The prefix used is dictated by
	# how rpm generates the path of the source code from the
	# debuginfo package.
	#
	say "Extracting kernel $KERNEL_VERSION$scmversion source code"
	git archive --format=tar --prefix=uname_r/ HEAD | tar -C $tmpdir -xf - &&

	#
	# List all the configs with the given flavour and with the
	# given revision
	#
	for src
	do
		arch=$(config__get_architecture "$src")
		case $arch in
		x86_64)
			asmarch=x86
			dst=arch/x86/configs/x86_64_defconfig ;;
		i386)
			asmarch=x86
			dst=arch/x86/configs/i386_defconfig ;;
		esac
		rpm_exclusive+="$arch "

		say "Installing $src in $dst"
		dst=$tmpdir/uname_r/$dst
		cp "$src" $dst

		#
		# We insert the distro release number now, assuming
		# that LOCALVERSION is empty.
		#
		config__set_symbol \".$release\" LOCALVERSION $dst

		#
		# Generate the devel file list for this architecture
		#
		if test $with_devel; then
			if ! test -f $tmpdir/uname_r/develfiles-$asmarch.list
			then
				say "Generating '$asmarch' devel file list"
				package__list_arch_devel_files $asmarch\
					>$tmpdir/uname_r/develfiles-$asmarch.list
			fi
		else
			touch $tmpdir/uname_r/develfiles-$asmarch.list
		fi

	done

	#
	# FIXME: to be moved in the sanity checkings part when that
	# will be done
	#
	have_modules=$(config__lookup_symbol MODULES $dst)

	#
	# Use the last installed config to generate the kernel
	# release. Since all configs have the same version stuff
	# settings (localversion_auto, localversion...) this should be
	# ok.
	#
	# Note: 'make kernelrelease' is called twice so we don't get the
	# verbose message sent to stdin(?) "Configuration written to..."
	#
	uname_r=$(
		export KCONFIG_OVERWRITECONFIG=1
		export KCONFIG_CONFIG=$dst
		make -s ARCH=$arch kernelrelease >/dev/null &&
		make -s ARCH=$arch kernelrelease
	) || {
		warn "Failed to retrieve kernel release"
		return
	}

	mv $tmpdir/uname_r $tmpdir/$uname_r
	rpm_archive=kernel-$uname_r
	rpm_exclusive=$(rpm__architecture $rpm_exclusive)

	#
	# Put the spec file in the directory that will be
	# archived. The archive will contain only the spec file...
	#
	if test $spec_only; then
		show_spec vmlinux
		return
	fi

	mkdir -p $tmpdir/specfile &&
        show_spec vmlinux >$tmpdir/specfile/$rpm_name.spec

	#
	# Append other extra files to the archive
	#
	if test $with_devel; then
		say "Generating 'common' devel file list"
		package__list_devel_files >$tmpdir/$uname_r/develfiles.list
	fi &&

	#
	# Since the kernel.tar won't have the git repository for
	# generating the localversion stuff, we generate .scmversion
	# file containing its value so Kbuild can figure it out later.
	#
	if test -e .scmversion; then
		cp .scmversion $tmpdir/$uname_r/
	else
		scripts/setlocalversion --save-scmversion &&
		mv .scmversion $tmpdir/$uname_r/
	fi &&

	#
	# Finally get rid of the unsupported architectures
	#
	cd $tmpdir

	for dir in $(find $uname_r/arch -mindepth 1 -maxdepth 1 -type d)
	do
		asmarch=$(basename $dir)
		if ! test -f $uname_r/develfiles-$asmarch.list; then
			rm -fr $dir
			continue
		fi
		say "Keeping source for '$asmarch' architecture"
	done

	say "Generating $rpm_archive.tar.bz2"
	tar --remove-files -cjf $rpm_archive.tar.bz2 $uname_r &&

	#
	# Weird: pack the spec file in a tarball to make rpmbuild
	# happy. Note that the kernel tarball must be kept out of it.
	#
	say "Creating the source rpm package" &&
	tar cf specfile.tar specfile &&
	rpmbuild -ts specfile.tar
}

#
#
#
release=0
spec_only=
verbose=
force=

while
	case $1 in
	-f|--force)
		force=yes ;;
	-v|--verbose)
		verbose=yes ;;
	--release=*)
		release=${1#*=} ;;
	--show-spec)
		spec_only=yes ;;
	--with-devel)
		with_devel=yes ;;
	--with-debuginfo)
		with_debuginfo=yes ;;
	-*)
		usage ;;
	*)
		break
	esac
do
	shift
done

if test $# -gt 1; then
	usage
fi
target=$1

#
# check the repo validity
#
kdist__cd_kernel_topdir || exit

#
# At that point no .config is needed
#
kdist__setup_kernel_version || exit

rpm_name=kernel-$target
rpm_version=$KERNEL_VERSION_BASE

#
# This is also used by show_spec()
#
scmversion=$(git__scmversion)

#
# For firmware, source and headers targets uname_r is only the kernel
# release (no build number). But we always use the long scmversion for
# path installation, the short version being reserved for the package
# name.
#
uname_r=$KERNEL_VERSION$scmversion
rpm_archive=kernel-$uname_r

#
# rpm_log is used by show_spec: if there's no release information then
# we probably don't need to include the changelog.
#
rpm_log=false
if test $KERNEL_VERSION_PACKAGE; then
	rpm_log=true
fi

case $target in
firmware|headers|source)
	[ $with_debuginfo ] && {
		die "Invalid --with-debuginfo option with '$target'."
	}
	[ $with_devel ] && {
		die "Invalid --with-devel option with '$target'."
	}

	# No need for a build number
	rpm_release=${KERNEL_VERSION_PACKAGE:-0}${scmversion:++}

	if test $spec_only; then
		show_spec $target
		return
	fi
	package_$target
	return
esac

#
# When releasing, we request the current head to be at a tagged
# commit.
#
if test $release -ne 0; then
	if test $scmversion; then
		die "--release wants a tagged commit."
	fi
fi

#
# The rpm release version is different for the <flavour> package since
# it also includes the build version.
#
rpm_release=${KERNEL_VERSION_PACKAGE:-0}.$release${scmversion:++}

# Generate the list of the config files to use
case $target in
'')
	test -f .config ||
		die ".config is missing."

	flavour=$(config__get_flavour .config)
	rpm_name=kernel${flavour:+-$flavour}

	configs=".config" ;;
*)
	if ! test $force && ! configs__check_clean_db; then
		die "Use -f if you really want to use your local changes."
	fi
	configs=$(configs__list_db $KERNEL_VERSION_BASE \* $target)
	if test -z "$configs"; then
		die "Unknown target $target."
	fi
esac &&

#
# FIXME: make some sanity checking on config files here like:
#
#     - LOCALVERSION_AUTO should all have the same value
#     - LOCALVERSION must be empty (used by distro release num)
#     - MODULES should also be the same
#
package_flavour $configs
