chiark / gitweb /
bin/disorder-notify, dot/e16-bindings: Use `notify-send', not `gdbus'.
[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 [-v] 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 "hv" 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 toppath $(pwd)
245 assign srcpath $toppath
246
247 ## Build any necessary qualifiers.
248 qual= sep=.
249 case ${SBOX_SESSION_DIR+t},${DEB_BUILD_ARCH+t} in
250   t,t) qual=$qual$sep$DEB_BUILD_ARCH; sep=- ;;
251   t,*) fail "unknown build arch" ;;
252 esac
253
254 ## Construct the output directory.
255 assign releasepath $srcpath/dist-$build$qual
256 chmod -R +w $releasepath 2>/dev/null || :
257 rm -rf $releasepath 2>/dev/null || :
258 mkdir $releasepath
259 case $verbose in
260   no)
261     exec 4>$releasepath/mdw-build.log 3>&4 ||
262       fail "Failed to create log."
263     ;;
264 esac
265
266 ## Do we have a Git repository?
267 case "$checkout,$setup,$(yesno [ -d $srcpath/.git ])" in
268   yes,no,*)
269     fail "Inconsistent options: can't check out without setup."
270     ;;
271   yes,yes,no)
272     info "No Git repository found."
273     checkout=no gitver=none
274     ;;
275   yes,yes,yes)
276     cd $srcpath
277     [ "$(git ls-files -m)" = "" ] ||
278       warn "working tree has uncommitted changes"
279     ;;
280 esac
281
282 ## Is there Debian build equipment?
283 case "$debian,$(yesno [ -d $srcpath/debian ])" in
284   yes,no)
285     info "No debian directory found."
286     debian=no debver=none
287     ;;
288   no,*)
289     debver=none
290     ;;
291   yes,yes)
292     debver=$(dpkg-parsechangelog | sed -n 's/^Version: //p')
293     debsrc=$(dpkg-parsechangelog | sed -n 's/^Source: //p')
294     debname=$(git config user.name) debemail=$(git config user.email)
295     ;;
296 esac
297
298 ## Maybe check out a copy of the source.
299 case "$checkout" in
300   yes)
301     cd $releasepath
302     run git clone -sn $srcpath/.git _source
303     assign srcpath $releasepath/_source
304     cd $srcpath
305     run git update-ref refs/heads/mdw-build $checkoutrev ""
306     run git symbolic-ref HEAD refs/heads/mdw-build
307     run git read-tree --reset refs/heads/mdw-build
308     run git checkout-index -afu
309     assign gitversion "$(git describe --abbrev=4)"
310     ;;
311 esac
312
313 ## Check the version number.
314 hack_dch_p=no
315 case "$gitversion,$debver" in
316   none,* | *,none)
317     ;;
318   *)
319     dvref=$(echo "$debver" | tr '~' '_')
320     if [ "$gitversion" = "$dvref" ]; then
321       assign debversion "$debver"
322     else
323       warn "Git version $gitversion doesn't match Debian version $debver"
324       hack_dch=yes
325       dver=$(echo $gitversion | sed 's/-/+/; s/-/./g')
326       case $debver in *~) dver=$debver$dver ;; esac
327       assign debversion "$dver"
328       now=$(date -R)
329     fi
330     ;;
331 esac
332
333 ## Maybe refresh the build machinery.
334 case "$setup" in
335   yes)
336     run $setupcmd
337     ;;
338 esac
339
340 ## Initialize the build directory.
341 case "$vpath,$(yesno [ -e $srcpath/configure ])" in
342   yes,yes)
343     assign buildpath $releasepath/_build
344     mkdir $buildpath
345     cd $buildpath
346     run $srcpath/configure
347     ;;
348   no,yes)
349     info "VPATH build disabled"
350     assign buildpath $srcpath
351     distcheck=no
352     cd $srcpath
353     run ./configure
354     ;;
355   *,no)
356     info "no configure script"
357     assign buildpath $srcpath
358     cd $srcpath
359     ;;
360 esac
361
362 ## Discover the release name.
363 cat >find-distdir.mk <<'EOF'
364 include Makefile
365 print-distdir:
366         @echo >&3 $(distdir)
367 EOF
368 assign distdir \
369         $({ make -f find-distdir.mk print-distdir >/dev/null 2>&1; } 3>&1)
370
371 ## Get a tarball distribution.
372 case "$distcheck" in
373   yes)
374     run make $makeopts distcheck
375     ;;
376   no)
377     run make $makeopts dist
378     ;;
379 esac
380
381 cd $releasepath
382
383 case $native in
384   yes)
385     if ! tar tf $buildpath/$distdir.tar.gz 2>/dev/null | grep -q RELEASE
386     then
387       fail "missing RELEASE file in distribution"
388     fi
389     ;;
390 esac
391
392 run mv $buildpath/$distdir.tar.gz .
393 case $build,$sign in
394   release,yes)
395     run gpg -u$signkey -ab -o$distdir.tar.gz.gpg $distdir.tar.gz
396     ;;
397 esac
398
399 ## Maybe build the Debian packages.
400 case "$debian" in
401   yes)
402     run tar xvfz $distdir.tar.gz
403     cd $distdir
404     case $hack_dch in
405       yes)
406         cat - debian/changelog >debian/changelog.new <<EOF
407 $debsrc ($debversion) experimental; urgency=low
408
409   * Hacking in process, not intended for release.
410
411  -- $debname <$debemail>  $now
412
413 EOF
414         mv debian/changelog.new debian/changelog
415         ;;
416     esac
417     sbuildargs=$sbuildsrv
418     case $sbuild,$build in
419       yes,release)
420         case $sign in yes) sbuildargs="-k$signkey $sbuildargs" ;; esac
421         ;;
422       yes,*)
423         if [ -d $toppath/dist-$build.pkgs ]; then
424           sbuildargs="-p$toppath/dist-$build.pkgs $sbuildargs"
425         fi
426         ;;
427     esac
428     case $sbuild,$build,$sign in
429       yes,*) run mdw-sbuild $sbuildargs ;;
430       no,release,yes) run dpkg-buildpackage -k$signkey ;;
431       no,*) run dpkg-buildpackage -us -uc ;;
432     esac
433     ;;
434 esac
435
436 ## Maybe upload Debian packages.
437 cd $releasepath
438 case "$upload,$build" in
439   yes,test) info "Test build: not uploading." ;;
440   yes,release) run rsync $distdir.tar.gz $distdir.tar.gz.gpg $uploadpath ;;
441 esac
442 case "$debian,$upload,$dput,$build" in
443   yes,yes,yes,release) run dput -f $dputtarget *.changes ;;
444 esac
445
446 ## Tidy up.
447 case "$clean" in
448   yes)
449     rm -rf $releasepath/$distdir
450     rm -rf $releasepath/_source
451     rm -rf $releasepath/_build
452     ;;
453 esac
454
455 ## Done.
456 info "All OK."
457
458 ###----- That's all, folks --------------------------------------------------