#!/usr/bin/bash
#
# Copyright 2013 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#
# Builds an rpm out of command line options
#
# $Id$

PATH=$PATH:/usr/bin

NAME=useless
EPOCH=
VERSION=1.0.0
RELEASE=1
ARCH=noarch
GROUP="Applications/System"
SUMMARY="Dummy package"
DESCRIPTION="The package description"
PACKAGER="(none)"
VENDOR="(none)"

usage() {
    echo "Usage:"
    echo "$0 [OPTIONS] [FILES]"
    echo "Builds an rpm from the specified command line options, optionally"
    echo "including files"
    echo
    echo "  OPTIONS:"
    echo "    --help          display usage and exit"
    echo "    --name          use this name for the rpm [$NAME]"
    echo "    --epoch         use this epoch [default is null]"
    echo "    --version       use this version [$VERSION]"
    echo "    --release       use this release [$RELEASE]"
    echo "    --arch          build the package for this arch [$ARCH]"
    echo "    --group         group this package belongs [$GROUP]"
    echo "    --packager      packager [$PACKAGER]"
    echo "    --vendor        vendor [$VENDOR]"
    echo "    --summary       package summary"
    echo "    --description   package description"
    echo "    --requires      make the generated rpm require this"
    echo "    --provides      make the generated rpm provide this"
    echo "    --conflicts     make the generated rpm conflict with this"
    echo "    --obsoletes     make the generated rpm obsolete with this"
    echo "    --buildreq      make the generated source rpm require this to build"
    echo "    --post          path to a postinstall script"
    echo "    --pre           path to a preinstall script"
    echo "    --postun        path to a post-uninstall script"
    echo "    --preun         path to a pre-uninstall script"
    echo
    echo "  FILES: <file-spec>*"
    echo "    <file-spec> ::== <dest-path>[:mode]=<source-path>"
    echo "      adds <source-path> in the RPM package, at <dest-path>"
    echo "      NOTE: <dest-path> has to be a filename"
    echo
    echo "Example:"
    echo "  $0 --name useless --version 0.99 --release 1 /var/foo=/var/log/messages"
    exit $1
}

ensure_file_exists() {
    file=$1
    sectname=$2

    if [ "$file" -a ! -s "$file" ]; then
        echo "Cannot read $sectname section from $file"
        exit -1
    fi

}

# Generates the post/pre/postun/preun sections
generate_section() {
    file=$1
    sectname=$2
    if [ "$file" ]; then
        echo "%$sectname"
        cat $file
        echo
    fi
}

# Builds the requires/provides/conflicts/obsoletes
generate_depend_section() {
    sectname=$1
    shift
    while [ "$1" ]; do
        val=$1
        shift
        echo "$sectname: $val"
    done | sort | uniq
}

# Array we use for grabbing the files
declare -a PARAMS
declare -a REQUIRES
declare -a PROVIDES
declare -a CONFLICTS
declare -a OBSOLETES
declare -a BUILDREQS

POST=""
PRE=""
POSTUN=""
PREUN=""

while true; do
    case "$1" in
        --help)
            usage 0
            ;;
        --name)
            case "$2" in
                "") echo "No parameter specified for --name"; break;;
                *)  NAME=$2; shift 2;;
            esac;;
        --epoch)
            case "$2" in
                "") echo "No parameter specified for --epoch"; break;;
                *)  EPOCH=$2; shift 2;;
            esac;;
        --version)
            case "$2" in
                "") echo "No parameter specified for --version"; break;;
                *)  VERSION=$2; shift 2;;
            esac;;
        --release)
            case "$2" in
                "") echo "No parameter specified for --release"; break;;
                *)  RELEASE=$2; shift 2;;
            esac;;
        --arch)
            case "$2" in
                "") echo "No parameter specified for --arch"; break;;
                *)  ARCH=$2; shift 2;;
            esac;;
        --group)
            case "$2" in
                "") echo "No parameter specified for --group"; break;;
                *)  GROUP=$2; shift 2;;
            esac;;
        --summary)
            case "$2" in
                "") echo "No parameter specified for --summary"; break;;
                *)  SUMMARY=$2; shift 2;;
            esac;;
        --description)
            case "$2" in
                "") echo "No parameter specified for --description"; break;;
                *)  DESCRIPTION=$2; shift 2;;
            esac;;
        --packager)
            case "$2" in
                "") echo "No parameter specified for --packager"; break;;
                *)  PACKAGER=$2; shift 2;;
            esac;;
        --vendor)
            case "$2" in
                "") echo "No parameter specified for --vendor"; break;;
                *)  VENDOR=$2; shift 2;;
            esac;;
        --post)
            case "$2" in
                "") echo "No parameter specified for --post"; break;;
                *)  POST=$2; shift 2;;
            esac;;
        --pre)
            case "$2" in
                "") echo "No parameter specified for --pre"; break;;
                *)  PRE=$2; shift 2;;
            esac;;
        --postun)
            case "$2" in
                "") echo "No parameter specified for --postun"; break;;
                *)  POSTUN=$2; shift 2;;
            esac;;
        --preun)
            case "$2" in
                "") echo "No parameter specified for --preun"; break;;
                *)  PREUN=$2; shift 2;;
            esac;;
        --requires)
            case "$2" in
                "") echo "No parameter specified for --requires"; break;;
                *)  REQUIRES[${#REQUIRES[*]}]=$2; shift 2;;
            esac;;
        --provides)
            case "$2" in
                "") echo "No parameter specified for --provides"; break;;
                *)  PROVIDES[${#PROVIDES[*]}]=$2; shift 2;;
            esac;;
        --conflicts)
            case "$2" in
                "") echo "No parameter specified for --conflicts"; break;;
                *)  CONFLICTS[${#CONFLICTS[*]}]=$2; shift 2;;
            esac;;
        --obsoletes)
            case "$2" in
                "") echo "No parameter specified for --obsoletes"; break;;
                *)  OBSOLETES[${#OBSOLETES[*]}]=$2; shift 2;;
            esac;;
        --buildreq)
            case "$2" in
                "") echo "No parameter specified for --buildreq"; break;;
                *)  BUILDREQ[${#BUILDREQ[*]}]=$2; shift 2;;
            esac;;
        "") break;;
        *)
            ftwo=`echo $1 | (read -n 2 foo; echo $foo)`
            if [ $ftwo == '--' ]; then
                echo "Unknown option $1"
                usage 1
            fi
            PARAMS[${#PARAMS[*]}]=$1
            shift
    esac
done

ensure_file_exists "$PRE" "pre"
ensure_file_exists "$POST" "post"
ensure_file_exists "$PREUN" "preun"
ensure_file_exists "$POSTUN" "postun"

# End of the command-line processing stage

RPM_BUILD_DIR=/tmp/$NAME-$VERSION-build
DIRNAME=$NAME-$VERSION
TARBALL=$NAME-$VERSION.tar.gz

echo "Building $NAME-$VERSION-$RELEASE.$ARCH.rpm"

rm -rf $RPM_BUILD_DIR
install --verbose -d $RPM_BUILD_DIR/$DIRNAME

# Prepare the tar file
i=0
while [ $i -lt ${#PARAMS[*]} ]; do
    echo ${PARAMS[$i]} | (
        IFS== read dstmod src
        echo ${dstmod} | (IFS=: read dst mod
            echo "${src} -> ${RPM_BUILD_DIR}/${DIRNAME}/${dst}"
            mkdir --parents --verbose ${RPM_BUILD_DIR}/${DIRNAME}/`dirname "${dst}"`; cp ${src} ${RPM_BUILD_DIR}/${DIRNAME}/${dst}
        )
    )
    i=$[$i+1]
done

# Build the install section
installsect=`i=0
while [ $i -lt ${#PARAMS[*]} ]; do
    echo ${PARAMS[$i]} | (
        IFS== read dstmod src
        echo ${dstmod} | (IFS=: read dst mod
            echo "install --verbose -d \\\$RPM_BUILD_ROOT\`dirname ${dst}\`"
            echo "install --verbose .${dst} \\\$RPM_BUILD_ROOT${dst}")
    )
    i=$[$i+1]
done | sort | uniq | while read line; do echo -n "$line\n"; done`

# Build the file section
filesect=`i=0
while [ $i -lt ${#PARAMS[*]} ]; do
    echo ${PARAMS[$i]} | (
        IFS== read dstmod src
        echo ${dstmod} | (IFS=: read dst mod
            # Now split mod into the actual mode, the user and the group
            # Default to 0644,-,-
            # NOTE there's already a %defattr(-,root,root), so if there's no u
            # or g defined, set it to '-' by default
            echo $mod | (IFS=, read m u g
                echo "%attr(${m:-0644},${u:--},${g:--}) ${dst}"
            )
        )
    )
    i=$[$i+1]
done | sort | uniq | while read line; do echo -n "$line\n"; done`

cat > $RPM_BUILD_DIR/$DIRNAME/$NAME.spec << EOF
Name: $NAME
$(if [ -n "$EPOCH" ]; then echo "Epoch: $EPOCH"; fi)
Version: $VERSION
Release: $RELEASE
Group: $GROUP
License: GPL
BuildArch: $ARCH
Source: %{name}-%{version}.tar.gz
BuildRoot: /var/tmp/%{name}-%{version}-root
Summary: $SUMMARY
Packager: $PACKAGER
Vendor: $VENDOR
`generate_depend_section Requires "${REQUIRES[@]}"`
`generate_depend_section Provides "${PROVIDES[@]}"`
`generate_depend_section Conflicts "${CONFLICTS[@]}"`
`generate_depend_section Obsoletes "${OBSOLETES[@]}"`
`generate_depend_section BuildRequires "${BUILDREQ[@]}"`

%description
`echo -e $DESCRIPTION`

%prep
%setup

%build

%install
rm -rf \$RPM_BUILD_ROOT
install -d \$RPM_BUILD_ROOT
`echo -e $installsect`

%clean
rm -rf \$RPM_BUILD_ROOT

`generate_section "$POST" post`
`generate_section "$PRE" pre`
`generate_section "$POSTUN" postun`
`generate_section "$PREUN" preun`

%files
`echo -e $filesect`
EOF

# Build the tarball
(cd $RPM_BUILD_DIR; tar cf - $DIRNAME | gzip -c > $RPM_BUILD_DIR/$TARBALL)
rm -rf $RPM_BUILD_DIR/$DIRNAME

# Build the rpm from that tarball
RPMOPTS="--define \"_topdir $RPM_BUILD_DIR\"\
 --define '_builddir    %{_topdir}'\
 --define '_sourcedir   %{_topdir}'\
 --define '_specdir     %{_topdir}'\
 --define '_rpmdir      %{_topdir}'\
 --define '_srcrpmdir   %{_topdir}'\
 --define '_source_payload nil'\
 --define '_binary_payload nil'"

eval "rpmbuild -ta $RPMOPTS --clean $RPM_BUILD_DIR/$TARBALL" || exit 1

mv $RPM_BUILD_DIR/$ARCH/$NAME-$VERSION-$RELEASE.$ARCH.rpm .
mv $RPM_BUILD_DIR/$NAME-$VERSION-$RELEASE.src.rpm .
rm -rf $RPM_BUILD_DIR
