projects/aports·blob v1.7 · refs

689 lines · 15.5 KiB

1#!/bin/sh
2
3# script to build apk packages (light version og makepkg)
4# Copyright (c) 2008 Natanael Copa <[email protected]>
5#
6# Distributed under GPL-2
7#
8# Depends on: busybox utilities, fakeroot,
9#
10
11abuild_ver=1.6
12
13startdir="$PWD"
14srcdir=${srcdir:-"$startdir/src"}
15pkgdir=${pkgdir:-"$startdir/pkg"}
16pkgrel=0
17repo=${startdir%/*}
18repo=${repo##*/}
19
20# defaults
21SRCDEST=${SRCDEST:-$startdir}
22PKGDEST=${PKGDEST:-$startdir}
23BUILD_BASE="binutils gcc make patch uclibc-dev"
24
25default_cmds="sanitycheck builddeps clean fetch unpack rootpkg"
26
27# read config
28ABUILD_CONF=${ABUILD_CONF:-"/etc/abuild.conf"}
29[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"
30
31# If REPODEST is set then it will override the PKGDEST
32if [ -n "$REPODEST" ]; then
33 PKGDEST="$REPODEST/$repo"
34fi
35
36# source functions
37datadir=/usr/share/abuild
38
39# if abuild was not run from PATH, then look for func lib at same location
40if [ -z "$FUNCLIB" ]; then
41 FUNCLIB="${0##/*}/functions.sh"
42 [ -f "$FUNCLIB" ] || FUNCLIB=$datadir/functions.sh
43fi
44
45if ! [ -f "$FUNCLIB" ]; then
46 echo "$FUNCLIB: not found" >&2
47 exit 1
48fi
49. "$FUNCLIB"
50
51set_xterm_title() {
52 if [ "$TERM" = xterm ]; then
53 printf "\033]0;$1\007" >&2
54 fi
55}
56
57cleanup() {
58 set_xterm_title ""
59 if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
60 sudo apk del $uninstall_after
61 fi
62}
63
64die() {
65 error "$@"
66 cleanup
67 exit 1
68}
69
70# check if apkbuild is basicly sane
71sanitycheck() {
72 msg "Checking sanity of $APKBUILD..."
73 [ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
74 [ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
75 [ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
76 [ "${pkgver##[0-9]}" == "$pkgver" ] && \
77 die "pkgver does not start with a digit"
78 [ -z "$pkgrel" ] && warning "Missing pkgrel in APKBUILD. Using pkgrel=0"
79 [ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
80 [ -z "$url" ] && die "Missing url in APKBUILD"
81 [ -z "$license" ] && die "Missing license in APKBULID"
82
83 if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
84 die "Number of md5sums does not correspond to number of sources"
85 fi
86
87 # common spelling errors
88 [ -n "$depend" ] && die "APKBUILD contains 'depend'. It should be depends"
89 [ -n "$makedepend" ] && die "APKBUILD contains 'makedepend'. It should be makedepends"
90 return 0
91}
92
93md5check() {
94 if [ -z "$source" ]; then
95 return 0
96 fi
97 if [ -z "$md5sums" ]; then
98 die "Use 'abuild checksum' to generate/update the checksum(s)"
99 fi
100
101 if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
102 die "Number of md5sums does not correspond to number of sources"
103 fi
104 fetch || return 1
105 msg "Checking md5sums..."
106 cd "$srcdir" && echo "$md5sums" | md5sum -c
107}
108
109uri_fetch() {
110 local uri="$1"
111 local d="${s##*/}" # $(basename $s)
112 local opts
113 [ -n "$quiet" ] && opts="-q"
114 [ -f "$SRCDEST/$d" ] && return 0
115
116 mkdir -p "$SRCDEST"
117 if [ -f "$SRCDEST/$d.part" ]; then
118 msg "Partial download found. Trying to resume"
119 opts="$opts -c"
120 fi
121 msg "Fetching $uri"
122 wget $opts -O "$SRCDEST/$d.part" "$uri" \
123 && mv "$SRCDEST/$d.part" "$SRCDEST/$d"
124}
125
126is_remote() {
127 case "$1" in
128 http://*|ftp://*)
129 return 0;;
130 esac
131 return 1
132}
133
134fetch() {
135 local s
136 mkdir -p "$srcdir"
137 for s in $source; do
138 if is_remote "$s"; then
139 uri_fetch "$s" || return 1
140 ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
141 else
142 ln -sf "$startdir/$s" "$srcdir/"
143 fi
144 done
145}
146
147# unpack the sources
148unpack() {
149 local u
150 md5check || return 1
151 mkdir -p "$srcdir"
152 for u in $source; do
153 local s="$SRCDEST/${u##*/}" # $(basename $s)
154 case "$s" in
155 *.tar.gz|*.tgz)
156 msg "Unpacking $s..."
157 tar -C "$srcdir" -zxf "$s" || return 1;;
158 *.tar.bz2)
159 msg "Unpacking $s..."
160 tar -C "$srcdir" -jxf "$s" || return 1;;
161 *.tar.lzma)
162 msg "Unpacking $s..."
163 unlzma -c "$s" | tar -C "$srcdir" -x \
164 || return 1;;
165 *.zip)
166 msg "Unpacking $s..."
167 unzip "$s" -d "$srcdir" || return 1;;
168 esac
169 done
170}
171
172# cleanup source and package dir
173clean() {
174 msg "Cleaning temporary build dirs..."
175 rm -rf "$srcdir"
176 rm -rf "$pkgdir"
177 local i
178 for i in $subpackages; do
179 rm -rf "$pkgdir-$(get_split_func $i)"
180 done
181}
182
183# cleanup fetched sources
184cleancache() {
185 local s
186 for s in $source; do
187 if is_remote "$s"; then
188 msg "Cleaning downloaded ${s##*/}..."
189 rm -f "$SRCDEST/${s##*/}"
190 fi
191 done
192}
193
194cleanpkg() {
195 local i
196 msg "Cleaning built packages..."
197 for i in $pkgname $subpackages; do
198 local p="$i-$pkgver-r$pkgrel"
199 rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz"
200 done
201}
202
203# clean all packages except current
204cleanoldpkg() {
205 local i j
206 msg "Cleaning all packages except $pkgver-r$pkgrel..."
207 for i in $pkgname $subpackages; do
208 for j in "$PKGDEST"/${i%:*}-[0-9]*.apk; do
209 [ "$j" != "$PKGDEST/${i%:*}-$pkgver-r$pkgrel.apk" ] \
210 && rm -f "$j"
211 done
212 done
213 return 0
214}
215
216runpart() {
217 local part=$1
218 [ -n "$DEBUG" ] && msg "$part"
219 $part || die "$part failed"
220}
221
222# override those in your build script
223build() {
224 die "No build() function found in $APKBUILD"
225}
226
227get_split_func() {
228 # get the 'func' from "sub-pkg:func"
229 local func=${1##*:}
230
231 # get 'func' from "sub-pkg-func" if there was no :func
232 [ "$func" = "$1" ] && func=${func##*-}
233 echo $func
234}
235
236subpkg() {
237 if [ -z "$subpackages" ]; then
238 return 0
239 fi
240 local i
241 cd "$startdir"
242 for i in $subpackages; do
243 local func=$(get_split_func $i)
244 # call abuild recursively, setting subpkg{dir,name}
245 msg "Running split function $func..."
246 subpkgdir="$startdir/pkg-$func" subpkgname="${i%:*}" \
247 $0 $func package || return 1
248 done
249}
250
251package_apk() {
252 local name=${subpkgname:-$pkgname}
253 [ -z "${name##* *}" ] && die "package name contains spaces"
254 local dir=${subpkgdir:-$pkgdir}
255 local pkg="$name-$pkgver-r$pkgrel.apk"
256 local sub
257
258 [ ! -d "$dir" ] && die "Missing $dir"
259 cd "$dir"
260 msg "Creating ${subpkgname:+sub}package $pkg..."
261 local builddate=$(date -u "+%s")
262 local size=$(du -sk | awk '{print $1 * 1024}')
263
264 echo "# Generated by $(basename $0) $abuild_ver" >.PKGINFO
265 if [ -n "$FAKEROOTKEY" ]; then
266 echo "# using $(fakeroot -v)" >> .PKGINFO
267 fi
268 echo "# $(date -u)" >> .PKGINFO
269 cat >> .PKGINFO <<EOF
270pkgname = $name
271pkgver = $pkgver-r$pkgrel
272pkgdesc = $pkgdesc
273url = $url
274builddate = $builddate
275packager = ${PACKAGER:-"Unknown"}
276size = $size
277EOF
278 local i
279
280 for i in $license; do
281 echo "license = $i" >>.PKGINFO
282 done
283 for i in $replaces; do
284 echo "replaces = $i" >>.PKGINFO
285 done
286 for i in $depends; do
287 echo "depend = $i" >>.PKGINFO
288 done
289 for i in $conflicts; do
290 echo "conflict = $i" >>.PKGINFO
291 done
292 for i in $provides; do
293 echo "provides = $i" >>.PKGINFO
294 done
295 for i in $backup; do
296 echo "backup = $i" >>.PKGINFO
297 done
298
299 local metafiles=".PKGINFO"
300 if [ -n "$install" ]; then
301 cp "$srcdir/$install" "$dir/.INSTALL" || return 1
302 chmod +x "$dir/.INSTALL"
303 metafiles="$metafiles .INSTALL"
304 fi
305
306# for i in pre-install post-install pre-deinstall post-deinstall; do
307# [ -f ../$i ] && cp ../$i "$db"/
308# done
309
310 set *
311 [ "$1" = '*' ] && set --
312 ( cd "$dir" && tar -zcf "$PKGDEST/$pkg" $metafiles $@ )
313}
314
315package() {
316 stripbin
317 package_apk
318}
319
320# predefined splitfunc doc
321doc() {
322 depends="$depends_doc"
323 local i
324 for i in doc man info html sgml licenses; do
325 if [ -d "$pkgdir/usr/share/$i" ]; then
326 mkdir -p "$subpkgdir/usr/share"
327 mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
328 fi
329 done
330
331 rm -f "$subpkgdir/usr/share/info/dir"
332
333# # compress info and man pages
334# find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
335# -o -name '*.[1-9]' \) -exec gzip {} \;
336
337 # remove if empty, ignore error (not empty)
338 rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null
339
340# [ -d "$subpkgdir/usr/share/man" ] && depends="man"
341 return 0
342}
343
344# predefined splitfunc mod
345mod() {
346 depends="$kernel $depends_mod"
347 for i in firmware modules; do
348 if [ -d "$pkgdir/lib/$i" ]; then
349 rm -rf "$subpkgdir/lib"
350 mkdir -p "$subpkgdir/lib"
351 mv "$pkgdir/lib/$i" "$subpkgdir/lib"
352 fi
353 done
354}
355
356# predefined splitfunc dev
357dev() {
358 depends="$pkgname $depends_dev"
359 cd "$pkgdir" || return 0
360 for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
361 usr/share/gettext usr/bin/*-config \
362 $(find -name include -type d) \
363 $(find usr/ -name '*.[acho]' -o -name '*.la' \
364 2>/dev/null); do
365 if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
366 d="$subpkgdir/${i%/*}" # dirname $i
367 mkdir -p "$d"
368 mv "$pkgdir/$i" "$d"
369 rmdir "$pkgdir/${i%/*}" 2>/dev/null
370 fi
371 done
372 return 0
373}
374
375# build and package in fakeroot
376rootpkg() {
377 cd "$startdir"
378 msg "Entering fakeroot..."
379 fakeroot $0 build subpkg package
380}
381
382srcpkg() {
383 local p="$pkgname-$pkgver-$pkgrel"
384 local prefix="${startdir##*/}"
385 local i files="$prefix/APKBUILD"
386 for i in $source; do
387 files="$files $prefix/${i##*/}"
388 done
389 mkdir -p "$PKGDEST"
390 msg "Creating source package $p.src.tar.gz..."
391 (cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files)
392}
393
394# check if package is up to date
395up2date() {
396 local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
397 local i s
398 cd "$startdir"
399 for i in $pkgname $subpackages; do
400 [ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
401 done
402 [ -n "$keep" ] && return 0
403
404 for i in $source APKBUILD; do
405 local s
406 if is_remote "$i"; then
407 s="$SRCDEST/${i##*/}" # $(basename $i)
408 else
409 s="$startdir/${i##*/}"
410 fi
411 if [ "$s" -nt "$pkg" ]; then
412 return 1
413 fi
414 done
415 return 0
416}
417
418# source all APKBUILDs and output:
419# 1) origin of package
420# 2) all dependencies
421# the output is i in a format easy parseable for awk
422depparse_aports() {
423 # lets run this in a subshell since we source all APKBUILD here
424 (
425 aportsdir=$(realpath ${APKBUILD%/APKBUILD}/../..)
426 for i in $aportsdir/*/*/APKBUILD; do
427 pkgname=
428 subpackages=
429 depends=
430 makedepends=
431 . $i
432 dir=${i%/APKBUILD}
433 for j in $pkgname $subpackages; do
434 echo "o ${j%%:*} $dir"
435 set -- $depends $makedepends
436 echo -n "d ${j%%:*} $1"
437 shift
438 while [ $# -gt 0 ]; do
439 echo -n ",$1"
440 shift
441 done
442 echo
443 done
444 done
445 )
446}
447
448deptrace() {
449 ( depparse_aports
450 if [ -z "$upgrade" ]; then
451 # list installed pkgs and prefix with 'i '
452 apk info -q | sort | sed 's/^/i /'
453 fi
454 ) | awk -v pkgs="$BUILD_BASE $depends $makedepends" '
455
456 function depgraph(pkg, a, i) {
457 if (visited[pkg])
458 return 0;
459 visited[pkg] = 1;
460 split(deps[pkg], a, ",");
461 for (i in a)
462 depgraph(a[i]);
463 print pkg ":" origin[pkg];
464
465 }
466
467 $1 == "i" { visited[$2] = 1 }
468 $1 == "o" { origin[$2] = $3 }
469 $1 == "d" { deps[$2] = $3 }
470 END {
471 split(pkgs, pkgarray);
472 for (i in pkgarray)
473 depgraph(pkgarray[i]);
474 }
475 '
476}
477
478# build and install dependencies
479builddeps() {
480 local deps alldeps pkg i dir ver
481 msg "Building dependencies..."
482 deps="$BUILD_BASE $depends $makedepends"
483 if [ -z "$recursive" ]; then
484 for i in $deps; do
485 apk info -e $i || die "Missing dependency $i. Use -r to build recursively"
486 done
487 return 0
488 fi
489
490 for i in $(deptrace); do
491 # i = pkg:dir
492 local dir=${i#*:}
493 local pkg=${i%:*}
494 msg "Entering $dir"
495 cd "$dir" || return 1
496 $0 -i $pkg || return 1
497 uninstall_after="$pkg $uninstall_after"
498 done
499}
500
501# replace the md5sums in the APKBUILD
502checksum() {
503 local s files
504 fetch
505 msg "Updating the md5sums in APKBUILD..."
506 for s in $source; do
507 files="$files ${s##*/}"
508 done
509 md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
510 sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
511 echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
512}
513
514stripbin() {
515 local bin
516 cd "${subpkgdir:-$pkgdir}" || return 1
517 msg "Stripping binaries"
518 find . -type f 2>/dev/null | while read bin; do
519 local opt=
520 case "$(file -biz "$bin")" in
521 */x-sharedlib*|*/x-archive*)
522 strip --strip-debug "$bin";;
523 */x-executable*)
524 strip "$bin";;
525 esac
526 done
527 return 0
528}
529
530# simply list target apks
531listpkg() {
532 local i
533 for i in $pkgname $subpackages; do
534 echo "${i%:*}-$pkgver-r$pkgrel.apk"
535 done
536}
537
538subpackages_has() {
539 local i
540 for i in $subpackages; do
541 [ "$1" = "${i%:*}" ] && return 0
542 done
543 return 1
544}
545
546# install package after build
547post_add() {
548 local pkgf="$PKGDEST/$1-$pkgver-r$pkgrel.apk"
549 local deps i
550 if ! subpackages_has $1 && [ "$1" != "$pkgname" ]; then
551 die "$1 is not built by this APKBUILD"
552 fi
553 # recursively install dependencies that are provided by this APKBUILD
554 deps=$(apk index "$pkgf" 2>/dev/null | awk -F: '$1=="D" { print $2 }')
555 for i in $deps; do
556 if subpackages_has $i || [ "$i" = "$pkgname" ]; then
557 post_add $i || return 1
558 fi
559 done
560 sudo apk add -u "$pkgf" || die "Failed to install $1"
561}
562
563# create new aport from templates
564newaport() {
565 local pn=${newname%-[0-9]*}
566 local pv
567 if [ "$pn" != "$newname" ]; then
568 pv=${newname#$pn-}
569 fi
570 if [ -e "$pn"/APKBUILD ]; then
571 error "$pn/APKBUILD already exist"
572 return 1
573 fi
574 mkdir -p "$pn"
575 cd "$pn"
576 sed -e '1,/^\#*$/d' \
577 -e "s/^\(# Contributor: \).*/\1$PACKAGER/" \
578 -e "s/^\(# Maintainer: \).*/\1$PACKAGER/" \
579 -e "s/^pkgname=.*/pkgname=$pn/" \
580 -e "s/^pkgver=.*/pkgver=$pv/" \
581 "$datadir"/sample.APKBUILD > APKBUILD || return 1
582 #-e '1,/^\#$/d' \
583 if [ -n "$cpinitd" ]; then
584 cp "$datadir"/sample.initd $pn.initd
585 cp "$datadir"/sample.confd $pn.confd
586 cp "$datadir"/sample.install $pn.install
587 sed -i -e "s/^install=.*/install=\"$pn.install\"/" \
588 -e "s/^source=\"\(.*\)\"/source=\"\1\n\t$pn.initd\n\t$pn.confd\n\t\$install\n\t\"/" \
589 APKBUILD
590
591 fi
592}
593
594usage() {
595 echo "$(basename $0) $abuild_ver"
596 echo "usage: ${0##*/} [options] [-i PKG] [-p PKGDEST] [-s SRCDEST] [cmd] ..."
597 echo " ${0##*/} [-c] -n PKGNAME[-PKGVER]"
598 echo "Options:"
599 echo " -f Force specified cmd, even if they are already done"
600 echo " -h Show this help"
601 echo " -i Install PKG after successul build"
602 echo " -k Keep built packages, even if APKBUILD or sources are newer"
603 echo " -p Set package destination directory"
604 echo " -q Quiet"
605 echo " -r Recursively build and install missing dependencies (using sudo)"
606 echo " -s Set source package destination directory"
607 echo " -u Recursively build and upgrade dependencies (using sudo)"
608 echo ""
609 echo " -n Create a new APKBUILD in a directory named PKGNAME"
610 echo " -c Copy a sample init.d, conf.d and install script to new directory"
611 echo ""
612 echo "Commands:"
613 echo " checksum Generate checksum to be included in APKBUILD"
614 echo " fetch Fetch sources to \$SRCDEST and verify checksums"
615 echo " sanitycheck Basic sanity check of APKBUILD"
616 echo " md5check Check md5sums"
617 echo " unpack Unpack sources to \$srcdir"
618 echo " build Compile and install package into \$pkgdir"
619 echo " listpkg List target packages"
620 echo " package Create package in \$PKGDEST"
621 echo " rootpkg Run '$0 build package' as fakeroot"
622 echo " clean Remove temp build and install dirs"
623 echo " cleanoldpkg Remove binary packages except current version"
624 echo " cleanpkg Remove already built binary and source package"
625 echo " cleancache Remove downloaded files from \$SRCDEST"
626 echo " srcpkg Make a source package"
627 echo " up2date Compare target and sources dates"
628 echo ""
629 exit 0
630}
631
632APKBUILD="${APKBUILD:-./APKBUILD}"
633unset force
634unset recursive
635while getopts "cfhi:kin:p:qrs:u" opt; do
636 case $opt in
637 'c') cpinitd=1;;
638 'f') force=1;;
639 'h') usage;;
640 'i') install_after="$install_after $OPTARG";;
641 'k') keep=1;;
642 'n') newname=$OPTARG;;
643 'p') PKGDEST=$OPTARG;;
644 'q') quiet=1;;
645 'r') recursive=1;;
646 's') SRCDEST=$OPTARG;;
647 'u') upgrade=1
648 recursive=1;;
649 esac
650done
651shift $(( $OPTIND - 1 ))
652
653# source the buildfile
654if [ -z "$newname" ]; then
655 [ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
656 . "$APKBUILD"
657fi
658
659# If we are handling a sub package then reset subpackages
660if [ -n "$subpkgname" ]; then
661 subpackages=
662fi
663
664trap 'die "Aborted by user"' INT
665set_xterm_title "abuild: $pkgname"
666
667if [ -z "$1" ] && [ -n "$newname" ]; then
668 set "newaport"
669fi
670
671if [ -z "$1" ]; then
672 if up2date && [ -z "$force" ]; then
673 msg "Package is up to date"
674 else
675 set $default_cmds
676 fi
677fi
678
679while [ $# -gt 0 ]; do
680 runpart $1
681 shift
682done
683
684for i in $install_after; do
685 post_add $i
686done
687
688cleanup
689