#!/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.4
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://pagure.io/rpmdevtools/issues>."
}
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 (RHEL >= 5, Fedora >= 7)
# 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 (Fedora >= 10)
# filter BuildRoot and Group tags
specfilter+="
s/^(BuildRoot|Group)[ \\t]*:[^\\n]*\\n//IMg
"
fi
if [[ $rpmver -ge 40800 ]] ; then # >= 4.8 (RHEL >= 6, Fedora >= 13)
# 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 [[ $rpmver -ge 41100 ]] ; then # >= 4.11 (RHEL >= 7, Fedora >= 19)
# filter unnecessary %license availability detection
specfilter+="
s|^%\\{!\\?_licensedir:%global license %%doc\\}\\n||Mg
"
# use %autosetup instead of %setup -q
specfilter+="
s|^%setup -q( \\|\$)|%autosetup\\1|Mg
"
fi
if [[ $rpmver -ge 41200 ]] ; then # >= 4.12 (Fedora >= 21)
# use %make_build instead of make %{?_smp_mflags}
specfilter+="
s|^make %\\{?\\?_smp_mflags\\}?|%make_build|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
s|^%changelog\\s*|%changelog\\n* $(LC_ALL=C date --utc +'%a %b %e %Y') $(rpmdev-packager)\\n- |Mg
$specfilter
p
}" > "$specfile"
if [[ $specfile != /dev/stdout ]] ; then
echo "$specfile created; type $spectype, rpm version >= $rpmmaj.$rpmmin."
fi
|