#!/bin/sh
#
#    $Revision: 1.2 $
#
# rpmpatch
#    Perform a patch on an src rpm file rebuilding the new patched src rpm.
#    - this script is only intended to work on src rpms.
#
# Copyright (C) 2005 Simon J. Mudd (sjmudd@pobox.com)
#
#    Newer versions of this script may be made available at:
#        http://ftp.wl0.org/rpmdiff
#
# Usage: rpmpatch <patchfile> [<originalrpm>] [<newrpm>]
#
#        patchfile is the file containing the patches (from rpmdiff).
#        originalrpm is the unpatched src rpm
#        newrpm is the newly created src rpm (built to $pwd)
#
# Exit Status
#    As patch 0 = ok, otherwise trouble.
#
# License:
#    This program 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 program 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 may have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
#    USA.
#
#    An on-line copy of the GNU General Public License can be found
#    http://www.fsf.org/copyleft/gpl.html.

[ -n "$DEBUG" ] && set -x
myname=$(basename $0)
myversion=$(echo '$Id: rpmpatch,v 1.2 2005/01/08 20:10:32 sjmudd Exp $' | awk '{ print $3 }')

# fatal error and stop
msg_fatal () {
	echo "FATAL: $*" >&2
	exit 1
}

# standard message
msg_info () {
	echo "$*"
}

# extract rpm to path, ensure destination directory does not exist.
extract_rpm () {
	local local_rpm="$1"
	local local_dir="$2"

	[ "${local_rpm}" = "${local_dir}" ] || {
		[ -d "${local_dir}" ] && msg_fatal "directory ${local_dir} already exists"
		msg_info "Extracting files from $(basename ${local_dir})"
		( mkdir ${local_dir} && cd ${local_dir} && rpm2cpio ${local_rpm} | cpio -im --quiet) ||\
			msg_fatal "problem extracting ${local_rpm}"
	}
}

# remove temporary directory
remove_rpmdir () {
	local local_dir="$1"

	msg_info "Removing ${local_dir}"
	[ -d ${local_dir} ] || msg_fatal "${local_dir} is not a directory"
	rm -rf ${local_dir} || msg_fatal "problems removing ${local_dir}"
}

# generate macro contents based on repo name
# - this is only from src rpms so don't worry too much about it's contents
# - provide the old file if any so we can restore it later
generate_rpmmacros_file () {
	local srpmdir="$1"
	local rpmmacros=$HOME/.rpmmacros
	local tmpdir=${TMPDIR:-/tmp}
	local backup

	# backup file if needed
	[ -f ${rpmmacros} ] && \
		backup=$HOME/.rpmmacros.backup.$(date +%y%m%d.%H%M%S) && \
		mv ${rpmmacros} ${backup}

	cat <<-EOF > ${rpmmacros}
	# Temporary RPM macros configuration file used by $myname.
	%_sourcedir     ${srpmdir}
	%_specdir       ${srpmdir}
	%_tmppath       ${tmpdir}
	# build the rpm into this directory
	%_srcrpmdir     ${PWD}
	EOF
	echo ${backup}
}

build_srpm () {
	local sdir="$1"
	local srpm="$2"

	msg_info "generating ${srpm}"
	local backup=$(generate_rpmmacros_file ${sdir})

	# assume only one spec file!
	rpmbuild --nodeps -bs $sdir/*.spec

	# return the rpmmacros file back to it's location
	[ -f "${backup}" ] && mv ${backup} $HOME/.rpmmacros
}

[ $# = 1 -o $# = 2 -o $# = 3 ] || msg_fatal "usage: rpmpatch <patchfile> [<fromrpm>] [<torpm>]"

patch_file="$1"
from_rpm="$2"
to_rpm="$3"
patchoptions=
tmpdir=${TMPDIR:-/tmp}

# check the patchfile
[ -n "${patch_file}" ] || msg_fatal "empty <patchfile> given"
[ -f "${patch_file}" ] || msg_fatal "${patch_file} not found"

# determine the from_rpm
if [ -z ${from_rpm} ]; then
	# try and determine the from_rpm from the patch file
	# - look for
	#diff -uNr /tmp/postfix-2.0.16-13.RHEL3.src.rpm/postfix.spec /tmp/postfix-2.0.16-14.RHEL3.src.rpm/postfix.spec
	# and return postfix-2.0.16-13.RHEL3.src.rpm
	# this won't work if we have subdirectories in the system!
	from_rpm=$(awk '$1 == "diff" { print $3 }' ${patch_file} | head -1)
	from_rpm=$(dirname $from_rpm)
	from_rpm=$(basename $from_rpm)
	msg_info "Assuming <from_rpm> is $from_rpm"
fi

# determine the to_rpm
if [ -z ${to_rpm} ]; then
	# try and determine the to_rpm from the patch file
	# - look for
	#diff -uNr /tmp/postfix-2.0.16-13.RHEL3.src.rpm/postfix.spec /tmp/postfix-2.0.16-14.RHEL3.src.rpm/postfix.spec
	# and return postfix-2.0.16-14.RHEL3.src.rpm
	# this won't work if we have subdirectories in the system!
	to_rpm=$(awk '$1 == "diff" { print $4 }' ${patch_file} | head -1)
	to_rpm=$(dirname $to_rpm)
	to_rpm=$(basename $to_rpm)
	msg_info "Assuming <to_from> is $to_rpm"
fi

# now check the results
[ -n "${from_rpm}" ] || msg_fatal "empty <from_rpm>"
[ -f "${from_rpm}" ] || msg_fatal "${from_rpm} not found or is not a file"

[ -n "${to_rpm}" ] || msg_fatal "empty rpm <to_rpm>"
[ -e ${to_rpm} ] && msg_fatal "<to_rpm> already exists"

# ready to extract from_rpm


#exit
#
#&& to_dir=${tmpdir}/$(basename ${to_rpm})
#[ -f ${to_rpm} ] && to_dir=${tmpdir}/$(basename ${to_rpm})
#[ -d ${to_rpm} ] && to_dir=${to_rpm}
#[ -n ${to_dir} ] || msg_fatal "can not find rpm ${to_rpm} (and not a directory)"

# generate location of the extracted rpm

[ -f ${from_rpm} ] && from_dir=${tmpdir}/$(basename ${from_rpm})
[ -d ${from_rpm} ] && from_dir=${from_rpm}
[ -n ${from_dir} ] || msg_fatal "can not find rpm ${from_rpm} (and not a directory)"

# extract the rpm
extract_rpm ${from_rpm} ${from_dir}

# patch the rpm directory
cat ${patch_file} | {
	cd ${from_dir}
	patch -i- 
}
rc=$?

if [ $rc = 0 ]; then
	# patch went ok so attempt to rebuild src.rpm
	# the ${to_rpm} may not actually be created as it depends on rpmbuild
	build_srpm ${from_dir} ${to_rpm}
	rc=$?
	[ -f "${to_rpm}" ] || msg_fatal "${to_rpm} not found! PLEASE INVESTIGATE"
fi

# remove the temporary directory
remove_rpmdir ${from_dir}

# provide the exit result 
exit $rc
