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