3 ### Build a Debian package on supported architectures
5 ### (c) 2016 Mark Wooding
8 ###----- Licensing notice ---------------------------------------------------
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.
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.
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.
24 ###--------------------------------------------------------------------------
27 unset buildroot default_targets parallel
29 "/etc/mdw-sbuild.conf" \
30 "${XDG_CONFIG_HOME-$HOME/.config}/mdw-sbuild.conf"
32 if [ -f "$i" ]; then . "$i"; fi
34 : ${buildroot=$HOME/build}
35 : ${default_targets="wheezy-amd64 wheezy-i386"}
37 : ${DEB_BUILD_OPTIONS=parallel=4}; export DEB_BUILD_OPTIONS
39 ###--------------------------------------------------------------------------
44 fail () { echo >&2 "$prog: $*"; exit 1; }
45 usage () { echo "usage: $prog [-ain] [-t TARGET] COMMAND [ARGUMENTS ...]"; }
46 fail_usage () { usage >&2; exit 1; }
49 what=$1 pat=$2 type=$3; shift 3
51 [ $type "$i" ] || fail "$what not found: \`$i'"
55 *) fail "expected exactly one $what matching \`$pat', but found $#" ;;
60 ###--------------------------------------------------------------------------
63 bogusp=nil archp=nil indepp=nil makeopts=""
66 while getopts "haint:" opt; do
73 -h Show this help text.
74 -a Build only architecture-dependent packages.
75 -i Build only architecture-neutral packages.
76 -n Don't actually do the build.
77 -t TARGET Build in TARGET build environment.
82 Return a freshly-made directory for the source code to
86 Build the package placed in BUILDDIR, which should contain
87 exactly one \`.dsc' file, and whatever source archive files
94 n) makeopts="${makeopts+$makeopts }-n" ;;
95 t) targets="${targets+$targets }$OPTARG" ;;
99 shift $(( $OPTIND - 1 ))
101 case $bogusp in t) fail_usage ;; esac
102 case $archp,$indepp in nil,nil) archp=t indepp=t ;; esac
103 case ${targets+t} in t) ;; *) targets=$default_targets ;; esac
105 ###--------------------------------------------------------------------------
110 *,*,*) fail "bad command name \`$1'" ;;
113 ## dirname PROJECT/VERSION
115 ## Try to create a fresh build directory.
117 case "$dist" in */*/*) fail "bad distribution name \`$dist'" ;; esac
118 proj=${dist%/*} ver=${dist#*/}
124 while [ $i -lt 50 ]; do
127 ## Find a sequence number different from all of the existing builds of
130 for j in "$ver#"*; do
131 case "$j" in "$ver#*") break ;; esac
133 if [ $nn -le $n ]; then nn=$(( $n + 1 )); fi
136 ## Try to make the build directory. This might not work if we're
137 ## racing with another process, but that's why we're trying in a loop.
138 if mkdir "$ver#$nn" >/dev/null 2>&1; then
143 ## Make sure it actually failed because a directory appeared, rather
144 ## than for some other reason.
145 [ -e "$ver#$nn" ] || \
146 fail "unexpectedly couldn't create \`$buildroot/$dist#$nn'"
149 ## Make sure we actually succeeded.
150 case $winp in t) ;; *) fail "failed to create build directory" ;; esac
153 echo "$buildroot/$dist#$nn"
157 echo >&2 "usage: $prog dir PROJECT/VERSION"; exit 1 ;;
162 ## Track down the build directory.
165 dsc=$(want_1 "file" "*.dsc" -f *.dsc)
167 ## Figure out which targets need building. If the `.dsc' file isn't
168 ## telling, assume it needs building everywhere and let sbuild(1) sort
170 os=$(dpkg-architecture -qDEB_HOST_ARCH_OS)
171 unset first rest; anyp=nil depp=nil allp=nil
172 wantarchs=$(sed -n '/^[Aa]rchitecture:/ s/^[^:]*: *//p' "$dsc")
175 ## Work through the available targets assigning builds to them. This is
176 ## actually a little tricky.
177 for t in $targets; do
179 ## Work through the architectures which we can build.
180 for arch in $wantarchs; do
183 ## Package suitable for all architectures.
185 ## If we don't want to build architecture-neutral packages then
186 ## there's nothing to do.
187 case $indepp in nil) continue ;; esac
189 ## Pick this up if nobody has volunteered. However, we should be
190 ## ready to let some other architecture build this if it's going
191 ## to build some architecture-dependent package too.
192 case $anyp in nil) first=$t anyp=t allp=t ;; esac
195 ## There's at least one architecture-specific package.
197 ## If we don't want to build architecture-specific package then
198 ## there's nothing to do.
199 case $archp in nil) continue ;; esac
201 ## If we can't build it then we shouldn't try.
202 if ! dpkg-architecture -a"$os-${t#*-}" -i"$arch"; then
206 ## Decide whether we should take responsibility for the
207 ## architecture-neutral packages. If nobody's claimed them yet,
208 ## or the previous claimant wasn't building architecture-specific
209 ## packages, we should take over.
211 nil) first=$t depp=t anyp=t ;;
212 t) rest="${rest+$rest }$t" ;;
219 ## If we never found a match then we can't do anything.
220 case $anyp in nil) echo "$prog: no packages to build"; exit 0 ;; esac
222 ## Figure out the right options to use.
224 t) firstopt="--arch-all" ;;
225 nil) firstopt="--no-arch-all" ;;
229 nil) firstopt="$firstopt --debbuildopt=-A" ;;
232 ## Build a cheesy makefile to run these in parallel.
240 { echo started >build-status.\$\$t; \\
242 --dist=\$\${t%-*} --arch=\$\${t\#*-} \\
243 --chroot=\$@ --verbose \$1 \$(DSC); \\
244 rc=\$\$?; case \$\$rc in \\
245 0) echo ok >build-status.\$\$t ;; \\
246 *) echo failed rc=\$\$rc >build-status.\$\$t ;; \\
248 while IFS= read -r line; do \\
249 printf "%s: %s\n" "\$\$t" "\$\$line"; \\
251 read st _ <build-status.\$\$t && \\
252 case \$\$st in ok) exit 0 ;; *) exit 1 ;; esac
253 all: \$(FIRST) \$(REST)
254 \$(FIRST):; \$(call sbuild-wrap,$firstopt)
255 \$(REST):; \$(call sbuild-wrap,--no-arch-all)
258 ## Make some marker files to say things are in progress.
259 for i in $first $rest; do echo "starting" >build-status.$i; done
261 ## And we're ready to go.
263 cat pipeout& catpid=$!
264 set +e; make -fbuild.mk $parallel $makeopts -k all >pipeout
267 rm build.mk pipeout build-status.*
268 find . -maxdepth 1 -type l -exec rm {} \;
272 echo >&2 "usage: $prog build BUILDDIR"; exit 1 ;;
275 fail "unknown command \`$1'"
279 ###----- That's all, folks --------------------------------------------------