Late commit of license change
[make-srpm.git] / make-srpm
blob5669e308ed93cb2f41ae8bf41c4c34e4dddd1833
1 #! /bin/bash
2 # make-srpm: srpm builder, helps build srpm out of rcs sources
4 # Copyright (C) 2008-2010 Sam Liddicott <sam@liddicott.com>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # make-srpm will export from git or subversion and produce a src.rpm
21 # It will try and pick a recent tagged release for the "pristine source" and
22 # then produce patches up to the selected release as part of the rpm.
24 # It requires a .spec or .spec.in specfile template, from which it can also
25 # read some configuration, but this can be overridden on the command line
27 # arguments can be specified in the template spec file, or in the environment
28 # or as name=value pairs on the command line. (Once a non name=value argument
29 # is found, others are not looked for).
31 # $1 should be a spec file template
33 # arguments are:
34 # ORIGIN - an rcs reference to the revision that should be tar'd
35 # ORIGIN_PATTERN - a glob or regex used to look for rcs tags to guess ORIGIN
36 # RELEASE - an rcs reference to the revision you want to build. Patches
37 # are generated from ORIGIN to RELEASE. RELEASE can be:
38 # - HEAD whatever os checked out
39 # - LOCAL means whatever is checked out + local changes
41 #include svn and git helpers
43 export PATH="$PATH:/usr/local/lib/make-srpm:/usr/lib/make-srpm"
44 PATH="$PATH:`dirname $0`:`dirname $0`/../lib" . make-srpm_git
45 PATH="$PATH:`dirname $0`:`dirname $0`/../lib" . make-srpm_svn
47 die() {
48 echo "!! $@" >&2
49 exit 1
52 report() {
53 echo "-- $@" >&2
56 # try to find a checked-out project src dir
57 find_topdir() {
58 # stop when we find the git folder or the top level svn folder
59 while :
61 echo "Checking for top level source directory in $PWD" >&2
62 git_toplevel && break # found top level git
63 svn_toplevel && break # found top level svn
65 if ! cd .. || test "$PWD" = "/"
66 then
67 report "Can't find top level repository directory, using $BASED"
68 cd "$BASED"
69 break
71 done
72 echo "$PWD"
75 # read a config item from a file and set environment variables.
76 # e.g.
77 # to match 2.4 from Version: 2.4
78 # get_config Version
80 # to match /bin:/usr/bin from PATH=/bin:/usr/bin
81 # sep="=" get_config PATH
83 # to match 2.4alpha from #mksrpm-RELEASE: 2.4alpha
84 # prefix="#mksrpm-" get_config RELEASE
85 get_config() {
86 for g in "$@"
88 if test -z "${!g}"
89 then export $g="`sed "/^$prefix$g *${sep:-:} */!d;s/^[^${sep:-:}]*${sep:-:} *//;" "$SPEC_SRC"`"
91 done
94 # generate the $SPEC spec file from $SPEC template which MAY be $SPEC.in
95 make_spec() {
96 _SPEC="$SRC_EXPORT/`basename "$SPECIN" .in`"
98 cat "$SPEC_SRC" > "$_SPEC" || die "Can't copy $SPECIN to $_SPEC"
100 report "Updating $_SPEC"
101 # insert some macros which may be useful
102 # as well as define versions etc
103 sed -i -e "1i%define makesrpm_tarname $TAR_NAME" \
104 -e "1i%define makesrpm_tarprefix $TAR_PREFIX" \
105 -e "s/^\(Version: *\).*/\1$SPEC_VERSION/" \
106 -e "s/^\(Release: *\).*/\1${SPEC_RELEASE:-0}/" \
107 -e "s/^\(Source: *\).*/\1$TAR_NAME/" \
108 -e "/^Source: */r$SRC_EXPORT/patches.list" \
109 -e "/^%setup/r$SRC_EXPORT/patches.apply" \
110 "$_SPEC"
111 # insert/replace any macro defines that were passed on the command line
112 for define in "${defines[@]}"
114 if grep "^%define ${define%%=*} " 2>/dev/null "$_SPEC"
115 then sed -i -e "/^%define[ \t][ \t]*${define%%=*}[ \t]/c%define ${define%%=*} ${define#*=}" "$_SPEC"
116 else sed -i -e "1i%define ${define%%=*} ${define#*=}" "$_SPEC"
118 done
119 # _defines are like defines except subject to variable interpolation so
120 # that inner values calculated during execution, like TAR_NAME can be accessed
121 for define in "${_defines[@]}"
123 eval "define=$define"
124 if grep "^%define ${define%%=*} " 2>/dev/null "$_SPEC"
125 then sed -i -e "/^%define[ \t][ \t]*${define%%=*}[ \t]/c%define ${define%%=*} ${define#*=}" "$_SPEC"
126 else sed -i -e "1i%define ${define%%=*} ${define#*=}" "$_SPEC"
128 done
131 # export current checked out source to file "$2" with tar path prefix of $1
132 # normally a git or svn helper is used to do a repo-export, but this will
133 # try to do a poor-mans equivalent
134 source_export() {
135 mkdir -p "$1"
136 # we want to specify the top-level folder name so we use a ghastly
137 # cpio hard-link trick to avoid copying the whole tree before tar-ing it
138 find ${SOURCE_PATHS:-.} '(' -wholename "$SRC_EXPORT*" -o -wholename "./.git*" -o -name '*.o' \
139 -o -name '*.a' -o -name '*.so' -o -name '.svn' \
140 -o -name "$Name-*gz" -o -name "$Name-*src.rpm" \
141 ')' -prune -o -print |\
142 cpio -p -d -l "$1" >/dev/null
144 source_archive() {
145 source_export "$SRC_EXPORT/$1" &&
146 ( cd "$SRC_EXPORT" && tar -czf - "1"; rm -fr "$1") > "$2"
149 # export_archive exports some "clean" source tree to $TAR_NAME
150 archive_version() {
151 report "Writing $SOURCE_TYPE to $TAR_NAME"
152 case "$SOURCE_TYPE" in
153 git) git_archive "$DIRNAME" "$TAR_NAME" ;;
154 svn) svn_archive "$DIRNAME" "$TAR_NAME" ;;
155 source) source_archive "$DIRNAME" "$TAR_NAME" ;;
156 *) die "Can't export from unknown source type $SOURCE_TYPE";;
157 esac
160 # export_src exports some "clean" source tree to $SRC_EXPORT
161 export_version() {
162 report "Exporting $SOURCE_TYPE to $1"
163 case "$SOURCE_TYPE" in
164 git) git_export "$1" ;;
165 svn) svn_export "$1" ;;
166 source) source_export "$1";;
167 *) die "Can't export from unknown source type $SOURCE_TYPE";;
168 esac
171 # $1 is a simple glob like v*-release
172 # $2 is a simple value like v2.3-release
173 # outputs 2.3 by splitting on the * and then removing the LHS and RHS from $2
174 glob_match() {
175 local R="${2#${1/\**}}"
176 echo "${R%${1/\**}}"
179 cd_toplevel() {
180 test -n "$TOPDIR" || TOPDIR="`find_topdir`"
181 cd "$TOPDIR" || die "Can't cd to $TOPDIR from $BASED"
183 if [ "$SOURCE_TYPE" = "" ]
184 then
186 SOURCE_TYPE="source"
187 test -d .svn && SOURCE_TYPE="svn"
188 test -d .git && SOURCE_TYPE="git"
191 echo "Source type: $SOURCE_TYPE"
193 SRC_EXPORT="./dist_export"
194 TMPDIR="$SRC_EXPORT"
195 rm -fr "$TMPDIR"
196 mkdir -p "$TMPDIR"
199 clean_tmp() {
200 echo "Cleaning temp dir" >&2
201 # delete the git tmpdir unless asked to keep it
202 if test -z "$KEEP_GIT"
203 then
204 # this is safer than rm -fr $GIT_TMP if $HOME is accidentally used!
205 rm -fr $GIT_TMP/git-tmp
206 rmdir $GIT_TMP
210 make_srpm() {
211 rm -fr "$SRC_EXPORT"
212 mkdir -p "$SRC_EXPORT"
214 # copy any local sources
215 test -n "$EXTRA_SOURCE" && cp `dirname "$SPEC_SRC"`/$EXTRA_SOURCE "$SRC_EXPORT"
217 # what number should our patches start at? Check what patches are already listed
218 START_PATCH_NO=$(( 1 + 0`sed -n 's/^\(%\|\)\(patch\)//i;T;s/[: ].*//;T;p' "$SPEC_SRC" | sort -nr | head -1` ))
220 # get patches ready according to rebase, origin etc
221 case "$SOURCE_TYPE" in
222 git) prepare_git_src;;
223 svn) prepare_svn_src;;
224 *);;
225 esac
227 # make spec file and calculate START_PATCH_NO
228 TAR_NAME="`basename "$TAR_NAME"`" make_spec
230 # nodeps tip from proyvind at #rpm on 5 Feb 2009
231 # nodeps because we are building src.rpm and we don't need build-time dependancies to be satisfied
232 rpmbuild --nodeps --define "_sourcedir $SRC_EXPORT" --define "_srcrpmdir ." -bs "$SRC_EXPORT/`basename "$SPEC"`" >&2 || "Failed to build src.rpm"
235 # set environment from args of style var=value
236 while test -n "$*"
238 case "$1" in
239 # -c means make tmp checkout here and delete afterwards
240 -c) KEEP_GIT= ; GIT_TMP="$2"; shift 2;;
241 # -C means make tmp checkout here and don't delete afterwards
242 -C) KEEP_GIT=1; GIT_TMP="$2"; shift 2;;
243 define_*=*) defines[${#defines[@]}]="${1#define_}"; shift;;
244 _define_*=*) _defines[${#_defines[@]}]="${1#_define_}"; shift;;
245 *=*) export "${1%%=*}"="${1#*=}"; shift;;
246 *) break;;
247 esac
248 done
250 if test -z "$GIT_TMP"
251 then
252 GIT_TMP="${TMP:-${TEMP:-/tmp}}/make-srpm.$$.git"
253 KEEP_GIT=
256 VERSION=${VERSION%%-*}
258 # Check if we need to do git checkout
260 # get to the top level project folder
261 BASED="$PWD"
263 trap "clean_tmp" 0
265 for spec in "$@"
266 do (
267 # fixup relative paths to what PWD was when we launched
268 case "$spec" in
269 /*) ;;
270 *) spec="$BASED/$spec";;
271 esac
273 case "$spec" in
274 *.spec.in) test -z "$SPECIN" && SPECIN="$spec";;
275 *.spec) test -z "$SPEC" && SPEC="$spec";;
276 esac
278 test -z "$SPECIN" -a -n "$SPEC" && SPECIN="$SPEC.in"
279 test -z "$SPECIN" && SPECIN="`set -- *spec.in && echo $spec`"
280 test -z "$SPEC" && SPEC="`dirname "$SPECIN"`/`basename "$SPECIN" .in`"
281 test -r "$SPECIN" -o -r "$SPEC" || die "Can't find spec file to work with"
282 # find the project parameters
283 test -r "$SPECIN" && SPEC_SRC="$SPECIN" || SPEC_SRC="$SPEC"
285 CASE="i" get_config Name Version
286 prefix="#makes\(-\|\)rpm-" get_config SOURCE_PATHS ORIGIN ORIGIN_PATTERN RELEASE PATCH_LEVEL VERSION_PATTERN GIT_CLONE GIT_CHECKOUT
288 test -z "$PATCH_LEVEL" && export PATCH_LEVEL=0
290 if test -n "$GIT_CLONE"
291 then
292 GIT_BASENAME=`git_basename "$GIT_CLONE"`
293 mkdir -p "$GIT_TMP/git-tmp" || die "Can't make git dir $GIT_TMP/git-tmp"
294 cd "$GIT_TMP/git-tmp" || die "Can't cd to git dir $GIT_TMP/git-tmp"
295 git clone -n "$GIT_CLONE" "$GIT_BASENAME" || die "Can't clone $GIT_CLONE to $PWD/$GIT_BASENAME"
296 cd "$GIT_BASENAME"
297 git checkout "$GIT_CHECKOUT"
300 cd_toplevel
301 make_srpm
302 ) ; done