#!/bin/bash

# rpmdev-newspec -- generate new rpm .spec file from template
#
# Copyright (c) Warren Togami <warren@togami.com>,
#               Ville Skyttä <ville.skytta@iki.fi>
#
# 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 should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

SPECDIR=/etc/rpmdevtools
DEFTYPE=minimal
DEFSPEC=newpackage.spec
CONFIG=/etc/rpmdevtools/newspec.conf

# Don't load config at rpm build time so it won't affect the man page
if [[ -z $RPM_BUILD_ROOT && -f $CONFIG ]] ; then
    . "$CONFIG"
fi

version()
{
    cat <<EOF
rpmdev-newspec version 2.2

Copyright (c) Warren Togami <warren@togami.com>, Ville Skyttä
<ville.skytta@iki.fi>
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.
EOF
}

help()
{
    cat <<EOF
rpmdev-newspec generates new rpm .spec files from templates.

EOF
    usage
    echo ""
    echo "Report bugs at <https://bugzilla.redhat.com/>, component rpmdevtools,"
    echo "or at <https://fedorahosted.org/rpmdevtools/>."
}

usage() {
    # Don't emit available types at build time to avoid them from being
    # embedded in the man page.
    types=
    if [[ -z $RPM_BUILD_ROOT ]] ; then
        indent="                     "
        types=$(ls $SPECDIR/spectemplate-*.spec 2>/dev/null | \
            sed 's,.*spectemplate-,,;s,\.spec$,,' | tr '\n' ' ' | \
            fmt -w 60 | sed "s/^/$indent/")
        [[ -z $types ]] && types="${indent}None ($SPECDIR/spectemplate-*.spec)"
    fi

    cat <<EOF
Usage: rpmdev-newspec [option]... [appname[.spec]]

Options:
  -o FILE, --output FILE
                 Output the specfile to FILE. "-" means stdout. The default is
                 derived from <appname>, or "$DEFSPEC" if <appname> is
                 not given.
  -t TYPE, --type TYPE
                 Force use of the TYPE spec template. The default is guessed
                 from <appname>, falling back to "$DEFTYPE" if the guesswork
                 does not result in a more specific one or if <appname> is not
                 given.${types:+ Available types:
$types}
  -m, --macros   Emit templates using macros instead of shell style variables.
                 Configuration variable: NEWSPEC_PREFER_MACROS, default is off.
  -r VERSION, --rpm-version VERSION
                 Filter out some spec file constructs not needed by the
                 specified rpm(build) version and newer ones. Configuration
                 variable: NEWSPEC_MIN_RPMVER, default is system rpm version.
  -h, --help     Show this usage message and exit.
  -v, --version  Print version information and exit.

Files:
$SPECDIR
  Directory for specfile templates.
$CONFIG
  System wide configuration.
EOF
}

appname=
specfile=
spectype=
specfile_set=

while [[ $1 ]] ; do
    case $1 in
        -t|--type)
            shift
            spectype="$1"
            ;;
        -o|--output)
            shift
            specfile="$1"
            specfile_set=1
            case $specfile in
                *.spec) [[ -z $appname ]] && appname="$(basename $1 .spec)" ;;
            esac
            ;;
        -m|--macros)
            NEWSPEC_PREFER_MACROS=1
            ;;
        -r|--rpm-version)
            shift
            NEWSPEC_MIN_RPMVER="$1"
            ;;
        -h|--help)
            help
            exit 0
            ;;
        -v|--version)
            version
            exit 0
            ;;
        *.spec)
            [[ -z $specfile ]] && specfile="$1"
            appname="$(basename $1 .spec)"
            ;;
        *)
            appname="$1"
            [[ -z $specfile ]] && specfile="$appname.spec"
            ;;
    esac
    shift
done

rpmmaj=4
rpmmin=4
rpmver="${NEWSPEC_MIN_RPMVER:-$RPMVER}" # RPMVER: 2.0 backwards compat
[[ $rpmver ]] || rpmver=$(rpm --version 2>/dev/null)
if [[ $rpmver =~ (^|.* )([0-9]{1,})(\.([0-9]{1,}))? ]] ; then
    rpmmaj=${BASH_REMATCH[2]}
    rpmmin=${BASH_REMATCH[4]:-0}
else
    echo "Unrecognized rpm version '$rpmver', using $rpmmaj.$rpmmin" \
        > /dev/stderr
fi
# major * 10000 + minor * 100 ( + micro perhaps later )
rpmver=$(( $rpmmaj * 10000 + $rpmmin * 100 ))

specfilter=
if [[ -z $spectype ]] ; then
    case $appname in
        ocaml-*)
            spectype="${appname%%-*}"
            libname="${appname##ocaml-}"
            specfilter="
    s/^%define\\s+libname\\s[^\\n]*\\n//Mg
    s/%\\{libname}/$libname/g
"
            ;;
        perl-*)
            spectype="${appname%%-*}"
            cpandist="${appname##perl-}"
            specfilter="
    s/^%setup.*/%setup -q -n $cpandist-%{version}/Mg
    s|^(URL:[ \\t]*)[^\\n]*|\\1http://search.cpan.org/dist/$cpandist/|IMg
"
            ;;
        php-pear-*)
            spectype=php-pear
            ;;
        [Pp]y*)
            spectype=python
            ;;
        R-*)
            spectype="${appname%%-*}"
            packname="${appname##R-}"
            specfilter="
    s/^%define\\s+packname\\s[^\\n]*\\n//Mg
    s/%\\{packname}/$packname/g
"
            ;;
        ruby-*)
            spectype="${appname%%-*}"
            ;;
        lib*|*-lib|*-libs)
            spectype=lib
            ;;
        *-fonts|*-fonts-simple)
            spectype=fonts-simple
            appname="${appname%%-simple}"
            specfilter="s/<FONTNAME>/${appname%%-fonts}/g"
            [[ $specfile_set ]] || specfile="$appname.spec"
            ;;
        *-fonts-multi)
            spectype=fonts-multi
            appname="${appname%%-multi}"
            specfilter="s/<FONTNAME>/${appname%%-fonts}/g"
            [[ $specfile_set ]] || specfile="$appname.spec"
            ;;
        *)
            spectype=$DEFTYPE
            ;;
    esac
fi

tempspec="$SPECDIR/spectemplate-$spectype.spec"

if [[ ! -f $tempspec ]] ; then
    echo "Template \"$tempspec\" not found, exiting."
    exit 1
fi

[[ -z $specfile ]] && specfile="$DEFSPEC"
if [[ -f $specfile ]] ; then
    echo "Output file \"$specfile\" already exists, exiting."
    exit 2
elif [[ $specfile == - ]] ; then
    specfile=/dev/stdout
fi

# If enabling more versions, remember to update bash completion too.
if [[ $rpmver -ge 40400 ]] ; then # >= 4.4
    # filter %defattr(-,root,root(,-)) immediately after %files
    specfilter+="
    s/^(%files\\b[^\\n]*\\n)%defattr[ \\t]*\\([ \\t]*-[ \\t]*,[ \\t]*root[ \\t]*,[ \\t]*root([ \\t]*,[ \\t]*-[ \\t]*)?\\)[^\\n]*\\n/\\1/Mg
"
fi
if [[ $rpmver -ge 40600 ]] ; then # >= 4.6
    # filter BuildRoot and Group tags
    specfilter+="
    s/^(BuildRoot|Group)[ \\t]*:[^\\n]*\\n//IMg
"
fi
if [[ $rpmver -ge 40800 ]] ; then # >= 4.8
    # filter unnecessary basic %clean section, up to next section
    specfilter+="
    s|^%clean\\s*((/bin/)?rm\\|%\\{?__rm\\}?)[ \\t]+-[rRf]+[ \\t]+\\\$RPM_BUILD_ROOT\\s{2,}^%|%|Mg
"
    # use %make_install instead of make install DESTDIR=...
    specfilter+="
    s|^make install DESTDIR=\\\$RPM_BUILD_ROOT|%make_install|Mg
"
fi

if [[ $NEWSPEC_PREFER_MACROS ]] ; then
    # This assumes templates are written using the shell style variables,
    # without surrounding curly braces.
    specfilter+="
    s/\\\$RPM_SOURCE_DIR\\b/%{_sourcedir}/g
    s/\\\$RPM_BUILD_DIR\\b/%{_builddir}/g
    s/\\\$RPM_OPT_FLAGS\\b/%{optflags}/g
    s/\\\$RPM_ARCH\\b/%{_arch}/g
    s/\\\$RPM_OS\\b/%{_os}/g
    s/\\\$RPM_DOC_DIR\\b/%{_docdir}/g
    s/\\\$RPM_PACKAGE_NAME\\b/%{name}/g
    s/\\\$RPM_PACKAGE_VERSION\\b/%{version}/g
    s/\\\$RPM_PACKAGE_RELEASE\\b/%{release}/g
    s/\\\$RPM_BUILD_ROOT\\b/%{buildroot}/g
"
fi

cat "$tempspec" | sed -rne "
1h
1!H
$ {
    g
    s/^(Name:[ \\t]*)[^\\n]*/\\1$appname/IMg
    $specfilter
    p
}" > "$specfile"

if [[ $specfile != /dev/stdout ]] ; then
    echo "$specfile created; type $spectype, rpm version >= $rpmmaj.$rpmmin."
fi