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