chiark / gitweb /
el/dot-emacs.el: Apply `extend' setting to all(?) the applicable fonts.
[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=!guess}
81 : ${distcheck=yes}
82 : ${debian=yes}
83 : ${clean=yes}
84 : ${vpath=yes}
85 : ${native=yes}
86 : ${make=make}
87 : ${test=yes}
88 default_depends sbuild sbuildsrv
89 default_depends sign signkey
90 default_depends upload uploadpath
91 default_depends dput dputtarget
92 : ${DEB_BUILD_OPTIONS=parallel=4}; export DEB_BUILD_OPTIONS
93
94 ###--------------------------------------------------------------------------
95 ### Parse options.
96
97 prog=${0##*/}
98
99 usage () {
100   cat <<EOF
101 Usage: $prog [-v] BUILDOPT
102
103 Build options:
104
105   [no]checkout[=REV]
106   [no]release
107   [no]setup[=RUNE]
108   [no]distcheck
109   [no]debian
110   [no]upload[=SERVER:PATH]
111   [no]dput[=TARGET]
112   [no]clean
113   [no]vpath
114   [no]sbuild[=SERVER]
115   [no]sign[=KEYID]
116   [no]test
117   [no]native
118   make=MAKE
119   qual=QUAL
120 EOF
121 }
122
123 ## Initialize qualifiers.
124 qual= qualsep=.
125
126 ## Parse simple options.
127 verbose=no
128 while getopts "hv" opt; do
129   case "$opt" in
130     h) usage; exit 0 ;;
131     v) verbose=yes ;;
132     *) exit 1 ;;
133   esac
134 done
135 shift $((OPTIND - 1))
136
137 ## Parse the build options.
138 maybe_set () {
139   var=$1 want=$2
140   eval "p=\${$want+t}\${$want-nil}"
141   case $p in
142     t) eval $var=yes ;;
143     nil) echo >&2 "$prog: $want not set"; exit 1 ;;
144   esac
145 }
146 for opt; do
147   case "$opt" in
148     checkout)   checkout=yes checkoutrev=HEAD ;;
149     checkout=*) checkout=yes checkoutrev=${opt#*=} ;;
150     release)    build=release ;;
151     norelease)  build=test ;;
152     setup)      setup=yes setupcmd=!guess ;;
153     setup=*)    setup=yes setupcmd=${opt#*=} ;;
154     upload)     maybe_set upload uploadpath ;;
155     upload=*)   upload=yes uploadpath=${opt#*=} ;;
156     sign)       maybe_set sign signkey ;;
157     sign=*)     sign=yes signkey=${opt#*=} ;;
158     sbuild)     maybe_set sbuild sbuildsrv ;;
159     sbuild=*)   sbuild=yes sbuildsrv=${opt#*=} ;;
160     dput)       maybe_set dput dputtarget ;;
161     dput=*)     dput=yes dputtarget=${opt#*=} ;;
162     make=*)     make=${opt#*=} ;;
163     qual=*)     qual=$qual$qualsep${opt#*=}; qualsep=- ;;
164
165     distcheck | debian | clean | vpath | native | test)
166       eval "$opt=yes"
167       ;;
168     nocheckout | nosetup | nodistcheck | nodebian | \
169       noupload | nodput | noclean | novpath | nonative | notest | \
170       nosbuild | nosign)
171       eval "${opt#no}=no"
172       ;;
173     *)
174       usage >&2
175       exit 1
176       ;;
177   esac
178 done
179
180 ## Parse DEB_BUILD_OPTIONS.
181 jobs=1
182 set -- $DEB_BUILD_OPTIONS
183 for opt; do
184   case "$opt" in
185     parallel=*) jobs=${opt#*=} ;;
186     nocheck) test=no ;;
187   esac
188 done
189
190 makeopts=""
191 case $jobs in 1) ;; *) makeopts="$makeopts -j$jobs" ;; esac
192
193 ###--------------------------------------------------------------------------
194 ### Utility functions.
195
196 ## File descriptor assignments:
197 ##
198 ##    0 -- original stdin (never touched)
199 ## 1, 2 -- stdout, stderr, redirected to 3 while running comamnds
200 ##  log -- logfile and original stderr (verbose), or logfile only (quiet);
201 ##              captures command output
202 ## diag -- logfile; primary diagnostic output
203 ## term -- orginal stderr; secondary diagnostic output (with colours)
204
205 notify () {
206   colour=$1 message=$2
207   echo $message >&$diag
208   echo "$(tput bold; tput setaf $colour)$message$(tput sgr0; tput op)" >&$term
209 }
210
211 fail () {
212   notify 1 "!!! $*"
213   exit 1
214 }
215
216 warn () {
217   case $build in
218     release) fail "$*" ;;
219     *) notify 5 "??? $*" ;;
220   esac
221 }
222
223 info () {
224   notify 6 "--- $*"
225 }
226
227 assign () {
228   info "$1 = $2"
229   eval "$1=$2"
230 }
231
232 runx () {
233   notify 2 "+++ $*"
234   nice "$@" 2>&$log {log}>&- {diag}>&- {term}>&- || fail "$1: exit $?"
235 }
236
237 run () { runx "$@" >&$log; }
238
239 yesno () {
240   echo -n "(test $*)" >&$diag
241   if "$@" >&$diag 2>&$diag {log}>&- {diag}>&- {term}>&-; then
242     echo "(yes)" >&$diag
243     echo yes
244   else
245     echo "(no)" >&$diag
246     echo no
247   fi
248 }
249
250 ###--------------------------------------------------------------------------
251 ### Do the building.
252
253 ## Some preflight checks.
254 case $test,$build in
255   no,release) fail "refusing to make release build without testing" ;;
256 esac
257 case $test,$distcheck in
258   no,yes)
259     info "forcing \`distcheck' off because tsting disabled"
260     distcheck=no
261     ;;
262 esac
263
264 ## Find the top-level package directory.
265 while [ ! -f configure.ac -a ! -f configure.in -a \
266         ! -f .links -a ! -d .git ]; do
267   case "$(pwd)" in
268     /)
269       fail "couldn't find top-level directory"
270       ;;
271   esac
272   cd ..
273 done
274 toppath=$(pwd)
275
276 ## Add a qualifier for Scratchbox builds.
277 case ${SBOX_SESSION_DIR+t},${DEB_BUILD_ARCH+t} in
278   t,t) qual=$qual$qualsep$DEB_BUILD_ARCH; qualsep=- ;;
279   t,*) fail "unknown build arch" ;;
280 esac
281
282 ## Construct the output directory.
283 releasepath=$toppath/dist-$build$qual
284 chmod -R +w $releasepath 2>/dev/null || :
285 rm -rf $releasepath 2>/dev/null || :
286 mkdir $releasepath
287 logfile=$releasepath/mdw-build.log
288 exec {term}>&2
289 exec {diag}>>$logfile || fail "Failed to create log."
290 case $verbose in
291   no) exec {log}>&$diag ;;
292   yes) exec {log}> >(tee -a $logfile >&$term {term}>&- {diag}>&-) ;;
293 esac
294
295 ## Repeat the earlier assignments for tbe benefit of the logfile.
296 assign toppath $toppath
297 assign releasepath $releasepath
298 assign logfile $logfile
299
300 ## Do we have a Git repository?
301 case "$checkout,$setup,$(yesno [ -d $toppath/.git ])" in
302   yes,no,*)
303     fail "Inconsistent options: can't check out without setup."
304     ;;
305   yes,yes,no)
306     info "No Git repository found."
307     checkout=no gitver=none
308     ;;
309   yes,yes,yes)
310     cd $toppath
311     [ "$(git ls-files -m)" = "" ] ||
312       warn "working tree has uncommitted changes"
313     ;;
314 esac
315
316 ## Is there Debian build equipment?
317 case "$debian,$(yesno [ -d $toppath/debian ])" in
318   yes,no)
319     info "No debian directory found."
320     debian=no debver=none
321     ;;
322   no,*)
323     debver=none
324     ;;
325   yes,yes)
326     debver=$(dpkg-parsechangelog | sed -n 's/^Version: //p')
327     debsrc=$(dpkg-parsechangelog | sed -n 's/^Source: //p')
328     debname=$(git config user.name) debemail=$(git config user.email)
329     ;;
330 esac
331
332 ## Maybe check out a copy of the source.
333 case "$checkout" in
334   yes)
335     cd $releasepath
336     run git clone -sn $toppath/.git _source
337     assign srcpath $releasepath/_source
338     cd $srcpath
339     run git update-ref refs/heads/mdw-build $checkoutrev ""
340     run git symbolic-ref HEAD refs/heads/mdw-build
341     run git read-tree --reset refs/heads/mdw-build
342     run git checkout-index -afu
343     assign gitversion "$(git describe --abbrev=4)"
344     ;;
345   no)
346     assign srcpath $toppath
347     if [ -e .git ] && gitver=$(git describe --abbrev=4 --dirty=+ 2>/dev/null); then
348       assign gitversion "$gitver"
349     else
350       assign gitversion none
351     fi
352     ;;
353 esac
354
355 ## Check the version number.
356 hack_dch_p=no
357 case "$gitversion,$debver" in
358   none,* | *,none)
359     ;;
360   *)
361     dvref=$(echo "$debver" | tr '~' '_')
362     if [ "$gitversion" = "$dvref" ]; then
363       assign debversion "$debver"
364     else
365       warn "Git version $gitversion doesn't match Debian version $debver"
366       hack_dch_p=yes
367       dver=$(echo $gitversion | sed 's/-/+/; s/-/./g')
368       case $debver in *~) dver=$debver$dver ;; esac
369       assign debversion "$dver"
370       now=$(date -R)
371     fi
372     ;;
373 esac
374
375 ## Maybe refresh the build machinery.
376 case "$setup" in
377   yes)
378     case $setupcmd in
379       !guess)
380         if [ -f .links ]; then setupcmd=mdw-setup
381         elif [ -x autogen.sh ]; then setupcmd=./autogen.sh
382         elif [ -x setup ]; then setupcmd=./setup
383         elif [ -f configure.ac ]; then setupcmd="autoreconf -fis"
384         else setupcmd=mdw-setup
385         fi
386         ;;
387     esac
388     run $setupcmd
389     ;;
390 esac
391
392 ## Initialize the build directory.
393 case "$vpath,$(yesno [ -e $srcpath/configure ])" in
394   yes,yes)
395     assign buildpath $releasepath/_build
396     mkdir $buildpath
397     cd $buildpath
398     run $srcpath/configure
399     ;;
400   no,yes)
401     info "VPATH build disabled"
402     assign buildpath $srcpath
403     distcheck=no
404     cd $srcpath
405     run ./configure
406     ;;
407   *,no)
408     info "no configure script"
409     assign buildpath $srcpath
410     cd $srcpath
411     ;;
412 esac
413
414 ## Discover the release name.
415 cat >find-distdir.mk <<'EOF'
416 include Makefile
417 print-distdir:
418         @bash -c 'echo >&$(fd) $(distdir)'
419 EOF
420 assign distdir \
421   $({ $make -f find-distdir.mk print-distdir fd=$t >/dev/null 2>&1; } {t}>&1)
422
423 ## Get a tarball distribution.
424 case "$distcheck" in
425   yes)
426     run $make $makeopts distcheck
427     ;;
428   no)
429     run $make $makeopts dist
430     ;;
431 esac
432
433 cd $releasepath
434
435 case $native in
436   yes)
437     if ! tar tf $buildpath/$distdir.tar.gz 2>/dev/null | grep -q RELEASE
438     then
439       fail "missing RELEASE file in distribution"
440     fi
441     ;;
442 esac
443
444 run mv $buildpath/$distdir.tar.gz .
445 case $build,$sign in
446   release,yes)
447     run gpg -u$signkey -ab -o$distdir.tar.gz.gpg $distdir.tar.gz
448     ;;
449 esac
450
451 ## Maybe build the Debian packages.
452 case "$debian" in
453   yes)
454     run tar xvfz $distdir.tar.gz
455     cd $distdir
456     case $hack_dch_p in
457       yes)
458         cat - debian/changelog >debian/changelog.new <<EOF
459 $debsrc ($debversion) experimental; urgency=low
460
461   * Hacking in process, not intended for release.
462
463  -- $debname <$debemail>  $now
464
465 EOF
466         mv debian/changelog.new debian/changelog
467         ;;
468     esac
469     sbuildargs=$sbuildsrv
470     case $sbuild,$build in
471       yes,release)
472         case $sign in yes) sbuildargs="-k$signkey $sbuildargs" ;; esac
473         ;;
474       yes,*)
475         if [ -d $toppath/dist-$build.pkgs ]; then
476           sbuildargs="-p$toppath/dist-$build.pkgs $sbuildargs"
477         fi
478         ;;
479     esac
480     case "$sbuild,$test, $DEB_BUILD_OPTIONS " in
481       yes,no,*) sbuildargs="-T $sbuildargs" ;;
482       *" nocheck "*) ;;
483       no,no,*)
484         DEB_BUILD_OPTIONS=${DEB_BUILD_OPTIONS+"$DEB_BUILD_OPTIONS nocheck"}
485         ;;
486     esac
487     case $sbuild,$build,$sign in
488       yes,*) run mdw-sbuild $sbuildargs ;;
489       no,release,yes) run dpkg-buildpackage -k$signkey ;;
490       no,*) run dpkg-buildpackage -us -uc ;;
491     esac
492     ;;
493 esac
494
495 ## Maybe upload Debian packages.
496 cd $releasepath
497 case "$upload,$build" in
498   yes,test) info "Test build: not uploading." ;;
499   yes,release) run rsync $distdir.tar.gz $distdir.tar.gz.gpg $uploadpath ;;
500 esac
501 case "$debian,$upload,$dput,$build" in
502   yes,yes,yes,release) run dput -f $dputtarget *.changes ;;
503 esac
504
505 ## Tidy up.
506 case "$clean" in
507   yes)
508     rm -rf $releasepath/$distdir
509     rm -rf $releasepath/_source
510     rm -rf $releasepath/_build
511     ;;
512 esac
513
514 ## Done.
515 info "All OK."
516
517 ###----- That's all, folks --------------------------------------------------