bin/mdw-sbuild-server: Unbreak local package support.
[profile] / bin / mdw-sbuild-server
CommitLineData
b94830d9
MW
1#! /bin/sh -e
2###
3### Build a Debian package on supported architectures
4###
5### (c) 2016 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### Configuration.
26
27unset buildroot default_targets parallel
28for i in \
29 "/etc/mdw-sbuild.conf" \
30 "${XDG_CONFIG_HOME-$HOME/.config}/mdw-sbuild.conf"
31do
32 if [ -f "$i" ]; then . "$i"; fi
33done
34: ${buildroot=$HOME/build}
35: ${default_targets="wheezy-amd64 wheezy-i386"}
b94830d9
MW
36: ${DEB_BUILD_OPTIONS=parallel=4}; export DEB_BUILD_OPTIONS
37
38###--------------------------------------------------------------------------
39### Some utilities.
40
41prog=${0##*/}
42
43fail () { echo >&2 "$prog: $*"; exit 1; }
ff55a023 44usage () { echo "usage: $prog [-aiknT] [-t TARGET] [-A DBPARGS] COMMAND [ARGUMENTS ...]"; }
b94830d9
MW
45fail_usage () { usage >&2; exit 1; }
46
47want_1 () {
48 what=$1 pat=$2 type=$3; shift 3
49 for i in "$@"; do
50 [ $type "$i" ] || fail "$what not found: \`$i'"
51 done
52 case $# in
53 1) ;;
54 *) fail "expected exactly one $what matching \`$pat', but found $#" ;;
55 esac
56 echo "$1"
57}
58
ba9719eb
MW
59run () {
60 case $notreally in
61 t) echo "+ $*" ;;
5b950572 62 nil) nice "$@" ;;
ba9719eb
MW
63 esac
64}
65
66decor () {
67 tag=$1 marker=$2
68 while IFS= read -r line; do
69 printf "%-21s %c %s\n" "$tag" "$marker" "$line"
70 done
71}
72
b94830d9
MW
73###--------------------------------------------------------------------------
74### Parse options.
75
ba9719eb 76bogusp=nil archp=nil indepp=nil keepon=nil notreally=nil
5e9e7146 77unset targets dbpargs
b94830d9 78
ff55a023 79while getopts "haint:A:T" opt; do
b94830d9
MW
80 case $opt in
81 h)
82 usage
83 cat <<EOF
84
85Options:
86 -h Show this help text.
87 -a Build only architecture-dependent packages.
88 -i Build only architecture-neutral packages.
ba9719eb 89 -k Keep going even if one fails.
b94830d9
MW
90 -n Don't actually do the build.
91 -t TARGET Build in TARGET build environment.
5e9e7146 92 -A ARGS Pass ARGS to \`dpkg-buildpackage'.
ff55a023 93 -T Don't run the tests.
b94830d9
MW
94
95Commands available:
96
97 dir PROJECT/VERSION
98 Return a freshly-made directory for the source code to
99 go in.
100
101 build BUILDDIR
102 Build the package placed in BUILDDIR, which should contain
103 exactly one \`.dsc' file, and whatever source archive files
104 are necessary.
105EOF
106 exit
107 ;;
108 a) archp=t ;;
109 i) indepp=t ;;
ba9719eb
MW
110 k) keepon=t ;;
111 n) notreally=t ;;
b94830d9 112 t) targets="${targets+$targets }$OPTARG" ;;
5e9e7146 113 A) dbpargs="${dbpargs+$dbpargs }$OPTARG" ;;
ff55a023
MW
114 T)
115 case " $DEB_BUILD_OPTIONS " in
116 *" nocheck "*) ;;
117 *) DEB_BUILD_OPTIONS=${DEB_BUILD_OPTIONS+"$DEB_BUILD_OPTIONS "} nocheck ;;
118 esac
119 ;;
b94830d9
MW
120 *) bogusp=nil ;;
121 esac
122done
123shift $(( $OPTIND - 1 ))
124
125case $bogusp in t) fail_usage ;; esac
126case $archp,$indepp in nil,nil) archp=t indepp=t ;; esac
127case ${targets+t} in t) ;; *) targets=$default_targets ;; esac
128
129###--------------------------------------------------------------------------
130### Main work.
131
132case "$#,$1" in
133 0,*) fail_usage ;;
134 *,*,*) fail "bad command name \`$1'" ;;
135
136 2,dir)
137 ## dirname PROJECT/VERSION
138
139 ## Try to create a fresh build directory.
140 dist=$2
141 case "$dist" in */*/*) fail "bad distribution name \`$dist'" ;; esac
142 proj=${dist%/*} ver=${dist#*/}
143 cd "$buildroot"
144 mkdir -p "$proj"
145 cd "$proj"
146 i=0
147 winp=nil
148 while [ $i -lt 50 ]; do
149 i=$(( $i + 1 ))
150
151 ## Find a sequence number different from all of the existing builds of
152 ## this version.
153 nn=1
154 for j in "$ver#"*; do
155 case "$j" in "$ver#*") break ;; esac
156 n=${j##*\#}
157 if [ $nn -le $n ]; then nn=$(( $n + 1 )); fi
158 done
159
160 ## Try to make the build directory. This might not work if we're
161 ## racing with another process, but that's why we're trying in a loop.
162 if mkdir "$ver#$nn" >/dev/null 2>&1; then
163 winp=t
6cf97414 164 cd "$ver#$nn"
b94830d9
MW
165 break
166 fi
167
168 ## Make sure it actually failed because a directory appeared, rather
169 ## than for some other reason.
170 [ -e "$ver#$nn" ] || \
171 fail "unexpectedly couldn't create \`$buildroot/$dist#$nn'"
172 done
173
174 ## Make sure we actually succeeded.
175 case $winp in t) ;; *) fail "failed to create build directory" ;; esac
176
6cf97414
MW
177 ## Make an empty directory for dependency packages.
178 mkdir -p pkgs/
179
b94830d9
MW
180 ## Done.
181 echo "$buildroot/$dist#$nn"
182 ;;
183
184 *,dir)
185 echo >&2 "usage: $prog dir PROJECT/VERSION"; exit 1 ;;
186
187 2,build)
188 ## build BUILDDIR
189
190 ## Track down the build directory.
191 builddir=$2
192 cd "$builddir"
193 dsc=$(want_1 "file" "*.dsc" -f *.dsc)
194
195 ## Figure out which targets need building. If the `.dsc' file isn't
196 ## telling, assume it needs building everywhere and let sbuild(1) sort
197 ## out the mess.
198 os=$(dpkg-architecture -qDEB_HOST_ARCH_OS)
199 unset first rest; anyp=nil depp=nil allp=nil
200 wantarchs=$(sed -n '/^[Aa]rchitecture:/ s/^[^:]*: *//p' "$dsc")
201 : ${wantarchs:=any}
be0b4ef6 202 unset buildarchs buildarchs_seen=:
b94830d9
MW
203
204 ## Work through the available targets assigning builds to them. This is
205 ## actually a little tricky.
206 for t in $targets; do
207
92b05c85
MW
208 ## Dissect the target name.
209 suite=${t%%-*} archs=${t#*-}
210 case $archs in
211 */*) target=${archs%/*} host=${archs#*/} ;;
212 *) target=$archs host=$archs; t=$suite-$target/$host ;;
213 esac
be0b4ef6
MW
214 case $buildarchs_seen in
215 *:$target:*)
216 ;;
217 *)
218 buildarchs=${buildarchs+$buildarchs }$target
219 buildarchs_seen=$buildarchs_seen$target:
220 ;;
221 esac
92b05c85 222
b94830d9
MW
223 ## Work through the architectures which we can build.
224 for arch in $wantarchs; do
225 case $arch in
226 all)
227 ## Package suitable for all architectures.
228
229 ## If we don't want to build architecture-neutral packages then
230 ## there's nothing to do.
231 case $indepp in nil) continue ;; esac
232
233 ## Pick this up if nobody has volunteered. However, we should be
234 ## ready to let some other architecture build this if it's going
235 ## to build some architecture-dependent package too.
236 case $anyp in nil) first=$t anyp=t allp=t ;; esac
237 ;;
238 *)
239 ## There's at least one architecture-specific package.
240
28f48d70 241 ## If we don't want to build architecture-specific packages then
b94830d9
MW
242 ## there's nothing to do.
243 case $archp in nil) continue ;; esac
244
245 ## If we can't build it then we shouldn't try.
92b05c85 246 if ! dpkg-architecture -a"$os-$target" -i"$arch"; then
b94830d9
MW
247 continue
248 fi
249
250 ## Decide whether we should take responsibility for the
251 ## architecture-neutral packages. If nobody's claimed them yet,
252 ## or the previous claimant wasn't building architecture-specific
253 ## packages, we should take over.
254 case $depp in
255 nil) first=$t depp=t anyp=t ;;
256 t) rest="${rest+$rest }$t" ;;
257 esac
258 ;;
259 esac
260 done
261 done
262
263 ## If we never found a match then we can't do anything.
264 case $anyp in nil) echo "$prog: no packages to build"; exit 0 ;; esac
265
266 ## Figure out the right options to use.
267 case $indepp in
268 t) firstopt="--arch-all" ;;
269 nil) firstopt="--no-arch-all" ;;
270 esac
271 case $archp in
272 t) ;;
ea91eab4 273 nil) firstopt="$firstopt --no-arch-any" ;;
b94830d9
MW
274 esac
275
6cf97414
MW
276 ## Sort out the additional packages. This is rather annoying, because
277 ## sbuild(1) does this in a really stupid way.
278 rm -rf pkgs.*
279 for a in $buildarchs; do
280 mkdir pkgs.$a
281 for f in $(dpkg-scanpackages -a$a pkgs/ |
282 sed -n '/^Filename: /s///p')
283 do
284 ln $f pkgs.$a/
285 done
286 done
287
ba9719eb
MW
288 ## Build the builds sequentially. Tests can conflict with each other,
289 ## e.g., over port numbers.
290 rc=0 buildopt=$firstopt
291 for t in $first $rest; do
292 host=${t##*/} full=${t%/*}
293 suite=${full%%-*} target=${full#*-}
294
295 ## And we're ready to go.
296 exec 3>&1
297 thisrc=$(
298 { { { { set +e
bac824a6 299 run sbuild --extra-package=pkgs.$target \
ba9719eb
MW
300 --dist=$suite --build=$host --host=$target \
301 --chroot=$suite-$host --verbose $buildopt $dsc \
5e9e7146 302 ${dbpargs+--debbuildopts="$dbpargs"} \
ba9719eb
MW
303 3>&- 4>&- 5>&-
304 echo $? >&5
305 } |
306 decor "$full" "|" >&4; } 2>&1 |
307 decor "$full" "*" >&4; } 4>&1 |
308 cat -u >&3; } 5>&1 </dev/null)
309 exec 3>&-
310 case $thisrc in 0) ;;
311 *)
312 echo failed rc=$thisrc >$stat; rc=$thisrc
313 case $keepon in nil) break ;; esac
314 ;;
315 esac
316 buildopt=--no-arch-all
317 done
b94830d9
MW
318 exit $rc
319 ;;
320 build,*)
321 echo >&2 "usage: $prog build BUILDDIR"; exit 1 ;;
322
323 *)
324 fail "unknown command \`$1'"
325 ;;
326esac
327
328###----- That's all, folks --------------------------------------------------