chiark / gitweb /
el/dot-emacs.el: Better fontification for Ediff.
[profile] / bin / mdw-build
1 #! /bin/bash
2 ###
3 ### Build script for Debian packages
4 ###
5 ### (c) 2008 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This program is free software; you can redistribute it and/or modify
11 ### it under the terms of the GNU General Public License as published by
12 ### the Free Software Foundation; either version 2 of the License, or
13 ### (at your option) any later version.
14 ###
15 ### This program is distributed in the hope that it will be useful,
16 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ### GNU General Public License for more details.
19 ###
20 ### You should have received a copy of the GNU General Public License
21 ### along with this program; if not, write to the Free Software Foundation,
22 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 ###--------------------------------------------------------------------------
25 ### Conventions for build systems.
26 ###
27 ### This script is designed to work with a variety of `make'-based build
28 ### systems, but there are a number of conventions which must be followed if
29 ### this is going to work properly.
30 ###
31 ###   * There must be a `configure.ac', `configure.in', or `.links' file, or
32 ###     a `.git' directory in the project top-level, so that we can find it.
33 ###
34 ###   * The following `make' variables must be assigned in the top-level
35 ###     Makefile, after `mdw-build' has constructed it.
36 ###
37 ###     distdir         The name of the top-level project directory in the
38 ###                     source distribution, and the base name for
39 ###                     distribution archives; should be of the form
40 ###                     `PROJECT-VERSION'.
41 ###
42 ###     The following `make' targets must be available in the top-level
43 ###     Makefile.
44 ###
45 ###     dist            Write to $(distdir).tar.gz a source distribution of
46 ###                     the package.
47 ###
48 ###     distcheck       As for `dist', but also build and test the project.
49 ###
50 ###  * The source distribution constructed by `make dist' must contain a file
51 ###     $(distdir)/RELEASE containing the release name.  This isn't currently
52 ###     tested, but it might be later.
53
54 set -e
55
56 ###--------------------------------------------------------------------------
57 ### Configuration.
58
59 unset checkout checkoutrev
60 unset setup setupcmd
61 unset sign signkey
62 unset sbuild sbuildsrv
63 unset upload uploadpath
64 unset dput dputtarget
65 unset build distcheck debian clean vpath native
66 for i in \
67   "/etc/mdw-build.conf" \
68   "${XDG_CONFIG_HOME-$HOME/.config}/mdw-build.conf" \
69   "./.mdw-build.conf"
70 do
71   if [ -f "$i" ]; then . "$i"; fi
72 done
73 default_depends () {
74   var=$1 want=$2
75   eval "p=\${$var+t} q=\${$want+t}"
76   case $p,$q in t,*) ;; *,t) eval "$var=yes" ;; *) eval "$var=no" ;; esac
77 }
78 : ${checkout=yes} ${checkoutrev=HEAD}
79 : ${build=test}
80 : ${setup=yes} ${setupcmd=mdw-setup}
81 : ${distcheck=yes}
82 : ${debian=yes}
83 : ${clean=yes}
84 : ${vpath=yes}
85 : ${native=yes}
86 default_depends sbuild sbuildsrv
87 default_depends sign signkey
88 default_depends upload uploadpath
89 default_depends dput dputtarget
90 : ${DEB_BUILD_OPTIONS=parallel=4}; export DEB_BUILD_OPTIONS
91
92 ###--------------------------------------------------------------------------
93 ### Parse options.
94
95 prog=${0##*/}
96
97 usage () {
98   cat <<EOF
99 Usage: $prog [-vr] BUILDOPT
100
101 Build options:
102
103   [no]checkout[=REV]
104   [no]release
105   [no]setup[=RUNE]
106   [no]distcheck
107   [no]debian
108   [no]upload[=SERVER:PATH]
109   [no]dput[=TARGET]
110   [no]clean
111   [no]vpath
112   [no]sbuild[=SERVER]
113   [no]sign[=KEYID]
114   [no]native
115 EOF
116 }
117
118 ## Parse simple options.
119 verbose=no
120 while getopts "hvr" opt; do
121   case "$opt" in
122     h) usage; exit 0 ;;
123     v) verbose=yes ;;
124     *) exit 1 ;;
125   esac
126 done
127 shift $((OPTIND - 1))
128
129 ## Parse the build options.
130 maybe_set () {
131   var=$1 want=$2
132   eval "p=\${$want+t}\${$want-nil}"
133   case $p in
134     t) eval $var=yes ;;
135     nil) echo >&2 "$prog: $want not set"; exit 1 ;;
136   esac
137 }
138 for opt; do
139   case "$opt" in
140     checkout)   checkout=yes checkoutrev=HEAD ;;
141     checkout=*) checkout=yes checkoutrev=${opt#*=} ;;
142     release)    build=release ;;
143     norelease)  build=test ;;
144     setup)      setup=yes setupcmd=mdw-setup ;;
145     setup=*)    setup=yes setupcmd=${opt#*=} ;;
146     upload)     maybe_set upload uploadpath ;;
147     upload=*)   upload=yes uploadpath=${opt#*=} ;;
148     sign)       maybe_set sign signkey ;;
149     sign=*)     sign=yes signkey=${opt#*=} ;;
150     sbuild)     maybe_set sbuild sbuildsrv ;;
151     sbuild=*)   sbuild=yes sbuildsrv=${opt#*=} ;;
152     dput)       maybe_set dput dputtarget ;;
153     dput=*)     dput=yes dputtarget=${opt#*=} ;;
154
155     distcheck | debian | clean | vpath | native)
156       eval "$opt=yes"
157       ;;
158     nocheckout | nosetup | nodistcheck | nodebian | \
159     noupload | nodput | noclean | novpath | nonative | nosbuild | nosign)
160       eval "${opt#no}=no"
161       ;;
162     *)
163       usage >&2
164       exit 1
165       ;;
166   esac
167 done
168
169 ## Parse DEB_BUILD_OPTIONS.
170 jobs=1
171 set -- $DEB_BUILD_OPTIONS
172 for opt; do
173   case "$opt" in
174     parallel=*) jobs=${opt#*=} ;;
175   esac
176 done
177
178 makeopts=""
179 case $jobs in 1) ;; *) makeopts="$makeopts -j$jobs" ;; esac
180
181 ###--------------------------------------------------------------------------
182 ### Utility functions.
183
184 exec 3>&2 4>/dev/null 5>&2
185
186 notify () {
187   colour=$1 message=$2
188   echo $message >&4
189   echo "$(tput bold; tput setaf $colour)$message$(tput sgr0; tput op)" >&5
190 }
191
192 fail () {
193   notify 1 "!!! $*"
194   exit 1
195 }
196
197 warn () {
198   case $build in
199     release) fail "$*" ;;
200     *) notify 5 "??? $*" ;;
201   esac
202 }
203
204 info () {
205   notify 6 "--- $*"
206 }
207
208 assign () {
209   info "$1 = $2"
210   eval "$1=$2"
211 }
212
213 runx () {
214   notify 2 "+++ $*"
215   "$@" 2>&3 || fail "$1: exit $?"
216 }
217
218 run () { runx "$@" >&3; }
219
220 yesno () {
221   echo -n "(test $*)" >&4
222   if "$@" >&4 2>&4; then
223     echo "(yes)" >&4
224     echo yes
225   else
226     echo "(no)" >&4
227     echo no
228   fi
229 }
230
231 ###--------------------------------------------------------------------------
232 ### Do the building.
233
234 ## Find the top-level package directory.
235 while [ ! -f configure.ac -a ! -f configure.in -a \
236         ! -f .links -a ! -d .git ]; do
237   case "$(pwd)" in
238     /)
239       fail "couldn't find top-level directory"
240       ;;
241   esac
242   cd ..
243 done
244 assign srcpath $(pwd)
245
246 ## Build any necessary qualifiers.
247 qual= sep=.
248 case ${SBOX_SESSION_DIR+t},${DEB_BUILD_ARCH+t} in
249   t,t) qual=$qual$sep$DEB_BUILD_ARCH; sep=- ;;
250   t,*) fail "unknown build arch" ;;
251 esac
252
253 ## Construct the output directory.
254 assign releasepath $srcpath/dist-$build$qual
255 chmod -R +w $releasepath 2>/dev/null || :
256 rm -rf $releasepath 2>/dev/null || :
257 mkdir $releasepath
258 case $verbose in
259   no)
260     exec 4>$releasepath/mdw-build.log 3>&4 ||
261       fail "Failed to create log."
262     ;;
263 esac
264
265 ## Do we have a Git repository?
266 case "$checkout,$setup,$(yesno [ -d $srcpath/.git ])" in
267   yes,no,*)
268     fail "Inconsistent options: can't check out without setup."
269     ;;
270   yes,yes,no)
271     info "No Git repository found."
272     checkout=no gitver=none
273     ;;
274   yes,yes,yes)
275     cd $srcpath
276     [ "$(git ls-files -m)" = "" ] ||
277       warn "working tree has uncommitted changes"
278     ;;
279 esac
280
281 ## Is there Debian build equipment?
282 case "$debian,$(yesno [ -d $srcpath/debian ])" in
283   yes,no)
284     info "No debian directory found."
285     debian=no debver=none
286     ;;
287   no,*)
288     debver=none
289     ;;
290   yes,yes)
291     debver=$(dpkg-parsechangelog | sed -n 's/^Version: //p' | tr \~ -)
292     debsrc=$(dpkg-parsechangelog | sed -n 's/^Source: //p')
293     debname=$(git config user.name) debemail=$(git config user.email)
294     ;;
295 esac
296
297 ## Maybe check out a copy of the source.
298 case "$checkout" in
299   yes)
300     cd $releasepath
301     run git clone -sn $srcpath/.git _source
302     assign srcpath $releasepath/_source
303     cd $srcpath
304     run git checkout -b mdw-build $checkoutrev
305     gitver=$(git describe --abbrev=4)
306     ;;
307 esac
308
309 ## Check the version number.
310 hack_dch_p=no
311 case "$gitver,$debver" in
312   none,* | *,none)
313     ;;
314   *)
315     if [ "$gitver" != "$debver" ]; then
316       warn "Git version $gitver doesn't match Debian version $debver"
317       hack_dch=yes
318     fi
319     ;;
320 esac
321
322 ## Maybe refresh the build machinery.
323 case "$setup" in
324   yes)
325     run $setupcmd
326     ;;
327 esac
328
329 ## Initialize the build directory.
330 case "$vpath,$(yesno [ -e $srcpath/configure ])" in
331   yes,yes)
332     assign buildpath $releasepath/_build
333     mkdir $buildpath
334     cd $buildpath
335     run $srcpath/configure
336     ;;
337   no,yes)
338     info "VPATH build disabled"
339     assign buildpath $srcpath
340     distcheck=no
341     cd $srcpath
342     run ./configure
343     ;;
344   *,no)
345     info "no configure script"
346     assign buildpath $srcpath
347     cd $srcpath
348     ;;
349 esac
350
351 ## Discover the release name.
352 cat >find-distdir.mk <<'EOF'
353 include Makefile
354 print-distdir:
355         @echo >&3 $(distdir)
356 EOF
357 assign distdir \
358         $({ make -f find-distdir.mk print-distdir >/dev/null 2>&1; } 3>&1)
359
360 ## Get a tarball distribution.
361 case "$distcheck" in
362   yes)
363     run make $makeopts distcheck
364     ;;
365   no)
366     run make $makeopts dist
367     ;;
368 esac
369
370 cd $releasepath
371
372 case $native in
373   yes)
374     if ! tar tf $buildpath/$distdir.tar.gz 2>/dev/null | grep -q RELEASE
375     then
376       fail "missing RELEASE file in distribution"
377     fi
378     ;;
379 esac
380
381 run mv $buildpath/$distdir.tar.gz .
382 case $build,$sign in
383   release,yes)
384     run gpg -u$signkey -ab -o$distdir.tar.gz.gpg $distdir.tar.gz
385     ;;
386 esac
387
388 ## Maybe build the Debian packages.
389 case "$debian" in
390   yes)
391     run tar xvfz $distdir.tar.gz
392     cd $distdir
393     case $hack_dch in
394       yes)
395         dver=$(echo $gitver | sed 's/-/+/; s/-/./g')
396         now=$(date -R)
397         cat - debian/changelog >debian/changelog.new <<EOF
398 $debsrc ($dver) experimental; urgency=low
399
400   * Hacking in process, not intended for release.
401
402  -- $debname <$debemail>  $now
403
404 EOF
405         mv debian/changelog.new debian/changelog
406         ;;
407     esac
408     case $sbuild,$build,$sign in
409       yes,release,yes) run mdw-sbuild -k$signkey $sbuildsrv ;;
410       yes,*) run mdw-sbuild $sbuildsrv ;;
411       no,release,yes) run dpkg-buildpackage -k$signkey ;;
412       no,*) run dpkg-buildpackage -us -uc ;;
413     esac
414     ;;
415 esac
416
417 ## Maybe upload Debian packages.
418 cd $releasepath
419 case "$upload,$build" in
420   yes,test) info "Test build: not uploading." ;;
421   yes,release) run rsync $distdir.tar.gz $distdir.tar.gz.gpg $uploadpath ;;
422 esac
423 case "$debian,$upload,$dput,$build" in
424   yes,yes,yes,release) run dput -f $dputtarget *.changes ;;
425 esac
426
427 ## Tidy up.
428 case "$clean" in
429   yes)
430     rm -rf $releasepath/$distdir
431     rm -rf $releasepath/_source
432     rm -rf $releasepath/_build
433     ;;
434 esac
435
436 ## Done.
437 info "All OK."
438
439 ###----- That's all, folks --------------------------------------------------