Commit | Line | Data |
---|---|---|
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 |
54 | set -e |
55 | ||
816af8ee MW |
56 | ###-------------------------------------------------------------------------- |
57 | ### Configuration. | |
58 | ||
59 | unset checkout checkoutrev | |
60 | unset setup setupcmd | |
5a91acc5 | 61 | unset sign signkey |
b94830d9 | 62 | unset sbuild sbuildsrv |
5a91acc5 | 63 | unset upload uploadpath |
816af8ee | 64 | unset dput dputtarget |
5a91acc5 | 65 | unset build distcheck debian clean vpath native |
816af8ee MW |
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 | |
5a91acc5 MW |
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 | } | |
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} |
ff55a023 | 87 | : ${test=yes} |
b94830d9 | 88 | default_depends sbuild sbuildsrv |
5a91acc5 MW |
89 | default_depends sign signkey |
90 | default_depends upload uploadpath | |
91 | default_depends dput dputtarget | |
816af8ee MW |
92 | : ${DEB_BUILD_OPTIONS=parallel=4}; export DEB_BUILD_OPTIONS |
93 | ||
7ee12623 MW |
94 | ###-------------------------------------------------------------------------- |
95 | ### Parse options. | |
96 | ||
0660d224 MW |
97 | prog=${0##*/} |
98 | ||
7ee12623 MW |
99 | usage () { |
100 | cat <<EOF | |
24a3095a | 101 | Usage: $prog [-v] BUILDOPT |
7ee12623 MW |
102 | |
103 | Build 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 |
119 | EOF |
120 | } | |
121 | ||
122 | ## Parse simple options. | |
123 | verbose=no | |
24a3095a | 124 | while getopts "hv" opt; do |
7ee12623 MW |
125 | case "$opt" in |
126 | h) usage; exit 0 ;; | |
127 | v) verbose=yes ;; | |
128 | *) exit 1 ;; | |
129 | esac | |
130 | done | |
131 | shift $((OPTIND - 1)) | |
132 | ||
133 | ## Parse the build options. | |
5a91acc5 MW |
134 | maybe_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 |
142 | for 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 ;; | |
9c586ae1 MW |
148 | setup) setup=yes setupcmd=mdw-setup ;; |
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 | |
173 | done | |
174 | ||
84dd9069 MW |
175 | ## Parse DEB_BUILD_OPTIONS. |
176 | jobs=1 | |
177 | set -- $DEB_BUILD_OPTIONS | |
178 | for opt; do | |
179 | case "$opt" in | |
180 | parallel=*) jobs=${opt#*=} ;; | |
ff55a023 | 181 | nocheck) test=no ;; |
84dd9069 MW |
182 | esac |
183 | done | |
184 | ||
185 | makeopts="" | |
186 | case $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 |
200 | notify () { |
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 | ||
206 | fail () { | |
207 | notify 1 "!!! $*" | |
208 | exit 1 | |
209 | } | |
210 | ||
f282ba46 MW |
211 | warn () { |
212 | case $build in | |
213 | release) fail "$*" ;; | |
214 | *) notify 5 "??? $*" ;; | |
215 | esac | |
216 | } | |
217 | ||
7ee12623 MW |
218 | info () { |
219 | notify 6 "--- $*" | |
220 | } | |
221 | ||
222 | assign () { | |
223 | info "$1 = $2" | |
224 | eval "$1=$2" | |
225 | } | |
226 | ||
227 | runx () { | |
228 | notify 2 "+++ $*" | |
5b950572 | 229 | nice "$@" 2>&$log {log}>&- {diag}>&- {term}>&- || fail "$1: exit $?" |
7ee12623 MW |
230 | } |
231 | ||
ab9fae2a | 232 | run () { runx "$@" >&$log; } |
7ee12623 MW |
233 | |
234 | yesno () { | |
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. |
249 | case $test,$build in | |
250 | no,release) fail "refusing to make release build without testing" ;; | |
251 | esac | |
252 | case $test,$distcheck in | |
253 | no,yes) | |
254 | info "forcing \`distcheck' off because tsting disabled" | |
255 | distcheck=no | |
256 | ;; | |
257 | esac | |
258 | ||
7ee12623 | 259 | ## Find the top-level package directory. |
d43de82b MW |
260 | while [ ! -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 .. | |
268 | done | |
c3a2e2b1 | 269 | toppath=$(pwd) |
7ee12623 | 270 | |
9243a740 MW |
271 | ## Build any necessary qualifiers. |
272 | qual= sep=. | |
273 | case ${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" ;; | |
276 | esac | |
277 | ||
7ee12623 | 278 | ## Construct the output directory. |
c3a2e2b1 | 279 | releasepath=$toppath/dist-$build$qual |
47539e6a | 280 | chmod -R +w $releasepath 2>/dev/null || : |
7ee12623 MW |
281 | rm -rf $releasepath 2>/dev/null || : |
282 | mkdir $releasepath | |
4ed33f50 | 283 | logfile=$releasepath/mdw-build.log |
5043931a | 284 | exec {term}>&2 |
4ed33f50 | 285 | exec {diag}>>$logfile || fail "Failed to create log." |
7ee12623 | 286 | case $verbose in |
4ed33f50 MW |
287 | no) exec {log}>&$diag ;; |
288 | yes) exec {log}> >(tee -a $logfile >&$term {term}>&- {diag}>&-) ;; | |
7ee12623 MW |
289 | esac |
290 | ||
c3a2e2b1 MW |
291 | ## Repeat the earlier assignments for tbe benefit of the logfile. |
292 | assign toppath $toppath | |
293 | assign releasepath $releasepath | |
4ed33f50 | 294 | assign logfile $logfile |
c3a2e2b1 | 295 | |
f282ba46 | 296 | ## Do we have a Git repository? |
be2a2314 | 297 | case "$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 |
310 | esac |
311 | ||
312 | ## Is there Debian build equipment? | |
be2a2314 | 313 | case "$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 | ;; |
326 | esac | |
327 | ||
46fced9d MW |
328 | ## Maybe check out a copy of the source. |
329 | case "$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 |
344 | esac |
345 | ||
f282ba46 | 346 | ## Check the version number. |
40196145 | 347 | hack_dch_p=no |
ac1bda22 | 348 | case "$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 | ;; |
364 | esac | |
365 | ||
7ee12623 MW |
366 | ## Maybe refresh the build machinery. |
367 | case "$setup" in | |
368 | yes) | |
9c586ae1 | 369 | run $setupcmd |
7ee12623 MW |
370 | ;; |
371 | esac | |
372 | ||
373 | ## Initialize the build directory. | |
f5b3423e MW |
374 | case "$vpath,$(yesno [ -e $srcpath/configure ])" in |
375 | yes,yes) | |
376 | assign buildpath $releasepath/_build | |
377 | mkdir $buildpath | |
378 | cd $buildpath | |
379 | run $srcpath/configure | |
380 | ;; | |
381 | no,yes) | |
382 | info "VPATH build disabled" | |
383 | assign buildpath $srcpath | |
384 | distcheck=no | |
385 | cd $srcpath | |
386 | run ./configure | |
387 | ;; | |
388 | *,no) | |
389 | info "no configure script" | |
390 | assign buildpath $srcpath | |
391 | cd $srcpath | |
392 | ;; | |
393 | esac | |
7ee12623 MW |
394 | |
395 | ## Discover the release name. | |
396 | cat >find-distdir.mk <<'EOF' | |
397 | include Makefile | |
398 | print-distdir: | |
ab9fae2a | 399 | @echo >&$(fd) $(distdir) |
7ee12623 | 400 | EOF |
dd8d9a6c | 401 | assign distdir \ |
ab9fae2a | 402 | $({ $make -f find-distdir.mk print-distdir fd=$t >/dev/null 2>&1; } {t}>&1) |
7ee12623 MW |
403 | |
404 | ## Get a tarball distribution. | |
405 | case "$distcheck" in | |
406 | yes) | |
ac504698 | 407 | run $make $makeopts distcheck |
7ee12623 MW |
408 | ;; |
409 | no) | |
ac504698 | 410 | run $make $makeopts dist |
7ee12623 MW |
411 | ;; |
412 | esac | |
413 | ||
414 | cd $releasepath | |
415 | ||
d87d7867 MW |
416 | case $native in |
417 | yes) | |
418 | if ! tar tf $buildpath/$distdir.tar.gz 2>/dev/null | grep -q RELEASE | |
419 | then | |
420 | fail "missing RELEASE file in distribution" | |
421 | fi | |
422 | ;; | |
423 | esac | |
7ee12623 MW |
424 | |
425 | run mv $buildpath/$distdir.tar.gz . | |
5a91acc5 MW |
426 | case $build,$sign in |
427 | release,yes) | |
428 | run gpg -u$signkey -ab -o$distdir.tar.gz.gpg $distdir.tar.gz | |
47f56ea2 MW |
429 | ;; |
430 | esac | |
7ee12623 MW |
431 | |
432 | ## Maybe build the Debian packages. | |
f282ba46 MW |
433 | case "$debian" in |
434 | yes) | |
7ee12623 MW |
435 | run tar xvfz $distdir.tar.gz |
436 | cd $distdir | |
40196145 MW |
437 | case $hack_dch in |
438 | yes) | |
40196145 | 439 | cat - debian/changelog >debian/changelog.new <<EOF |
ac1bda22 | 440 | $debsrc ($debversion) experimental; urgency=low |
40196145 MW |
441 | |
442 | * Hacking in process, not intended for release. | |
443 | ||
444 | -- $debname <$debemail> $now | |
445 | ||
446 | EOF | |
447 | mv debian/changelog.new debian/changelog | |
448 | ;; | |
449 | esac | |
e5099dd8 MW |
450 | sbuildargs=$sbuildsrv |
451 | case $sbuild,$build in | |
452 | yes,release) | |
453 | case $sign in yes) sbuildargs="-k$signkey $sbuildargs" ;; esac | |
454 | ;; | |
6cf97414 MW |
455 | yes,*) |
456 | if [ -d $toppath/dist-$build.pkgs ]; then | |
457 | sbuildargs="-p$toppath/dist-$build.pkgs $sbuildargs" | |
458 | fi | |
459 | ;; | |
e5099dd8 | 460 | esac |
ff55a023 MW |
461 | case "$sbuild,$test, $DEB_BUILD_OPTIONS " in |
462 | yes,no,*) sbuildargs="-T $sbuildargs" ;; | |
463 | *" nocheck "*) ;; | |
464 | no,no,*) | |
465 | DEB_BUILD_OPTIONS=${DEB_BUILD_OPTIONS+"$DEB_BUILD_OPTIONS nocheck"} | |
466 | ;; | |
467 | esac | |
b94830d9 | 468 | case $sbuild,$build,$sign in |
e5099dd8 | 469 | yes,*) run mdw-sbuild $sbuildargs ;; |
b94830d9 | 470 | no,release,yes) run dpkg-buildpackage -k$signkey ;; |
5a91acc5 MW |
471 | no,*) run dpkg-buildpackage -us -uc ;; |
472 | esac | |
7ee12623 MW |
473 | ;; |
474 | esac | |
475 | ||
476 | ## Maybe upload Debian packages. | |
477 | cd $releasepath | |
478 | case "$upload,$build" in | |
5a91acc5 MW |
479 | yes,test) info "Test build: not uploading." ;; |
480 | yes,release) run rsync $distdir.tar.gz $distdir.tar.gz.gpg $uploadpath ;; | |
481 | esac | |
482 | case "$debian,$upload,$dput,$build" in | |
483 | yes,yes,yes,release) run dput -f $dputtarget *.changes ;; | |
7ee12623 MW |
484 | esac |
485 | ||
486 | ## Tidy up. | |
487 | case "$clean" in | |
488 | yes) | |
489 | rm -rf $releasepath/$distdir | |
490 | rm -rf $releasepath/_source | |
491 | rm -rf $releasepath/_build | |
492 | ;; | |
493 | esac | |
494 | ||
495 | ## Done. | |
496 | info "All OK." | |
497 | ||
498 | ###----- That's all, folks -------------------------------------------------- |