updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / archbuilder / archbuilder
blob0e297b836aa2057063d6afa40af7df86cf7ab20d
1 #!/bin/sh
3 # User overridable settings
4 PREFIX=/var/cache/archbuilder
5 CHROOT=$PREFIX/chroot.$$
6 CACHE=$PREFIX/cache
7 RESULT=$( pwd )
8 CHOWN=root
9 COLOR=1
10 PACMAN_PKG=""
11 PACMAN_BIN="pacman"
13 # Private settings
14 COREPKGS="glibc pacman coreutils filesystem sudo $PACMAN_PKG" # sudo is here to have it available on archbuilder shell
15 BASEPKGS="binutils cpio file findutils gawk gettext grep gzip less pcre perl popt ppp sed tar util-linux-ng vi wget which gcc patch pkgconfig make diffutils fakeroot"
16 CONFIGFILES="/etc/pacman.conf /etc/resolv.conf"
17 VERSION="0.6"
18 SILENT=">/dev/null"
21 error() {
22 if [ $COLOR -ne 0 ]; then
23 log "\e[31m$*\e[0m"
24 else
25 log "$*"
29 log() {
30 if [ $COLOR -ne 0 ]; then
31 echo "\e[34marchbuilder:\e[0m $*"
32 else
33 echo "archbuilder: $*"
37 li() {
38 if [ $COLOR -ne 0 ]; then
39 log "\e[33m - \e[0m$*"
40 else
41 log " - $*"
45 chroot() {
46 if [ "$*" ]; then
47 local CMD="$*"
48 else
49 local CMD="/bin/sh -i"
51 #echo "CHROOTCMD: /usr/sbin/chroot $CHROOT /bin/sh -c \"HOME=/root; $CMD\""
52 /usr/sbin/chroot $CHROOT /bin/sh -c "HOME=/root; unset LANG; $CMD"
55 rescue_packages() {
56 local F=$CHROOT/var/cache/pacman/pkg
57 local T=$CACHE/pkg
58 test -e $F || return 0
59 mkdir -p $T
61 if [ -e $F -a "$( ls $F | wc -l )" -gt 0 ]; then
62 for fn in $F/*; do
63 local bn=$( basename $fn )
64 if ! [ -e $T/$bn ]; then
65 test "$HEADER" || log "Caching packages"
66 local HEADER=1
67 li "$bn"
68 ln $F/$bn $T/$bn
70 done
74 rescue_syncdb() {
75 log "Caching sync db"
76 mkdir -p $CACHE/sync
77 rsync -a --del $CHROOT/var/lib/pacman/sync/ $CACHE/sync
80 prepare_chroot() {
81 log "Creating chroot ($CHROOT)"
82 mkdir -p $CACHE
83 mkdir -p $CHROOT
84 mkdir -p $CHROOT/dev
85 mkdir -p $CHROOT/var/cache/pacman/pkg
86 mkdir -p $CHROOT/var/lib/pacman/sync
88 mknod $CHROOT/dev/console c 5 1
89 mknod $CHROOT/dev/null c 1 3
90 mknod $CHROOT/dev/zero c 1 5
91 mknod $CHROOT/dev/random c 1 8
92 mknod $CHROOT/dev/urandom c 1 9
94 chmod 600 $CHROOT/dev/console
95 chmod 666 $CHROOT/dev/{null,zero,random,urandom}
96 chmod 666 $CHROOT/dev/{null,zero,random,urandom}
98 mkdir $CHROOT/proc
99 mount none $CHROOT/proc -t proc
102 restore_packages() {
103 log "Restoring cached packages"
104 local F=$CACHE/pkg
105 local T=$CHROOT/var/cache/pacman/pkg
106 mkdir -p $T
107 #if [ -e $F -a "$( ls $F | wc -l )" -gt 0 ]; then
108 #for fn in $F/*; do
109 #local bn=$( basename $fn )
110 #ln $F/$bn $T/$bn
111 #done
113 test -d $F -a $(ls $F|wc -l) -gt 0 && cp -l $F/* $T
116 restore_syncdb() {
117 if ! [ -e $CACHE/sync ]; then
118 error "No sync db cache found; run archbuilder init first"
119 cleanup_chroot
120 exit 1
122 log "Restoring sync db"
123 if ! cp -al $CACHE/sync/* $CHROOT/var/lib/pacman/sync; then
124 error "Error when restoring sync db"
125 cleanup_chroot
126 exit 1
130 copy_config() {
131 log "Copying config files from host"
132 for fn in $CONFIGFILES; do
133 li "$fn"
134 cp $fn $CHROOT/$fn
135 done
138 create_user() {
139 log "Creating archbuilder user"
140 echo "archbuilder:x:1234:100:Arch Builder,,,:/tmp/build:/bin/sh" >> $CHROOT/etc/passwd
141 echo "archbuilder::14117:0:99999:7:::" >> $CHROOT/etc/shadow
142 echo "archbuilder ALL=NOPASSWD: ALL" >> $CHROOT/etc/sudoers
143 mkdir -p $CHROOT/tmp/build
144 chown 1234 $CHROOT/tmp/build
147 install_corepkgs() {
148 log "Installing core packages"
149 if ! sh -c "$PACMAN_BIN -S -r $CHROOT --cachedir $CHROOT/var/cache/pacman/pkg -b $CHROOT/var/lib/pacman --noconfirm $COREPKGS $SILENT"; then
150 error "Error installing pacman, cleaning up"
151 cleanup_chroot
152 exit 1
156 create_chroot() {
157 prepare_chroot
158 restore_packages
159 restore_syncdb
160 install_corepkgs
161 copy_config
162 create_user
165 cleanup_chroot() {
166 rescue_packages
168 trap - SIGINT # Reset sigint so that if the user hammers ^C it wont loop
170 test -d $CHROOT/proc && umount $CHROOT/proc
172 log "Removing chroot"
173 rm -rf $CHROOT
176 init() {
177 prepare_chroot
178 #install_corepkgs
179 log "Installing core packages"
180 # powerpill 15.9-1 fails with this, so no $PACMAN_BIN here
181 if ! sh -c "pacman -Sy -r $CHROOT --cachedir $CHROOT/var/cache/pacman/pkg -b $CHROOT/var/lib/pacman --noconfirm $COREPKGS $SILENT"; then
182 error "Error installing pacman, cleaning up"
183 cleanup_chroot
184 exit 1
187 copy_config
189 log "Downloading base packages"
190 if ! chroot "$PACMAN_BIN -Sw --noconfirm $COREPKGS $BASEPKGS $SILENT"; then
191 error "Error downloading base packages, cleaning up"
192 cleanup_chroot
193 exit 1
196 rescue_syncdb
197 cleanup_chroot
200 update() {
201 create_chroot
203 log "Downloading updates"
204 if ! chroot "$PACMAN_BIN -Syuw --noconfirm $SILENT"; then
205 error "Error syncing & downloading packages"
206 cleanup_chroot
207 exit 1
210 rescue_syncdb
211 cleanup_chroot
214 copy_pkgbuild() {
215 local T=$1
216 mkdir -p $T
218 log "Copying PKGBUILD and related files"
220 li "PKGBUILD"
221 cp PKGBUILD $T/PKGBUILD
223 local INSTALL=$( CARCH=$(arch); . ./PKGBUILD && echo $install )
224 if [ "$INSTALL" -a -e $INSTALL ]; then
225 li "$INSTALL"
226 cp $INSTALL $T/$INSTALL
229 local SOURCES=$( CARCH=$(arch); . ./PKGBUILD && echo ${source[*]} )
230 if [ "$SOURCES" ]; then
231 for SOURCE in $SOURCES; do
232 if [ -e "$SOURCE" ]; then
233 li "$SOURCE"
234 cp $SOURCE $T/$SOURCE
235 else
236 if [ -e "$( basename $SOURCE )" ]; then
237 local SOURCE=$( basename $SOURCE )
238 li "$SOURCE"
239 cp $SOURCE $T/$SOURCE
240 elif [ "$SOURCE" = "$( basename $SOURCE )" ]; then
241 # TODO: Add --ignoremissingsource
242 error "Source \"$SOURCE\" not found"
243 cleanup_chroot
244 exit 1
247 done
250 local PKGNAME=$( . ./PKGBUILD && echo $pkgname )
251 if echo $PKGNAME | grep -q -- '-git$'; then
252 local GITNAME=$( . ./PKGBUILD && echo $_gitname )
253 if [ "$GITNAME" -a -d "$GITNAME" -a -d "$GITNAME/.git" ]; then
254 li "$GITNAME git repo"
255 mkdir -p "$T/src"
256 cp -r "$GITNAME" "$T/src"
258 elif echo $PKGNAME | grep -q -- '-svn$'; then
259 local SVNMOD=$( . ./PKGBUILD && echo $_svnmod )
260 if [ "$SVNMOD" -a -d "$SVNMOD" -a -d "$SVNMOD/.svn" ]; then
261 li "$SVNMOD svn repo"
262 mkdir -p "$T/src"
263 cp -r "$SVNMOD" "$T/src"
267 unset CARCH
270 shell() {
271 create_chroot
273 test "$OPT_COPYPKGBUILD" && copy_pkgbuild "$CHROOT/tmp/build"
274 log "Entering chroot"
275 chroot "su - archbuilder"
277 cleanup_chroot
280 build() {
281 if ! [ -e PKGBUILD ]; then
282 error "No PKGBUILD file found"
283 exit 1
286 create_chroot
288 local T=$CHROOT/tmp/build
290 copy_pkgbuild "$T"
292 local VERDEPENDS=$( . ./PKGBUILD && echo ${depends[*]} ${makedepends[*]} )
293 if [ "$VERDEPENDS" ]; then
294 for DEP in $VERDEPENDS; do
295 local DEPENDS="$DEPENDS $( echo $DEP | sed 's,[\<|\>|\=].*$,,' )"
296 done
299 log "Installing base packages & dependencies"
300 if ! chroot "$PACMAN_BIN --noconfirm -S $BASEPKGS $DEPENDS $SILENT"; then
301 error "Error installing dependencies"
302 cleanup_chroot
303 exit 1
306 log "Building package"
307 if ! chroot "su - archbuilder -c \"makepkg --noconfirm\""; then
308 error "Error building package"
309 if [ "$OPT_SHELLONERROR" ]; then
310 log "Invoking shell as requested"
311 chroot "su - archbuilder"
313 cleanup_chroot
314 exit 1
317 local ARCH="$( . $T/PKGBUILD && echo $arch )"
318 test $ARCH = "any" || ARCH=$(arch)
319 local PKGNAME=$( CARCH=$(arch); . $T/PKGBUILD && echo $pkgname )
320 local PKGVER=$( CARCH=$(arch); . $T/PKGBUILD && echo $pkgver )
321 local PKGREL=$( CARCH=$(arch); . $T/PKGBUILD && echo $pkgrel )
322 local PKGFULL=$PKGNAME-$PKGVER-$PKGREL-$ARCH.pkg.tar.gz
323 if [ -e $T/$PKGFULL ]; then
324 mv $T/$PKGFULL $RESULT/$PKGFULL
325 test "$CHOWN" && chown $CHOWN $RESULT/$PKGFULL
326 else
327 error "Unable to find resulting package, expected $PKGFULL"
328 if [ "$OPT_SHELLONERROR" ]; then
329 log "Invoking shell as requested"
330 chroot "su - archbuilder"
332 cleanup_chroot
333 exit 1
336 if ! cmp -s $T/PKGBUILD PKGBUILD; then
337 log "PKGBUILD changed, copying back"
338 cp $T/PKGBUILD PKGBUILD
339 test "$CHOWN" && chown "$CHOWN" PKGBUILD
342 cleanup_chroot
345 sanity_check() {
346 if [ "$(id -u)" -ne 0 ]; then
347 error "archbuilder must be run as root"
348 exit 1
351 if [ $( basename ${CACHE}x ) = "x" ]; then
352 error "CACHE must not end with /"
353 exit 1
356 if [ $( basename ${CHROOT}x ) = "x" ]; then
357 error "CHROOT must not end with /"
358 exit 1
361 if [ $( basename ${RESULT}x ) = "x" ]; then
362 error "RESULT must not end with /"
363 exit 1
366 # Test that CHROOT & CACHE is on the same filesystem and supports hard links
367 test -e "$CHROOT" || mkdir -p "$CHROOT"
368 test -e "$CACHE" || mkdir -p "$CACHE"
370 touch $CACHE/test
371 touch $CHROOT/test
373 if [ "$( stat -c %d $CACHE/test )" -ne $( stat -c %d $CHROOT/test ) ]; then
374 error "CACHE and CHROOT must be on the same filesystem"
375 rm -f $CACHE/test $CHROOT/test $CHROOT/test2 $CACHE/test2
376 exit 1
379 if ! ln $CACHE/test $CHROOT/test2 2>/dev/null >/dev/null; then
380 error "Needs a filesystem that supports hard-links"
381 rm -f $CACHE/test $CHROOT/test $CHROOT/test2 $CACHE/test2
382 exit 1
384 rm -f $CACHE/test $CHROOT/test $CHROOT/test2 $CACHE/test2
386 # Test if the filesystem supports devices
387 if ! mknod $CHROOT/null c 1 3; then
388 error "Chroot filesystem doesn't support devices"
389 exit 1
391 if ! echo "test" | tee $CHROOT/null >/dev/null 2>/dev/null; then
392 error "Chroot filesystem doens't support devices"
393 rm -f $CHROOT/null
394 exit 1
396 rm -f $CHROOT/null
398 # Test if the filesystem supports suid binaries
399 touch $CHROOT/suid
400 if ! chmod +s $CHROOT/suid; then
401 error "Chroot filesystem doens't support suid binarys"
402 rm $CHROOT/suid
403 exit 1
405 rm $CHROOT/suid
408 usage() {
409 echo "ArchBuilder $VERSION"
410 echo ""
411 echo "Usage: archbuilder command [options]"
412 echo ""
413 echo "Commands:"
414 echo "init - Populates sync cache"
415 echo "update - Updates sync cache"
416 echo "shell - Runs a shell in a temporary chroot"
417 echo "build - Builds a package"
418 echo ""
419 echo "Options:"
420 echo " --copypkgbuild - Copies the PKGBUILD to the chroot, only for shell"
421 echo " --shellonerror - Starts a shell when the package fails to build, only for build"
422 echo " --verbose - Show pacman output"
425 CMD=$1
426 while test "$1"; do
427 case "$1" in
428 --copypkgbuild) OPT_COPYPKGBUILD=1 ;;
429 --shellonerror) OPT_SHELLONERROR=1 ;;
430 --verbose) OPT_VERBOSE=1 ;;
431 --help) usage; exit 0 ;;
432 --*) error "Unknown option \"$1\"" ; exit 1 ;;
433 esac
434 shift 1
435 done
437 if ! [ "$CMD" ]; then
438 usage
439 exit 0
442 test "$OPT_VERBOSE" && SILENT=""
444 trap cleanup_chroot SIGINT
446 # Load user settings
447 if test -e ~/.archbuilderrc; then
448 log "Loading user settings (~/.archbuilderrc)"
449 . ~/.archbuilderrc
450 else
451 log "User settings not found (~/.archbuilderrc)"
454 case "$CMD" in
455 init)
456 sanity_check
457 init
459 shell)
460 sanity_check
461 shell
463 build)
464 sanity_check
465 build
467 update)
468 sanity_check
469 update
472 error "Unknown command: $CMD"
473 exit 1
475 esac