OILS / benchmarks / testdata / abuild View on Github | oilshell.org

2512 lines, 2230 significant
1#!/bin/ash -e
2
3# abuild - build apk packages (light version of makepkg)
4# Copyright (c) 2008-2015 Natanael Copa <ncopa@alpinelinux.org>
5# Copyright (c) 2016 Timo Teräs <timo.teras@iki.fi>
6#
7# Distributed under GPL-2
8#
9
10program_version=3.0.2
11sysconfdir=/etc
12datadir=/home/andy/git/alpine/abuild
13
14abuild_path=$(readlink -f $0)
15
16if ! [ -f "$datadir/functions.sh" ]; then
17 echo "$datadir/functions.sh: not found" >&2
18 exit 1
19fi
20. "$datadir/functions.sh"
21
22# defaults
23: ${FAKEROOT:="fakeroot"}
24: ${SUDO_APK:="abuild-apk"}
25: ${APK:="apk"}
26: ${ADDUSER:="abuild-adduser"}
27: ${ADDGROUP:="abuild-addgroup"}
28
29apk_opt_wait="--wait 30"
30
31umask 022
32
33# run optional log command for remote logging
34logcmd() {
35 ${ABUILD_LOG_CMD:-true} "$@"
36 return 0
37}
38
39# we override the default msg, warning and error as we want the pkgname
40msg() {
41 [ -n "$quiet" ] && return 0
42 local prompt="$GREEN>>>${NORMAL}"
43 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
44 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
45 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
46}
47
48warning() {
49 local prompt="${YELLOW}>>> WARNING:${NORMAL}"
50 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
51 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
52 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
53}
54
55error() {
56 local prompt="${RED}>>> ERROR:${NORMAL}"
57 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
58 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
59 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
60 logcmd "ERROR: $pkgname: $1"
61}
62
63cross_creating() {
64 test "$CHOST" != "$CTARGET" -a -n "$CBUILDROOT"
65}
66
67cross_compiling() {
68 test "$CBUILD" != "$CHOST" -a -n "$CBUILDROOT"
69}
70
71want_check() {
72 [ -n "$ABUILD_BOOTSTRAP" ] && return 1
73 cross_compiling && return 1
74 options_has "!check" && return 1
75 return 0
76}
77
78cleanup() {
79 local i=
80 [ -z "$subpkgdir" ] && set_xterm_title ""
81 if [ -n "$keep_build" ]; then
82 return 0
83 fi
84 for i; do
85 case $i in
86 bldroot)
87 if [ "$BUILD_ROOT" ]; then
88 msg "Cleaning up build chroot"
89 abuild-rmtemp "$BUILD_ROOT"
90 fi;;
91 pkgdir) msg "Cleaning up pkgdir"; rm -rf "$pkgbasedir";;
92 srcdir) msg "Cleaning up srcdir"; rm -rf "$srcdir";;
93 deps)
94 if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
95 msg "Uninstalling dependencies..."
96 undeps
97 fi
98 ;;
99 esac
100 done
101}
102
103die() {
104 trap - EXIT
105 error "$@"
106 cleanup $ERROR_CLEANUP
107 exit 1
108}
109
110spell_error() {
111 die "APKBUILD contains '$1'. It should be '$2'"
112}
113
114print_version() {
115 msg "$program $program_version"
116}
117
118# check if apkbuild is basicly sane
119default_sanitycheck() {
120 local i= j= suggestion=
121 msg "Checking sanity of $APKBUILD..."
122 [ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
123 [ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
124 [ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
125 if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
126 $APK version --check --quiet "$pkgver" ||\
127 die "$pkgver is not a valid version"
128 fi
129 [ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
130 [ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
131 [ -z "$url" ] && die "Missing url in APKBUILD"
132 [ -z "$license" ] && die "Missing license in APKBUILD"
133 if [ $(echo "$pkgdesc" | wc -c) -gt 128 ]; then
134 die "pkgdesc is too long"
135 fi
136 is_function package || warning "Missing package() function in APKBUILD"
137
138 if [ -n "$replaces_priority" ] \
139 && ! echo $replaces_priority | egrep -q '^[0-9]+$'; then
140 die "replaces_priority must be a number"
141 fi
142 # check so no package names starts with -
143 for i in $pkgname $subpackages; do
144 case $i in
145 -*) die "${i%%:*} is not a valid package name";;
146 esac
147 done
148
149 for i in $install; do
150 local n=${i%.*}
151 local suff=${i##*.}
152 case "$suff" in
153 pre-install|post-install|pre-upgrade|post-upgrade|pre-deinstall|post-deinstall);;
154 *) die "$i: unknown install script suffix"
155 esac
156 if ! subpackages_has "$n" && [ "$n" != "$pkgname" ]; then
157 die "$i: install script does not match pkgname or any subpackage"
158 fi
159 [ -e "$startdir/$i" ] || die "install script $i is missing"
160 for j in chown chmod chgrp; do
161 if grep -q $j "$startdir"/$i; then
162 warning "$i: found $j"
163 warning2 "Permissions should be fixed in APKBUILD package()"
164 fi
165 done
166 done
167
168 for i in $triggers; do
169 local f=${i%=*}
170 local p=${f%.trigger}
171 [ "$f" = "$i" ] && die "$f: triggers must contain '='"
172 [ "$p" = "$f" ] && die "$f: triggers scripts must have .trigger suffix"
173 if ! subpackages_has "$p" && [ "$p" != "$pkgname" ]; then
174 die "$p: trigger script does not match pkgname or any subpackage"
175 fi
176
177 [ -e "$startdir"/$f ] || die "trigger script $f is missing"
178 done
179 if [ -n "$source" ]; then
180 for i in $source; do
181 if install_has "$i"; then
182 warning "You should not have \$install in source"
183 continue
184 fi
185 case "$i" in
186 *::*) i=${i%%::*};;
187 https://*) makedepends_has wget && warning "wget no longer need to be in makedepends when source has https://" ;;
188 esac
189 list_has ${i##*/} $md5sums $sha256sums $sha512sums \
190 || die "${i##*/} is missing in checksums"
191
192 # verify that our source does not have git tag version
193 # name as tarball (typicallly github)
194 if is_remote "$i" && [ "${i#*::}" = "$i" ]; then
195 case ${i##*/} in
196 v$pkgver.tar.*|$pkgver.tar.*)
197 die "source ${i##*/} needs to be renamed to avoid possible collisions"
198 ;;
199 esac
200 fi
201 done
202 fi
203
204 # verify that things listed in checksum also is listed in source
205 local algo=
206 for algo in md5 sha256 sha512; do
207 eval set -- \$${algo}sums
208 while [ $# -gt 1 ]; do
209 local file="$2"
210 shift 2
211 source_has $file || die "$file exists in ${algo}sums but is missing in source"
212 done
213 done
214
215 # common spelling errors
216 [ -n "$depend" ] && spell_error depend depends
217 [ -n "$makedepend" ] && spell_error makedepend makedepends
218 [ -n "$pkguser" ] && spell_error pkguser pkgusers
219 [ -n "$pkggroup" ] && spell_error pkggroup pkggroups
220 [ -n "$subpackage" ] && spell_error subpackage subpackages
221 [ -n "$checkdepend" ] && spell_error checkdepend checkdepends
222
223 check_maintainer || die "Provide a valid RFC822 maintainer address"
224
225 check_depends_dev || warning "depends_dev found but no development subpackage found"
226 check_secfixes_comment || return 1
227
228 makedepends_has 'g++' && ! options_has toolchain && warning "g++ should not be in makedepends"
229 return 0
230}
231
232sanitycheck() {
233 default_sanitycheck
234}
235
236sumcheck() {
237 local algo="$1" sums="$2"
238 local dummy f endreturnval originalparams origin file
239
240 # get number of checksums
241 set -- $sums
242 local numsums=$(( $# / 2 ))
243
244 set -- $source
245 if [ $# -ne $numsums ]; then
246 die "Number of ${algo}sums($numsums) does not correspond to number of sources($#)"
247 fi
248 fetch || return 1
249 msg "Checking ${algo}sums..."
250 cd "$srcdir" || return 1
251 IFS=$'\n'
252 endreturnval=0
253 for src in $sums; do
254 origin=$1; shift
255 if ! echo "$src" | ${algo}sum -c; then
256 endreturnval=1
257 is_remote $origin || continue
258
259 local csum="${src:0:8}"
260 local file="$SRCDEST/$(filename_from_uri $origin)"
261
262 echo "Because the remote file above failed the ${algo}sum check it will be renamed."
263 echo "Rebuilding will cause it to re-download which in some cases may fix the problem."
264 echo "Renaming: ${file##*/} to ${file##*/}.$csum"
265 mv "$file" "$file.$csum"
266 fi
267 done
268 unset IFS
269 return $endreturnval
270}
271
272# for compatibility
273md5check() {
274 warning "'md5check' is deprecated. Use 'verify' instead"
275 sumcheck md5 "$md5sums"
276}
277
278# verify checksums
279verify() {
280 local verified=false algo=
281 for algo in sha512 sha256 sha1 md5; do
282 local sums=
283 eval sums=\"\$${algo}sums\"
284 if [ -z "$sums" ] || [ -z "$source" ]; then
285 continue
286 fi
287 sumcheck "$algo" "$sums" || return 1
288 verified=true
289 break
290 done
291 if [ -n "$source" ] && ! $verified; then
292 die "Use 'abuild checksum' to generate/update the checksum(s)"
293 fi
294 return 0
295}
296
297# verify upstream sources
298sourcecheck() {
299 local uri
300 for uri in $source; do
301 is_remote $uri || continue
302 case "$uri" in
303 *::*)
304 uri=${uri##*::}
305 ;;
306 esac
307 wget --spider -q "$uri" || return 1
308 done
309 return 0
310}
311
312uri_fetch() {
313 local uri="$1"
314 mkdir -p "$SRCDEST"
315 msg "Fetching $uri"
316 abuild-fetch -d "$SRCDEST" "$uri"
317}
318
319is_remote() {
320 case "${1#*::}" in
321 http://*|ftp://*|https://*)
322 return 0;;
323 esac
324 return 1
325}
326
327filename_from_uri() {
328 local uri="$1"
329 local filename="${uri##*/}" # $(basename $uri)
330 case "$uri" in
331 *::*) filename=${uri%%::*};;
332 esac
333 echo "$filename"
334}
335
336# try download from file from mirror first
337uri_fetch_mirror() {
338 local uri="$1"
339 if [ -n "$DISTFILES_MIRROR" ]; then
340 if is_remote "$DISTFILES_MIRROR"; then
341 uri_fetch "$DISTFILES_MIRROR"/$(filename_from_uri $uri)\
342 && return 0
343 else
344 cp "$DISTFILES_MIRROR"/$(filename_from_uri $uri) \
345 "$SRCDEST" && return 0
346 fi
347 fi
348 uri_fetch "$uri"
349}
350
351symlinksrc() {
352 local s
353 mkdir -p "$srcdir"
354 for s in $source; do
355 if is_remote "$s"; then
356 ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
357 else
358 ln -sf "$startdir/$s" "$srcdir/"
359 fi
360 done
361}
362
363default_fetch() {
364 local s
365 mkdir -p "$srcdir"
366 for s in $source; do
367 if is_remote "$s"; then
368 uri_fetch_mirror "$s" || return 1
369 ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
370 else
371 ln -sf "$startdir/$s" "$srcdir/"
372 fi
373 done
374}
375
376fetch() {
377 default_fetch
378}
379
380# verify that all init.d scripts are openrc runscripts
381initdcheck() {
382 local i line
383 for i in $source; do
384 case $i in
385 *.initd) line=$(head -n 1 "$srcdir"/$i);;
386 *) continue ;;
387 esac
388
389 case "$line" in
390 *sbin/openrc-run)
391 ;;
392 *sbin/runscript)
393 warning "$i is not an openrc #!/sbin/openrc-run"
394 ;;
395 *) error "$i is not an openrc #!/sbin/openrc-run"
396 return 1
397 ;;
398 esac
399 done
400}
401
402# unpack the sources
403default_unpack() {
404 local u
405 if [ -z "$force" ]; then
406 verify || return 1
407 initdcheck || return 1
408 fi
409 mkdir -p "$srcdir"
410 for u in $source; do
411 local s
412 if is_remote "$u"; then
413 s="$SRCDEST/$(filename_from_uri $u)"
414 else
415 s="$startdir/$u"
416 fi
417 case "$s" in
418 *.tar)
419 msg "Unpacking $s..."
420 tar -C "$srcdir" -xf "$s" || return 1;;
421 *.tar.gz|*.tgz)
422 msg "Unpacking $s..."
423 tar -C "$srcdir" -zxf "$s" || return 1;;
424 *.tar.bz2)
425 msg "Unpacking $s..."
426 tar -C "$srcdir" -jxf "$s" || return 1;;
427 *.tar.lz)
428 msg "Unpacking $s..."
429 tar -C "$srcdir" --lzip -xf "$s" || return 1;;
430 *.tar.lzma)
431 msg "Unpacking $s..."
432 unlzma -c "$s" | tar -C "$srcdir" -x \
433 || return 1;;
434 *.tar.xz)
435 msg "Unpacking $s..."
436 unxz -c "$s" | tar -C "$srcdir" -x || return 1;;
437 *.zip)
438 msg "Unpacking $s..."
439 unzip -n -q "$s" -d "$srcdir" || return 1;;
440 esac
441 done
442}
443
444unpack() {
445 default_unpack
446}
447
448# cleanup source and package dir
449clean() {
450 msg "Cleaning temporary build dirs..."
451 rm -rf "$srcdir"
452 rm -rf "$pkgbasedir"
453}
454
455# cleanup fetched sources
456cleancache() {
457 local s
458 for s in $source; do
459 if is_remote "$s"; then
460 s=$(filename_from_uri $s)
461 msg "Cleaning downloaded $s ..."
462 rm -f "$SRCDEST/$s"
463 fi
464 done
465}
466
467subpkg_unset() {
468 unset subpkgname subpkgsplit subpkgarch
469}
470
471subpkg_set() {
472 subpkgname=${1%%:*}
473
474 local _splitarch=${1#*:}
475 [ "$_splitarch" = "$1" ] && _splitarch=""
476
477 subpkgsplit=${_splitarch%%:*}
478 [ -z "$subpkgsplit" ] && subpkgsplit="${subpkgname##*-}"
479
480 subpkgarch=${_splitarch#*:}
481 if [ "$subpkgarch" = "$_splitarch" -o -z "$subpkgarch" ]; then
482 case "$subpkgname" in
483 *-doc | *-lang | *-lang-*) subpkgarch="noarch" ;;
484 *) subpkgarch="$pkgarch" ;;
485 esac
486 fi
487}
488
489cleanpkg() {
490 local i
491 getpkgver || return 1
492 msg "Cleaning built packages..."
493 rm -f "$REPODEST/$repo/src/$pkgname-$pkgver-r$pkgrel.src.tar.gz"
494 for i in $allpackages; do
495 subpkg_set "$i"
496 rm -f "$REPODEST/$repo/${subpkgarch/noarch/$CARCH}/$subpkgname-$pkgver-r$pkgrel.apk"
497 done
498 subpkg_unset
499
500 # remove given packages from index
501 update_abuildrepo_index
502}
503
504# clean all packages except current
505cleanoldpkg() {
506 local i j
507 getpkgver || return 1
508 msg "Cleaning all packages except $pkgver-r$pkgrel..."
509 for i in $allpackages; do
510 subpkg_set "$i"
511 for j in "$REPODEST"/$repo/*/$subpkgname-[0-9]*.apk ; do
512 [ "${j##*/}" = "$subpkgname-$pkgver-r$pkgrel.apk" ] \
513 && continue
514 rm -f "$j"
515 done
516 done
517 subpkg_unset
518 update_abuildrepo_index
519 return 0
520}
521
522mkusers() {
523 local i
524 for i in $pkggroups; do
525 if ! getent group $i >/dev/null; then
526 msg "Creating group $i"
527 $ADDGROUP -S $i || return 1
528 fi
529 done
530 for i in $pkgusers; do
531 if ! getent passwd $i >/dev/null; then
532 local gopt=
533 msg "Creating user $i"
534 if getent group $i >/dev/null; then
535 gopt="-G $i"
536 fi
537 $ADDUSER -S -D -H $gopt $i || return 1
538 fi
539 done
540}
541
542# helper to update config.sub to a recent version
543update_config_sub() {
544 find . -name config.sub | (local changed=false; while read f; do
545 if ! ./$f armv6-alpine-linux-muslgnueabihf 2>/dev/null; then
546 msg "Updating $f"
547 cp "$datadir"/${f##*/} "$f" || return 1
548 changed=true
549 else
550 msg "No update needed for $f"
551 fi
552 done; $changed)
553}
554
555# helper to update config.guess to a recent version
556update_config_guess() {
557 find . -name config.guess | (local changed=false; while read f; do
558 if grep -q aarch64 "$f" && grep -q ppc64le "$f"; then
559 msg "No update needed for $f"
560 else
561 msg "Updating $f"
562 cp "$datadir"/${f##*/} "$f" || return 1
563 changed=true
564 fi
565 done; $changed)
566}
567
568runpart() {
569 local part=$1
570 [ -n "$DEBUG" ] && msg "$part"
571 trap "die '$part failed'" EXIT
572 $part
573 trap - EXIT
574}
575
576# override those in your build script
577getpkgver() {
578 # this func is supposed to be overridden by volatile packages
579 if [ "$pkgver" = "volatile" ]; then
580 error "Please provide a getpkgver() function in your APKBUILD"
581 return 1
582 fi
583}
584
585have_patches() {
586 local i
587 for i in $source; do
588 case ${i%::*} in
589 *.patch) return 0;;
590 esac
591 done
592 return 1
593}
594
595default_prepare() {
596 local i
597 [ -n "$builddir" -a -d "$builddir" ] && cd "$builddir"
598 if ! have_patches; then
599 return 0
600 fi
601 [ -d "$builddir" ] || { error "Is \$builddir set correctly?"; return 1; }
602 for i in $source; do
603 case ${i%::*} in
604 *.patch)
605 msg "${i%::*}"
606 patch ${patch_args:--p1} -i "$srcdir/${i%::*}" || return 1
607 ;;
608 esac
609 done
610}
611
612prepare() {
613 default_prepare
614}
615
616build() {
617 :
618}
619
620# generate a simple tar.gz package of pkgdir
621targz() {
622 cd "$pkgdir" || return 1
623 mkdir -p "$REPODEST"/src
624 tar -czf "$REPODEST"/src/$pkgname-$pkgver-r$pkgrel.tar.gz *
625}
626
627postcheck() {
628 local dir="$1" name="$2" i=
629 msg "Running postcheck for $name"
630 # checking for FHS compat
631 if ! options_has "!fhs"; then
632 for i in "$dir"/srv/* "$dir"/usr/local/* "$dir"/opt/*; do
633 if [ -e "$i" ]; then
634 error "Packages must not put anything under /srv, /usr/local or /opt"
635 return 1
636 fi
637 done
638 if [ -d "$dir"/usr/var ]; then
639 error "Found /usr/var, localstatedir is most likely wrong"
640 return 1
641 fi
642 fi
643
644 # remove *.la files if libtool is not set
645 if ! options_has "libtool"; then
646 find "$dir" -name '*.la' -type f -delete
647 fi
648
649 # look for /usr/lib/charset.alias
650 if [ -e "$dir"/usr/lib/charset.alias ] \
651 && ! options_has "charset.alias"; then
652 error "Found /usr/lib/charset.alias"
653 return 1
654 fi
655 # look for /usr/share/doc
656 if [ -e "$dir"/usr/share/doc ] \
657 && ! is_doc_pkg "$name"; then
658 warning "Found /usr/share/doc but package name doesn't end with -doc"
659 fi
660 # look for /usr/share/man
661 if [ -e "$dir"/usr/share/man ]; then
662 if ! is_doc_pkg "$name"; then
663 warning "Found /usr/share/man but package name doesn't end with -doc"
664 fi
665 # check for uncompressed man pages
666 i=$(find "$dir"/usr/share/man -name '*.[0-8]' -type f | sed "s|^$dir|\t|")
667 if [ -n "$i" ]; then
668 error "Found uncompressed man pages:"
669 echo "$i"
670 return 1
671 fi
672 fi
673 # check directory permissions
674 i=$(find "$dir" -type d -perm -777 | sed "s|^$dir|\t|")
675 if [ -n "$i" ]; then
676 warning "World writeable directories found:"
677 echo "$i"
678 fi
679 # check so we dont have any suid root binaries that are not PIE
680 i=$(find "$dir" -type f -perm /6000 \
681 | xargs scanelf --nobanner --etype ET_EXEC \
682 | sed "s|ET_EXEC $dir|\t|")
683 if [ -n "$i" ]; then
684 error "Found non-PIE files that has SUID:"
685 echo "$i"
686 return 1
687 fi
688 # test suid bit on executable
689 if ! options_has "suid"; then
690 i=$(find "$dir" \( -perm -u+s -o -perm -g+s \) -a -type f \
691 -a -perm -o+x)
692 if [ -n "$i" ]; then
693 error "Found executable files with SUID bit set:"
694 echo "$i"
695 return 1
696 fi
697 fi
698
699 # test for textrels
700 if ! options_has "textrels"; then
701 local res="$(scanelf --recursive --textrel --quiet "$dir")"
702 if [ -n "$res" ]; then
703 error "Found textrels:"
704 echo "$res"
705 return 1
706 fi
707 fi
708 return 0
709}
710
711pre_split() {
712 if [ -z "$subpkgname" ]; then
713 return 0
714 fi
715 # the subpackages should not inherit those form main package
716 provides=""
717 install_if=""
718}
719
720prepare_subpackages() {
721 local i
722 cd "$startdir"
723 for i in $subpackages; do
724 # call abuild recursively, setting subpkg{dir,name}
725 ( subpkg_set "$i"; msg "Running split function $subpkgsplit..."; \
726 subpkgdir="$pkgbasedir/$subpkgname" subpkgname="$subpkgname" subpkgarch="$subpkgarch" \
727 $0 pre_split $subpkgsplit prepare_package \
728 && postcheck "$pkgbasedir/$subpkgname" "$subpkgname" ) || return 1
729 done
730 postcheck "$pkgdir" "$pkgname" || return 1
731 # post check for /usr/share/locale
732 if [ -d "$pkgdir"/usr/share/locale ]; then
733 warning "Found /usr/share/locale"
734 warning2 "Maybe add \$pkgname-lang to subpackages?"
735 fi
736}
737
738default_lang() {
739 pkgdesc="Languages for package $pkgname"
740 install_if="$pkgname=$pkgver-r$pkgrel lang"
741
742 local dir
743 for dir in ${langdir:-/usr/share/locale}; do
744 mkdir -p "$subpkgdir"/${dir%/*}
745 mv "$pkgdir"/"$dir" "$subpkgdir"/"$dir" || return 1
746 done
747}
748
749lang() {
750 default_lang
751}
752
753default_lang_subpkg() {
754 if [ -z "$lang" ]; then
755 error "lang is not set"
756 return 1
757 fi
758 pkgdesc="$pkgname language pack for $lang"
759 install_if="$pkgname=$pkgver-r$pkgrel lang-$lang"
760
761 local dir
762 for dir in ${langdir:-/usr/share/locale}; do
763 mkdir -p "$subpkgdir"/$dir
764 mv "$pkgdir"/$dir/$lang* \
765 "$subpkgdir"/$dir/ \
766 || return 1
767 done
768}
769
770lang_subpkg() {
771 default_lang_subpkg
772}
773
774prepare_language_packs() {
775 local lang
776 for lang in $linguas; do
777 lang="$lang" \
778 subpkgname="$pkgname-lang-$lang" \
779 subpkgdir="$pkgbasedir"/$subpkgname \
780 $0 lang_subpkg prepare_package || return 1
781 done
782}
783
784# echo '-dirty' if git is not clean
785git_dirty() {
786 if [ $(git status -s "$startdir" | wc -l) -ne 0 ]; then
787 echo "-dirty"
788 fi
789}
790
791# echo last commit hash id
792git_last_commit() {
793 git log --format=oneline -n 1 "$startdir" | awk '{print $1}'
794}
795
796get_maintainer() {
797 if [ -z "$maintainer" ]; then
798 maintainer=$(awk -F': ' '/\# *Maintainer/ {print $2}' "$APKBUILD")
799 # remove surrounding whitespace
800 maintainer=$(echo "$maintainer" | xargs)
801 fi
802}
803
804check_maintainer() {
805 get_maintainer
806 if [ -z "$maintainer" ]; then
807 warning "No maintainer"
808 else
809 # try to check for a valid rfc822 address
810 case "$maintainer" in
811 *[A-Za-z0-9]*\ \<*@*.*\>) ;;
812 *) return 1 ;;
813 esac
814 fi
815}
816
817check_secfixes_comment() {
818 local c=$(sed -E -n -e '/^# secfixes:/,/(^[^#]|^$)/p' $APKBUILD | grep '^#')
819 local invalid=$(echo "$c" \
820 | grep -v -E '(^# secfixes:|^# +- [A-Z0-9-]+|^# [0-9]+.*:$|^#$)')
821 if [ -z "$invalid" ]; then
822 return 0
823 fi
824
825 # check if there are tabs
826 if echo "$invalid" | grep -q $'\t'; then
827 error "secfixes comment must not have tabs:"
828 echo "$c" | grep $'\t' >&2
829 return 1
830 fi
831
832 error "secfixes comment is not valid:"
833 echo "$invalid" >&2
834 return 1
835}
836
837check_depends_dev() {
838 if [ -z "$depends_dev" ]; then
839 return 0
840 fi
841 local i
842 for i in $pkgname $subpackages; do
843 case "${i%%:*}" in
844 *-dev) return 0 ;;
845 esac
846 done
847 return 1
848}
849
850prepare_metafiles() {
851 getpkgver || return 1
852 local name=${subpkgname:-$pkgname}
853 [ -z "${name##* *}" ] && die "package name contains spaces"
854 local dir=${subpkgdir:-$pkgdir}
855 local pkg="$name-$pkgver-r$pkgrel.apk"
856 local pkginfo="$controldir"/.PKGINFO
857 local sub
858
859 [ ! -d "$dir" ] && die "Missing $dir"
860 cd "$dir"
861 mkdir -p "$controldir"
862 local builddate=$(date -u "+%s")
863
864 # Fix package size on several filesystems
865 case "$(df -PT . | awk 'END {print $2}')" in
866 btrfs|ecryptfs|zfs)
867 sync;;
868 esac
869
870 local size=$(du -sk | awk '{print $1 * 1024}')
871
872 if [ "$arch" != "$apkbuild_arch" ]; then
873 local msg="Split function set arch=\"$arch\" for $name, use subpackages=pkg:split:arch format instead"
874 [ "$arch" != "noarch" ] && die "$msg"
875 warning "$msg"
876 subpkgarch="$arch"
877 fi
878
879 echo "# Generated by $(basename $0) $program_version" >"$pkginfo"
880 if [ -n "$FAKEROOTKEY" ]; then
881 echo "# using $($FAKEROOT -v)" >> "$pkginfo"
882 fi
883 echo "# $(date -u)" >> "$pkginfo"
884 cat >> "$pkginfo" <<-EOF
885 pkgname = $name
886 pkgver = $pkgver-r$pkgrel
887 pkgdesc = $pkgdesc
888 url = $url
889 builddate = $builddate
890 packager = ${PACKAGER:-"Unknown"}
891 size = $size
892 arch = ${subpkgarch:-$pkgarch}
893 origin = $pkgname
894 EOF
895 local i deps
896 deps="$depends"
897 if [ "$pkgname" != "busybox" ] && ! depends_has busybox && ! depends_has /bin/sh; then
898 for i in $install $triggers; do
899 local s=${i%=*}
900 [ "$name" != "${s%.*}" ] && continue
901 if head -n 1 "$startdir/$s" | grep '^#!/bin/sh' >/dev/null ; then
902 msg "Script found. /bin/sh added as a dependency for $pkg"
903 deps="$deps /bin/sh"
904 break
905 fi
906 done
907 fi
908
909 # store last_commit in global var so we only call git once
910 if [ -z "$last_commit" ]; then
911 last_commit="$(git_last_commit)$(git_dirty)"
912 fi
913 echo "commit = $last_commit" >> "$pkginfo"
914
915 get_maintainer
916 if [ -n "$maintainer" ]; then
917 echo "maintainer = $maintainer" >> "$pkginfo"
918 fi
919
920 if [ -n "$replaces_priority" ]; then
921 echo "replaces_priority = $replaces_priority" >> "$pkginfo"
922 fi
923
924 echo "license = $license" >> "$pkginfo"
925 for i in $replaces; do
926 echo "replaces = $i" >> "$pkginfo"
927 done
928 for i in $deps; do
929 echo "depend = $i" >> "$pkginfo"
930 done
931 for i in $provides; do
932 echo "provides = $i" >> "$pkginfo"
933 done
934 for i in $triggers; do
935 local f=${i%=*}
936 local dirs=${i#*=}
937 [ "${f%.trigger}" != "$name" ] && continue
938 echo "triggers = ${dirs//:/ }" >> "$pkginfo"
939 done
940 if [ -n "$install_if" ]; then
941 echo "install_if = $(echo $install_if)" >> "$pkginfo"
942 fi
943
944 local metafiles=".PKGINFO"
945 for i in $install $triggers; do
946 local f=${i%=*}
947 local n=${f%.*}
948 if [ "$n" != "$name" ]; then
949 continue
950 fi
951 script=${f#$name}
952 msg "Adding $script"
953 cp "$startdir/$f" "$controldir/$script" || return 1
954 chmod +x "$controldir/$script"
955 metafiles="$metafiles $script"
956 done
957 echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
958}
959
960prepare_trace_rpaths() {
961 local dir=${subpkgdir:-$pkgdir}
962 local etype= soname= file= sover=
963 [ "${subpkgarch:-$pkgarch}" = "noarch" ] && return 0
964 options_has "!tracedeps" && return 0
965 # lets tell all the places we should look for .so files - all rpaths
966 scanelf --quiet --recursive --rpath "$dir" \
967 | sed -e 's/[[:space:]].*//' -e 's/:/\n/' | sort -u \
968 >"$controldir"/.rpaths
969 if grep -q -x '/usr/lib' "$controldir"/.rpaths; then
970 warning "Redundant /usr/lib in rpath found"
971 fi
972 if grep '^/home/' "$controldir"/.rpaths; then
973 error "Has /home/... in rpath"
974 return 1
975 fi
976}
977
978# search for broken symlinks so we later can pull in proper depends
979prepare_symlinks() {
980 local target
981 local dir="${subpkgdir:-$pkgdir}"
982 options_has "!tracedeps" && return 0
983 cd "$dir" || return 1
984 find -type l | while read symlink; do
985 target=$(readlink "$symlink")
986 if ! [ -e "$dir$(normalize_target_path "$target" "$symlink")" ]; then
987 echo "$symlink $target" >> "$controldir"/.symlinks
988 fi
989 done
990}
991
992prepare_pkgconfig_provides() {
993 local dir="${subpkgdir:-$pkgdir}"
994 options_has "!tracedeps" && return 0
995 cd "$dir" || return 1
996 for i in usr/lib/pkgconfig/*.pc; do
997 if ! [ -e "$i" ]; then
998 continue
999 fi
1000 local f=${i##*/}
1001 local v=$(PKG_CONFIG_PATH="$dir"/usr/lib/pkgconfig PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=1 pkg-config \
1002 --modversion ${f%.pc})
1003 echo "${f%.pc}=${v:-0}" >> "$controldir"/.provides-pc
1004 done
1005}
1006
1007# check if dir has arch specific binaries
1008dir_has_arch_binaries() {
1009 local dir="$1"
1010 # if scanelf returns something, then we have binaries
1011 [ -n "$(scanelf -R "$dir" | head -n 1)" ] && return 0
1012
1013 # look for static *.a
1014 [ -n "$(find "$dir" -type f -name '*.a' | head -n 1)" ] && return 0
1015
1016 return 1
1017}
1018
1019# returns true if this is the -dev package
1020is_dev_pkg() {
1021 test "${subpkgname%-dev}" != "$subpkgname"
1022}
1023
1024# returns true if this is the -doc package
1025is_doc_pkg() {
1026 test "${1%-doc}" != "$1"
1027}
1028
1029# check that noarch is set if needed
1030archcheck() {
1031 options_has "!archcheck" && return 0
1032 if dir_has_arch_binaries "${subpkgdir:-$pkgdir}"; then
1033 [ "${subpkgarch:-$pkgarch}" != "noarch" ] && return 0
1034 error "Arch specific binaries found so arch must not be set to \"noarch\""
1035 return 1
1036 elif [ "${subpkgarch:-$pkgarch}" != "noarch" ] && ! is_dev_pkg; then
1037 # we dont want -dev package go to noarch
1038 warning "No arch specific binaries found so arch should probably be set to \"noarch\""
1039 fi
1040 return 0
1041}
1042
1043prepare_package() {
1044 msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
1045 stripbin
1046 prepare_metafiles \
1047 && prepare_trace_rpaths \
1048 && prepare_symlinks \
1049 && prepare_pkgconfig_provides \
1050 || return 1
1051 archcheck
1052}
1053
1054pkginfo_val() {
1055 local key="$1"
1056 local file="$2"
1057 awk -F ' = ' "\$1 == \"$key\" {print \$2}" "$file"
1058}
1059
1060# find real path to so files
1061real_so_path() {
1062 local so="$1"
1063 shift
1064 while [ $# -gt 0 ]; do
1065 [ -e "$1"/$so ] && realpath "$1/$so" && return 0
1066 shift
1067 done
1068 error "$so: path not found"
1069 return 1
1070}
1071
1072# search rpaths and /usr/lib /lib for given so files
1073find_so_files() {
1074 local rpaths=$(cat "$1")
1075 shift
1076 while [ $# -gt 0 ]; do
1077 real_so_path "$1" /usr/lib /lib $rpaths || return 1
1078 shift
1079 done
1080 return 0
1081}
1082
1083subpkg_provides_prefixed_so() {
1084 [ -n "$sonameprefix" ] && grep -q -w "^$sonameprefix$1" \
1085 "$pkgbasedir"/.control.*/.provides-so 2>/dev/null
1086}
1087
1088subpkg_provides_so() {
1089 grep -q -w "^$1" "$pkgbasedir"/.control.*/.provides-so 2>/dev/null
1090}
1091
1092subpkg_provides_pc() {
1093 grep -q -w "^${1%%[<>=]*}" "$pkgbasedir"/.control.*/.provides-pc \
1094 2>/dev/null
1095}
1096
1097trace_apk_deps() {
1098 local name="$1"
1099 local dir="$2"
1100 local parch="$3"
1101 local i= found= autodeps= deppkgs= missing=
1102 local apkroot=
1103
1104 case "$parch" in
1105 $CBUILD_ARCH) ;;
1106 $CARCH | $CTARGET_ARCH) apkroot="--root $CBUILDROOT --arch $CTARGET_ARCH" ;;
1107 esac
1108
1109 msg "Tracing dependencies..."
1110 # add pkgconfig if usr/lib/pkgconfig is found
1111 if [ -d "$pkgbasedir"/$name/usr/lib/pkgconfig ] \
1112 && ! grep -q '^depend = pkgconfig' "$dir"/.PKGINFO; then
1113 autodeps="$autodeps pkgconfig"
1114 fi
1115
1116 # special case for libpthread: we need depend on libgcc
1117 if [ "$CLIBC" = "uclibc" ] && [ -f "$dir"/.needs-so ] \
1118 && grep -q -w '^libpthread.so.*' "$dir"/.needs-so \
1119 && ! grep -q -w "^depend = libgcc" "$dir"/.PKGINFO; then
1120 autodeps="$autodeps libgcc"
1121 msg " added libgcc (due to libpthread)"
1122 fi
1123
1124 [ -f "$dir"/.needs-so ] && for i in $(cat "$dir"/.needs-so); do
1125 # first check if its provided by same apkbuild
1126 grep -q -w "^$sonameprefix$i" "$dir"/.provides-so 2>/dev/null && continue
1127
1128 if subpkg_provides_prefixed_so "$i"; then
1129 autodeps="$autodeps so:$sonameprefix$i"
1130 elif subpkg_provides_so "$i" \
1131 || $APK $apkroot info --quiet --installed "so:$i"; then
1132 autodeps="$autodeps so:$i"
1133 else
1134 missing="$missing $i"
1135 fi
1136 done
1137
1138 # find all packages that holds the so files
1139 if [ -f "$dir"/.rpaths ]; then
1140 local so_files=$(find_so_files "$dir"/.rpaths $missing) \
1141 || return 1
1142 deppkgs=$($APK $apkroot info --quiet --who-owns $so_files) || return 1
1143 fi
1144
1145 for found in $deppkgs; do
1146 if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
1147 warning "You can remove '$found' from depends"
1148 continue
1149 fi
1150 autodeps="$autodeps $found"
1151 done
1152
1153 # symlink targets
1154 for i in $(sort -u "$dir"/.symlinks-needs 2>/dev/null); do
1155 autodeps="$autodeps $i"
1156 done
1157
1158 # pkg-config depends
1159 for i in $(sort -u "$dir"/.needs-pc 2>/dev/null); do
1160 if subpkg_provides_pc "$i" \
1161 || $APK $apkroot info --quiet --installed "pc:$i"; then
1162 local provider=$(apk $apkroot search --quiet "pc:$i")
1163 if list_has "$provider" $depends_dev; then
1164 warning "$provider should be removed from depends_dev"
1165 fi
1166 autodeps="$autodeps pc:$i"
1167 else
1168 warning "Could not find any provider for pc:$i"
1169 local pcfile=/usr/lib/pkgconfig/"${i%%[<>=]*}".pc
1170 if [ -e "$pcfile" ]; then
1171 local owner=$($APK $apkroot info --quiet --who-owns $pcfile)
1172 warning "${owner:-package providing $pcfile} needs to be rebuilt"
1173 fi
1174 fi
1175 done
1176
1177 echo "# automatically detected:" >> "$dir"/.PKGINFO
1178 if [ -f "$dir"/.provides-so ]; then
1179 sed 's/^\(.*\) \([0-9].*\)/provides = so:\1=\2/' \
1180 "$dir"/.provides-so | sort -u \
1181 >> "$dir"/.PKGINFO
1182 fi
1183 if [ -f "$dir"/.provides-pc ]; then
1184 sed 's/^/provides = pc:/' "$dir"/.provides-pc | sort -u \
1185 >> "$dir"/.PKGINFO
1186 fi
1187 [ -z "$autodeps" ] && return 0
1188 for i in $autodeps; do
1189 echo "depend = $i"
1190 done | sort -u >> "$dir"/.PKGINFO
1191 # display all depends
1192 sed -n '/^depend =/s/depend = /\t/p' "$dir"/.PKGINFO >&2
1193}
1194
1195find_scanelf_paths() {
1196 local datadir="$1"
1197 local paths="$datadir/lib:$datadir/usr/lib" i= rpaths=
1198 if [ -n "$ldpath" ]; then
1199 paths="$paths:$(echo "${datadir}${ldpath}" | sed "s|:|:$datadir|g")"
1200 fi
1201 # search in all rpaths
1202 for rpaths in "$pkgbasedir"/.control.*/.rpaths; do
1203 [ -f "$rpaths" ] || continue
1204 while read i; do
1205 local dir="${datadir}${i}"
1206 IFS=:
1207 if [ -d "$dir" ] && ! list_has "$dir" $paths; then
1208 paths="$paths:${dir}"
1209 fi
1210 unset IFS
1211 done < "$rpaths"
1212 done
1213 echo "$paths"
1214}
1215
1216scan_shared_objects() {
1217 local name="$1" controldir="$2" datadir="$3"
1218 local opt= i=
1219
1220 if [ "${subpkgarch:-$pkgarch}" = "noarch" ]; then
1221 return 0
1222 fi
1223
1224 # allow spaces in paths
1225 IFS=:
1226 set -- $(find_scanelf_paths "$datadir")
1227 unset IFS
1228
1229 # sanity check, verify that each path is prefixed with datadir
1230 for i; do
1231 if [ "${i#$datadir}" = "$i" ]; then
1232 error "Internal error in scanelf paths"
1233 return 1
1234 fi
1235 done
1236
1237 if options_has "ldpath-recursive"; then
1238 opt="--recursive"
1239 fi
1240 msg "Scanning shared objects"
1241 # lets tell all the .so files this package provides in .provides-so
1242 scanelf --nobanner --soname $opt "$@" | while read etype soname file; do
1243 # if soname field is missing, soname will be the filepath
1244 sover=0
1245 if [ -z "$file" ]; then
1246 file="$soname"
1247 soname=${soname##*/}
1248 fi
1249
1250 # we only want shared libs
1251 case $soname in
1252 *.so|*.so.[0-9]*|*.c32);;
1253 *) continue;;
1254 esac
1255
1256 case "$file" in
1257 *.so.[0-9]*) sover=${file##*.so.};;
1258 *.so)
1259 # filter out sonames with version when file does not
1260 # have version
1261 case "$soname" in
1262 *.so.[0-9]*)
1263 if options_has "sover-namecheck"; then
1264 continue
1265 fi
1266 esac
1267 ;;
1268 esac
1269 list_has "$soname" $somask && continue
1270 echo "$sonameprefix$soname $sover"
1271 # use awk to filter out dupes that has sover = 0
1272 done | awk '{ if (so[$1] == 0) so[$1] = $2; }
1273 END { for (i in so) print(i " " so[i]); }' \
1274 | sort -u > "$controldir"/.provides-so
1275
1276 # verify that we dont have any duplicates
1277 local dupes="$(cut -d' ' -f1 "$controldir"/.provides-so | uniq -d)"
1278 if [ -n "$dupes" ]; then
1279 die "provides multiple versions of same shared object: $dupes"
1280 fi
1281
1282 # now find the so dependencies
1283 scanelf --nobanner --recursive --needed "$datadir" | tr ' ' ':' \
1284 | awk -F ":" '$2 != "" && ($1 == "ET_DYN" || $1 == "ET_EXEC") {print $2}' \
1285 | sed 's:,:\n:g' | sort -u \
1286 | while read soname; do
1287 # only add files that are not self provided
1288 grep -q -w "^$sonameprefix$soname" "$controldir"/.provides-so \
1289 || list_has "$soname" $somask \
1290 || echo $soname
1291 done > "$controldir"/.needs-so
1292}
1293
1294# normalize a symlink target path (1st arg)
1295# Converts a relative path to absolute with respect to the symlink
1296# path (2nd arg).
1297normalize_target_path() {
1298 local path=$1
1299 [ "${path:0:1}" = / ] || path=$(dirname "$2")/$path
1300
1301 local oifs="$IFS" pathstr= i=
1302 IFS='/'
1303 set -- $path
1304 for i; do
1305 case "$i" in
1306 "."|"") continue;;
1307 "..") pathstr="${pathstr%%/${pathstr##*/}}";;
1308 *) pathstr="${pathstr}/$i";;
1309 esac
1310 done
1311 echo "$pathstr"
1312}
1313
1314# find which package provides file that symlink points to
1315scan_symlink_targets() {
1316 local name="$1" dir="$2" datadir="$3"
1317 local symfile= targetpath=
1318 cd "$datadir"
1319 for symfile in "$pkgbasedir"/.control.*/.symlinks; do
1320 local d="${symfile%/.symlinks}"
1321 if ! [ -e "$symfile" ] || [ "$d" = "$dir" ]; then
1322 continue
1323 fi
1324
1325 while read symlink target; do
1326 targetpath=$datadir$(normalize_target_path "$target" "$symlink")
1327 if [ -e "$targetpath" ] || [ -L "$targetpath" ]; then
1328 echo "$name=$pkgver-r$pkgrel" \
1329 >> "$d"/.symlinks-needs
1330 fi
1331 done < "$symfile"
1332 done
1333}
1334
1335#find pkg-config dependencies
1336scan_pkgconfig_depends() {
1337 local provides_pc="$1" controldir= name= datadir=
1338 [ -e "$provides_pc" ] || return 0
1339 controldir="${provides_pc%/*}"
1340 name="$(pkginfo_val pkgname "$controldir"/.PKGINFO)"
1341 datadir="$pkgbasedir"/$name
1342 for i in $(sort -u "$provides_pc"); do
1343 PKG_CONFIG_PATH="$datadir"/usr/lib/pkgconfig pkg-config \
1344 --print-requires \
1345 --print-requires-private ${i%=*} \
1346 | sed -E 's/\s*([<>=]+)\s*/\1/' \
1347 | while read pc; do
1348 # only add files that are not self provided
1349 if ! grep -q -w "^${pc%%[<>=]*}" "$provides_pc"; then
1350 echo "$pc" >> "$controldir"/.needs-pc
1351 fi
1352 done
1353 done
1354}
1355
1356# read size in bytes from stdin and show as human readable
1357human_size() {
1358 awk '{ split("B KB MB GB TB PB", type)
1359 for(i=5; y < 1 && $1 > 0; i--)
1360 y = $1 / (2^(10*i))
1361 printf("%.1f %s\n", y, type[i+2]) }'
1362}
1363
1364create_apks() {
1365 local file= dir= name= ver= apk= datadir= size=
1366 getpkgver || return 1
1367 if ! options_has "!tracedeps"; then
1368 for file in "$pkgbasedir"/.control.*/.PKGINFO; do
1369 dir="${file%/.PKGINFO}"
1370 name="$(pkginfo_val pkgname $file)"
1371 datadir="$pkgbasedir"/$name
1372 subpkgname=$name
1373 scan_shared_objects "$name" "$dir" "$datadir"
1374 scan_symlink_targets "$name" "$dir" "$datadir"
1375 done
1376 for file in "$pkgbasedir"/.control.*/.provides-pc; do
1377 scan_pkgconfig_depends "$file"
1378 done
1379 fi
1380
1381 for file in "$pkgbasedir"/.control.*/.PKGINFO; do
1382 local dir="${file%/.PKGINFO}"
1383 local name=$(pkginfo_val pkgname $file)
1384 local ver=$(pkginfo_val pkgver $file)
1385 local size=$(pkginfo_val size $file | human_size)
1386 local apk=$name-$ver.apk
1387 local datadir="$pkgbasedir"/$name
1388 local subpkgname=$name
1389 local subpkgarch=$(pkginfo_val arch $file)
1390
1391 trace_apk_deps "$name" "$dir" "$subpkgarch" || return 1
1392 msg "Package size: ${size}"
1393 msg "Compressing data..."
1394 (
1395 cd "$datadir"
1396 # data.tar.gz
1397 set -- *
1398 if [ "$1" = '*' ]; then
1399 touch .dummy
1400 set -- .dummy
1401 fi
1402 tar --xattrs -f - -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
1403
1404 msg "Create checksum..."
1405 # append the hash for data.tar.gz
1406 local sha256=$(sha256sum "$dir"/data.tar.gz | cut -f1 -d' ')
1407 echo "datahash = $sha256" >> "$dir"/.PKGINFO
1408
1409 # control.tar.gz
1410 cd "$dir"
1411 tar -f - -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
1412 | gzip -9 > control.tar.gz
1413 abuild-sign -q control.tar.gz || exit 1
1414
1415 msg "Create $apk"
1416 mkdir -p "$REPODEST"/$repo/${subpkgarch/noarch/$CARCH}
1417 cat control.tar.gz data.tar.gz > "$REPODEST"/$repo/${subpkgarch/noarch/$CARCH}/$apk
1418 )
1419 done
1420}
1421
1422build_abuildrepo() {
1423 local d apk _build=build _check=check_fakeroot
1424 if ! is_function package; then
1425 # if package() is missing then build is called from rootpkg
1426 _build=true
1427 fi
1428 if options_has "!checkroot"; then
1429 _check=check
1430 fi
1431 if ! want_check; then
1432 _check=true
1433 fi
1434 if ! apk_up2date || [ -n "$force" ]; then
1435 print_version
1436 # check early if we have abuild key
1437 abuild-sign --installed
1438 logcmd "building $repo/$pkgname-$pkgver-r$pkgrel"
1439 sanitycheck
1440 builddeps
1441 clean
1442 fetch
1443 unpack
1444 prepare
1445 mkusers
1446 $_build
1447 $_check
1448 rootpkg
1449 cleanup $CLEANUP
1450 fi
1451 update_abuildrepo_index
1452}
1453
1454update_abuildrepo_index() {
1455 local i allarch=""
1456 for i in $allpackages; do
1457 subpkg_set "$i"
1458 ##NOARCH: These packages are really in $CARCH and do not need their
1459 # own repository. --rewrite-arch is used below to make sure the index
1460 # thinks they are for $CARCH and apk-tools will fetch them from
1461 # correct URL path. Remainder of the script uses ${subpkgarch/noarch/$CARCH}
1462 # when expanding to the target repository path.
1463 [ "$subpkgarch" = "noarch" ] && subpkgarch="$CARCH"
1464 list_has "$subpkgarch" "$allarch" || allarch="$allarch $subpkgarch"
1465 done
1466 subpkg_unset
1467
1468 [ -z "$DESCRIPTION" ] && DESCRIPTION="$repo $(cd $startdir && git describe || true)"
1469 for i in $allarch; do
1470 cd "$REPODEST/$repo/$i"
1471 local index=$i/APKINDEX.tar.gz
1472
1473 msg "Updating the $repo/$i repository index..."
1474 local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
1475 local oldindex=
1476 if [ -f APKINDEX.tar.gz ]; then
1477 oldindex="--index APKINDEX.tar.gz"
1478 fi
1479 ( $APK index --quiet $oldindex --output APKINDEX.tar.gz.$$ \
1480 --description "$DESCRIPTION" --rewrite-arch $i *.apk && \
1481 msg "Signing the index..." && \
1482 abuild-sign -q APKINDEX.tar.gz.$$ && \
1483 chmod 644 APKINDEX.tar.gz.$$ && \
1484 mv APKINDEX.tar.gz.$$ APKINDEX.tar.gz \
1485 ) || (rm -f APKINDEX.tar.gz.$$ ; die "Failed to create index")
1486 done
1487}
1488
1489# predefined function check
1490default_check() {
1491 warning "APKBUILD does not run any tests!"
1492 msg2 "Alpine policy will soon require that packages have any relevant testsuites run during the build process."
1493 msg2 "To fix, either define a check() function, or declare !check in \$options to indicate the package does not have a testsuite."
1494}
1495
1496check() {
1497 default_check
1498}
1499
1500# predefined splitfunc doc
1501default_doc() {
1502 depends="$depends_doc"
1503 pkgdesc="$pkgdesc (documentation)"
1504 install_if="docs $pkgname=$pkgver-r$pkgrel"
1505
1506 local i
1507 for i in doc man info html sgml licenses gtk-doc ri help; do
1508 if [ -d "$pkgdir/usr/share/$i" ]; then
1509 mkdir -p "$subpkgdir/usr/share"
1510 mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
1511 fi
1512 done
1513
1514 # compress man pages
1515 local mandir="$subpkgdir"/usr/share/man
1516 [ -d "$mandir" ] && find "$mandir" -type l \
1517 -a \( -name \*.[0-8n] -o -name \*.[0-8][a-z]* \) \
1518 -a \! \( -name '*.gz' -o -name '*.bz2' -o -name '*.xz' \) \
1519 | while read symlink; do
1520
1521 ln -s $(readlink $symlink).gz "$symlink".gz
1522 rm -f "$symlink"
1523 done
1524 [ -d "$mandir" ] && find "$mandir" -type f \
1525 -a \( -name \*.[0-8n] -o -name \*.[0-8][a-z]* \) \
1526 -a \! \( -name '*.gz' -o -name '*.bz2' -o -name '*.xz' \) \
1527 -exec stat -c "%i %n" \{\} \+ | while read inode name; do
1528
1529 # Skip hardlinks removed in last iteration.
1530 [ -f "$name" ] || continue
1531
1532 local islink=0
1533 find "$mandir" -type f -links +1 \
1534 -a \( -name \*.[0-8n] -o -name \*.[0-8][a-z]* \) \
1535 -a \! \( -name '*.gz' -o -name '*.bz2' -o -name '*.xz' \) \
1536 -exec stat -c "%i %n" \{\} \+ | while read linode lname; do
1537 if [ "$linode" = "$inode" -a "$lname" != "$name" ]; then
1538 islink=1
1539 rm -f "$lname"
1540 ln -s "${name##*/}".gz "$lname".gz
1541 fi
1542 done
1543
1544 [ $islink -eq 0 ] && gzip -9 "$name"
1545 done
1546
1547 rm -f "$subpkgdir/usr/share/info/dir"
1548
1549 # remove if empty, ignore error (not empty)
1550 rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null || :
1551}
1552
1553doc() {
1554 default_doc
1555}
1556
1557# predefined splitfunc dbg
1558default_dbg() {
1559 local f
1560 pkgdesc="$pkgdesc (debug symbols)"
1561
1562 binfiles=$(scanelf -R "$pkgdir" | grep ET_DYN | sed "s:$pkgdir\/::g" | sed "s:ET_DYN ::g")
1563 for f in $binfiles; do
1564 srcdir=$(dirname $pkgdir/$f)
1565 srcfile=$(basename $pkgdir/$f)
1566 dstdir=$(dirname $subpkgdir/usr/lib/debug/$f.debug)
1567 dstfile=$(basename $subpkgdir/usr/lib/debug/$f.debug)
1568 if [ ! -d $dstdir ] ; then
1569 mkdir -p $dstdir
1570 fi
1571 cd $srcdir
1572 local XATTR=$(getfattr --match="" --dump "${srcfile}")
1573 ${CROSS_COMPILE}objcopy --only-keep-debug $srcfile $dstfile
1574 ${CROSS_COMPILE}objcopy --add-gnu-debuglink=$dstfile $srcdir/$srcfile
1575 mv $dstfile $dstdir
1576 ${CROSS_COMPILE}strip $srcfile
1577 [ -n "$XATTR" ] && { echo "$XATTR" | setfattr --restore=-; }
1578 done
1579 return 0
1580}
1581
1582dbg() {
1583 default_dbg
1584}
1585
1586# predefined splitfunc dev
1587default_dev() {
1588 local i= j=
1589 depends="$depends_dev"
1590 pkgdesc="$pkgdesc (development files)"
1591
1592 cd "$pkgdir" || return 0
1593 local libdirs=usr/
1594 [ -d lib/ ] && libdirs="lib/ $libdirs"
1595 for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
1596 usr/share/gettext usr/bin/*-config \
1597 usr/share/vala/vapi usr/share/gir-[0-9]*\
1598 usr/share/qt*/mkspecs \
1599 usr/lib/qt*/mkspecs \
1600 usr/lib/cmake \
1601 $(find . -name include -type d) \
1602 $(find $libdirs -name '*.[acho]' \
1603 -o -name '*.prl' 2>/dev/null); do
1604 if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
1605 d="$subpkgdir/${i%/*}" # dirname $i
1606 mkdir -p "$d"
1607 mv "$pkgdir/$i" "$d"
1608 rmdir "$pkgdir/${i%/*}" 2>/dev/null || :
1609 fi
1610 done
1611 # move *.so links needed when linking the apps to -dev packages
1612 for i in lib/*.so usr/lib/*.so; do
1613 if [ -L "$i" ]; then
1614 mkdir -p "$subpkgdir"/"${i%/*}"
1615 mv "$i" "$subpkgdir/$i" || return 1
1616 fi
1617 done
1618 return 0
1619}
1620
1621dev() {
1622 default_dev
1623}
1624
1625# predefined splitfunc libs
1626default_libs() {
1627 pkgdesc="$pkgdesc (libraries)"
1628 local dir= file=
1629 for dir in lib usr/lib; do
1630 for file in "$pkgdir"/$dir/lib*.so.[0-9]*; do
1631 [ -f "$file" ] || continue
1632 mkdir -p "$subpkgdir"/$dir
1633 mv "$file" "$subpkgdir"/$dir/
1634 done
1635 done
1636}
1637
1638libs() {
1639 default_libs
1640}
1641
1642# predefined splitfunc openrc
1643default_openrc() {
1644 pkgdesc="$pkgdesc (OpenRC init scripts)"
1645 install_if="openrc $pkgname=$pkgver-r$pkgrel"
1646 local dir file
1647 for dir in conf.d init.d; do
1648 if [ -d "$pkgdir/etc/$dir" ]; then
1649 mkdir -p "$subpkgdir"/etc
1650 mv "$pkgdir/etc/$dir" "$subpkgdir"/etc/
1651 fi
1652 done
1653 return 0
1654}
1655
1656openrc() {
1657 default_openrc
1658}
1659
1660
1661is_function() {
1662 type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
1663}
1664
1665do_fakeroot() {
1666 if [ -n "$FAKEROOT" ]; then
1667 $FAKEROOT -- "$@"
1668 else
1669 "$@"
1670 fi
1671}
1672
1673# wrap check() with fakeroot
1674check_fakeroot() {
1675 cd "$startdir"
1676 [ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
1677 do_fakeroot "$abuild_path" $color_opt $keep_build check
1678}
1679
1680# build and package in fakeroot
1681rootpkg() {
1682 local _package=package
1683 if ! is_function package; then
1684 # if package() is missing then run 'build' in fakeroot instead
1685 warning "No package() function in APKBUILD"
1686 _package=build
1687 fi
1688 cd "$startdir"
1689 rm -rf "$pkgdir"
1690 [ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
1691 do_fakeroot "$abuild_path" $color_opt $keep_build \
1692 $_package \
1693 prepare_subpackages \
1694 prepare_language_packs \
1695 prepare_package \
1696 create_apks
1697}
1698
1699srcpkg() {
1700 echo "Ensuring source is fetched"
1701 fetch
1702 getpkgver || return 1
1703 local p="$pkgname-$pkgver-$pkgrel"
1704 local prefix="${startdir##*/}"
1705 local i files="$prefix/APKBUILD"
1706 for i in $source; do
1707 echo "Packaging source file: $i"
1708 if [ ! -e $(filename_from_uri $i) ]; then
1709 cp $srcdir/$(filename_from_uri $i) $(filename_from_uri $i)
1710 fi
1711 files="$files $prefix/$(filename_from_uri $i)"
1712 done
1713
1714 for i in $install; do
1715 echo "Packaging install file: $i"
1716 files="$files $prefix/$i"
1717 done
1718
1719 for i in $triggers; do
1720 local f=${i%=*}
1721 echo "Packaging trigger file: $f"
1722 files="$files $prefix/$f"
1723 done
1724
1725 mkdir -p "$REPODEST/src"
1726 msg "Creating source package $p.src.tar.gz..."
1727 (cd .. && tar -zcf "$REPODEST/src/$p.src.tar.gz" $files)
1728}
1729
1730# return true if arch is supported or noarch
1731check_arch() {
1732 local ret=1
1733 local i
1734 for i in $arch; do
1735 case $i in
1736 all | noarch) ret=0 ;;
1737 "$CARCH") ret=0 ;;
1738 "!$CARCH") return 1 ;;
1739 esac
1740 done
1741 return $ret
1742}
1743
1744# return true if libc is not masked in options
1745check_libc() {
1746 ! list_has "!libc_$CLIBC" $options
1747}
1748
1749# check if package is up to date
1750apk_up2date() {
1751 getpkgver || return 1
1752
1753 local i s
1754 for i in $allpackages; do
1755 subpkg_set "$i"
1756 if [ ! -f "$REPODEST/$repo/${subpkgarch/noarch/$CARCH}/$subpkgname-$pkgver-r$pkgrel.apk" ]; then
1757 subpkg_unset
1758 return 1
1759 fi
1760 done
1761 subpkg_unset
1762 [ -n "$keep" ] && return 0
1763
1764 cd "$startdir"
1765 for i in $source APKBUILD; do
1766 if is_remote "$i"; then
1767 s="$SRCDEST/$(filename_from_uri $i)"
1768 else
1769 s="$startdir/${i##*/}"
1770 fi
1771 if [ "$s" -nt "$REPODEST/$repo/${pkgarch/noarch/$CARCH}/$pkgname-$pkgver-r$pkgrel.apk" ]; then
1772 return 1
1773 fi
1774 done
1775 return 0
1776}
1777
1778abuildindex_up2date() {
1779 local i
1780 getpkgver || return 1
1781
1782 for i in $allpackages; do
1783 subpkg_set "$i"
1784 local dir="$REPODEST"/$repo/${subpkgarch/noarch/$CARCH}
1785 local idx="$dir"/APKINDEX.tar.gz
1786 local file="$dir"/$subpkgname-$pkgver-r$pkgrel.apk
1787
1788 # if any file is missing or .apk is newer then index
1789 # the index needs to be updated
1790 if [ ! -f "$idx" -o ! -f "$file" -o "$file" -nt "$idx" ]; then
1791 subpkg_unset
1792 return 1
1793 fi
1794 done
1795 subpkg_unset
1796
1797 return 0
1798}
1799
1800up2date() {
1801 check_arch || return 0
1802 check_libc || return 0
1803 apk_up2date && abuildindex_up2date
1804}
1805
1806# rebuild package and abuildrepo index if needed
1807abuildindex() {
1808 up2date && return 0
1809 build_abuildrepo
1810}
1811
1812# source all APKBUILDs and output:
1813# 1) origin of package
1814# 2) all dependencies
1815# the output is i in a format easy parseable for awk
1816parse_aports_makedepends() {
1817 # lets run this in a subshell since we source all APKBUILD here
1818 (
1819 aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
1820 for i in $aportsdir/*/APKBUILD; do
1821 # no forks in this loop or it will be painfully slow!
1822 pkgname=
1823 subpackages=
1824 depends=
1825 makedepends=
1826 checkdepends=
1827 . $i
1828 dir=${i%/APKBUILD}
1829 deps=
1830 # filter out conflicts from deps and version info
1831 wantdepends="$depends $makedepends"
1832 want_check && wantdepends="$wantdepends $checkdepends"
1833 for j in $wantdepends; do
1834 case "$j" in
1835 !*) continue;;
1836 esac
1837 deps="$deps ${j%%[<>=]*}"
1838 done
1839 for j in $pkgname $subpackages; do
1840 echo "o ${j%%:*} $dir"
1841 set -- $deps
1842 if [ $# -eq 0 ]; then
1843 echo "d ${j%%:*}"
1844 continue
1845 fi
1846 echo -n "d ${j%%:*} $1"
1847 shift
1848 while [ $# -gt 0 ]; do
1849 echo -n ",$1"
1850 shift
1851 done
1852 echo
1853 done
1854 done
1855 )
1856}
1857
1858trace_makedepends() {
1859 local deps= i=
1860 # strip versions from deps
1861 for i in "$@"; do
1862 deps="$deps ${i%%[<>=]*}"
1863 done
1864 [ -z "$deps" ] && return 0
1865 ( parse_aports_makedepends
1866 if [ -z "$upgrade" ]; then
1867 # list installed pkgs and prefix with 'i '
1868 $APK info --quiet | sort | sed 's/^/i /'
1869 fi
1870 ) | awk -v pkgs="$deps" '
1871
1872 function depgraph(pkg, a, i) {
1873 if (visited[pkg])
1874 return 0;
1875 visited[pkg] = 1;
1876 split(deps[pkg], a, ",");
1877 for (i in a)
1878 depgraph(a[i]);
1879 print pkg ":" origin[pkg];
1880
1881 }
1882
1883 $1 == "i" { visited[$2] = 1 }
1884 $1 == "o" { origin[$2] = $3 }
1885 $1 == "d" { deps[$2] = $3 }
1886 END {
1887 split(pkgs, pkgarray);
1888 for (i in pkgarray)
1889 depgraph(pkgarray[i]);
1890 }
1891 '
1892}
1893
1894calcdeps() {
1895 builddeps=
1896 hostdeps=
1897
1898 if cross_compiling && [ -n "$makedepends_build" -o -n "$makedepends_host" ]; then
1899 for i in $EXTRADEPENDS_BUILD $1 $makedepends_build; do
1900 list_has $i $hostdeps && continue
1901 builddeps="$builddeps $i"
1902 done
1903 for i in $EXTRADEPENDS_HOST $EXTRADEPENDS_TARGET $makedepends_host; do
1904 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
1905 list_has $i $hostdeps && continue
1906 subpackages_has ${i%%[<>=]*} || hostdeps="$hostdeps $i"
1907 done
1908 else
1909 [ -z "$makedepends" ] && makedepends="$makedepends_build $makedepends_host"
1910 want_check && makedepends="$makedepends $checkdepends"
1911 for i in $EXTRADEPENDS_BUILD $EXTRADEPENDS_HOST $1 $depends $makedepends; do
1912 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
1913 list_has $i $builddeps && continue
1914 subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
1915 done
1916 hostdeps="$EXTRADEPENDS_TARGET"
1917 fi
1918}
1919
1920get_missing_deps() {
1921 local cmd="$APK info --quiet --installed $1"
1922 shift
1923
1924 while [ "$1" ]; do
1925 local cp=${1#\!}
1926 if [ $cp != $1 ]; then
1927 if $cmd $cp; then
1928 error "Conflicting package installed: $cp"
1929 return 1
1930 fi
1931 elif [ "$upgrade" ] || ! $cmd $1; then
1932 echo $1
1933 fi
1934 shift
1935 done
1936}
1937
1938# build and install dependencies
1939builddeps() {
1940 local pkg= i= BUILD_BASE=
1941 [ -n "$nodeps" ] && return 0
1942
1943 msg "Analyzing dependencies..."
1944 case "$BOOTSTRAP" in
1945 no*) BUILD_BASE="";;
1946 *) if cross_creating || cross_compiling; then
1947 BUILD_BASE="build-base-$CTARGET_ARCH"
1948 else
1949 BUILD_BASE="build-base"
1950 fi
1951 esac
1952 calcdeps "$BUILD_BASE"
1953
1954 # find which deps are missing
1955 local mbd mhd missing
1956 mbd=$(get_missing_deps "" $builddeps) || return 1
1957 mhd=$(get_missing_deps "--root $CBUILDROOT --arch $CTARGET_ARCH" $hostdeps) || return 1
1958 missing=$(echo $mbd $mhd)
1959
1960 if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
1961 # if we dont have any missing deps we are done now
1962 [ -z "$missing" ] && return 0
1963 error "Missing dependencies (use -r to autoinstall or -R to build them): $missing"
1964 return 1
1965 fi
1966
1967 uninstall_after=".makedepends-$pkgname $uninstall_after"
1968 if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
1969 # make a --simulate run first to detect missing deps
1970 # apk-tools --virtual is no goot at reporting those.
1971 deps "--quiet --simulate" || return 1
1972 deps || return 1
1973 return 0
1974 fi
1975
1976 [ -z "$recursive" ] && return 1
1977
1978 if [ -n "$CBUILDROOT" ]; then
1979 error "Recursive rebuilding (-R) is not supported when cross compiling."
1980 return 1
1981 fi
1982
1983 # find dependencies that are installed but missing in repo.
1984 for i in $builddeps; do
1985 local m=$($APK search --repository "$REPODEST/$repo" ${i%%[<>=]*})
1986 if [ -z "$m" ]; then
1987 missing="$missing $i"
1988 fi
1989 done
1990
1991 for i in $(trace_makedepends $missing); do
1992 # i = pkg:dir
1993 local dir=${i#*:}
1994 local pkg=${i%:*}
1995
1996 # ignore if dependency is in other repo
1997 [ -d "$dir" ] || continue
1998
1999 # check if dep is blacklisted
2000 if list_has $pkg $ABUILD_BLACKLIST; then
2001 error "$pkg is blacklisted"
2002 return 1
2003 fi
2004
2005 # break circular deps
2006 list_has $pkg $ABUILD_VISITED && continue
2007 export ABUILD_VISITED="$ABUILD_VISITED $pkg"
2008
2009 msg "Entering $dir"
2010 cd "$dir" && $0 $forceroot $keep $keep_build $quiet \
2011 $install_deps $recursive $upgrade $color_opt \
2012 abuildindex || return 1
2013 done
2014 $SUDO_APK add --upgrade --repository "$REPODEST/$repo" \
2015 $apk_opt_wait \
2016 --virtual .makedepends-$pkgname $builddeps \
2017 || return 1
2018}
2019
2020# replace the md5sums in the APKBUILD
2021checksum() {
2022 local s files
2023 [ -z "$source" ] && [ -n "${md5sums}${sha256sums}${sha512sums}" ] \
2024 && msg "Removing checksums from APKBUILD"
2025 sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
2026 sed -i -e '/^sha512sums="/,/"\$/d; /^sha512sums=''/,/''\$/d' "$APKBUILD"
2027 sed -i -e '/^sha256sums="/,/"\$/d; /^sha256sums=''/,/''\$/d' "$APKBUILD"
2028 [ -z "$source" ] && return 0
2029 fetch
2030 for s in $source; do
2031 files="$files $(filename_from_uri $s)"
2032 done
2033
2034 msg "Updating the sha512sums in APKBUILD..."
2035 md5sums=
2036 sha256sums=
2037 sha512sums="$(cd "$srcdir" && sha512sum $files)" \
2038 || die "sha512sum failed"
2039 echo "sha512sums=\"$sha512sums\"" >>"$APKBUILD"
2040}
2041
2042rootbld_actions() {
2043 local part
2044 for part in symlinksrc unpack prepare build rootpkg; do
2045 runpart $part
2046 done
2047}
2048
2049rootbld() {
2050 if apk_up2date && [ -z "$force" ]; then
2051 msg "Package is up to date"
2052 return
2053 fi
2054
2055 [ "$CBUILD" = "$CHOST" ] || die "rootbld: cross-building not supported currently"
2056 apk info -eq abuild-rootbld || die "rootbld: abuild-rootbld package not installed"
2057
2058 logcmd "chroot building building $repo/$pkgname-$pkgver-r$pkgrel"
2059
2060 # check early if we have abuild key
2061 abuild-sign --installed
2062
2063 # networking business
2064 sanitycheck
2065 clean
2066 fetch
2067 verify
2068
2069 msg "Preparing build chroot..."
2070
2071 mkusers
2072
2073 BUILD_ROOT=$(mktemp -d /var/tmp/abuild.XXXXXXXXXX)
2074 local aportsgit=${APORTSDIR:-${startdir}}
2075
2076 mkdir -p "$BUILD_ROOT/proc" "$BUILD_ROOT/etc/apk/keys" \
2077 "$BUILD_ROOT/$HOME/.abuild" "$BUILD_ROOT/$aportsgit" \
2078 "$BUILD_ROOT/$SRCDEST" "$BUILD_ROOT/$REPODEST" \
2079 "$BUILD_ROOT/tmp/pkg" "$BUILD_ROOT/tmp/src" \
2080 "$BUILD_ROOT/usr/bin" "$pkgbasedir" "$REPODEST" \
2081 "$srcdir"
2082
2083 cp /etc/abuild.conf /etc/group /etc/passwd "$BUILD_ROOT/etc"
2084 cp /etc/apk/keys/* "$BUILD_ROOT/etc/apk/keys"
2085
2086 local version="edge" buildhost="edge" gitref
2087 if gitref="$(expr "$(git symbolic-ref --short HEAD)" : '\([0-9]\+\(\.[0-9]\+\)*\)-')"; then
2088 version=v${gitref}
2089 buildhost=${gitref/./-}
2090 fi
2091
2092 local repo_template=$aportsgit/$repo/.rootbld-repositories
2093 [ -s "$repo_template" ] || die "rootbld: $repo_template does not exist"
2094 (
2095 for key in $(git config --list --name-only); do
2096 k=${key#abuild.}
2097 [ $k != $key ] && \
2098 eval "export $k=\"$(git config --get $key)\""
2099 done
2100
2101 export mirror version
2102 [ "$mirror" ] || mirror=http://dl-cdn.alpinelinux.org/alpine
2103
2104 envsubst
2105 echo "$REPODEST/$repo"
2106 ) < "$repo_template" > "$BUILD_ROOT/etc/apk/repositories"
2107
2108 calcdeps
2109 $SUDO_APK add --initdb --root "$BUILD_ROOT" --update \
2110 abuild alpine-base build-base git $hostdeps $builddeps
2111
2112 local bwrap_opts=""
2113 options_has "net" || bwrap_opts="$bwrap_opts --unshare-net"
2114 bwrap --unshare-ipc --unshare-uts $bwrap_opts \
2115 --ro-bind "$BUILD_ROOT" / \
2116 --proc /proc \
2117 --dev-bind /dev /dev \
2118 --ro-bind "$HOME/.abuild" "$HOME/.abuild" \
2119 --ro-bind "$aportsgit" "$aportsgit" \
2120 --bind "$SRCDEST" "$SRCDEST" \
2121 --bind "$BUILD_ROOT/tmp/src" "$srcdir" \
2122 --bind "$BUILD_ROOT/tmp/pkg" "$pkgbasedir" \
2123 --bind "$BUILD_ROOT/tmp" /tmp \
2124 --bind "$REPODEST" "$REPODEST" \
2125 --hostname "build-$buildhost-$CARCH" \
2126 --chdir "$startdir" \
2127 --setenv PATH /bin:/usr/bin:/sbin:/usr/sbin \
2128 /usr/bin/abuild $force rootbld_actions
2129 update_abuildrepo_index
2130 cleanup $CLEANUP
2131}
2132
2133stripbin() {
2134 local bin
2135 if options_has "!strip" || [ "${subpkgarch:-$pkgarch}" = "noarch" ]; then
2136 return 0
2137 fi
2138 cd "${subpkgdir:-$pkgdir}" || return 1
2139
2140 local stripcmd=strip
2141 case "${subpkgarch:-$pkgarch}" in
2142 $CBUILD_ARCH) stripcmd="strip" ;;
2143 $CARCH) stripcmd="${CHOST}-strip" ;;
2144 $CTARGET_ARCH) stripcmd="${CTARGET}-strip" ;;
2145 esac
2146
2147 msg "Stripping binaries"
2148 scanelf --recursive --nobanner --osabi --etype "ET_DYN,ET_EXEC" . \
2149 | while read type osabi filename; do
2150 [ "$osabi" != "STANDALONE" ] || continue
2151 local XATTR=$(getfattr --match="" --dump "${filename}")
2152 "${stripcmd}" "${filename}"
2153 if [ -n "$XATTR" ]; then
2154 echo "$XATTR" | setfattr --restore=-
2155 fi
2156 done
2157}
2158
2159# simply list target apks
2160listpkg() {
2161 local name
2162 getpkgver || return 1
2163 for name in $allpackages ; do
2164 subpkg_set $name
2165 echo "$subpkgname-$pkgver-r$pkgrel.apk"
2166 done
2167 subpkg_unset
2168}
2169
2170source_has() {
2171 local i
2172 for i in $source; do
2173 [ "$1" = "${i##*/}" ] && return 0
2174 [ "$1" = "${i%%::*}" ] && return 0
2175 done
2176 return 1
2177}
2178
2179subpackages_has() {
2180 local i
2181 for i in $subpackages; do
2182 [ "$1" = "${i%%:*}" ] && return 0
2183 done
2184 return 1
2185}
2186
2187subpackage_types_has() {
2188 local i
2189 for i in $subpackages; do
2190 local _name="${i%%:*}"
2191 [ "$1" = "${_name##*-}" ] && return 0
2192 done
2193 return 1
2194}
2195
2196list_has() {
2197 local needle="$1"
2198 local i
2199 shift
2200 for i in $@; do
2201 [ "$needle" = "$i" ] && return 0
2202 [ "$needle" = "!$i" ] && return 1
2203 done
2204 return 1
2205}
2206
2207# same as list_has but we filter version info
2208deplist_has() {
2209 local needle="$1"
2210 local i
2211 shift
2212 for i in $@; do
2213 i=${i%%[<>=]*}
2214 [ "$needle" = "$i" ] && return 0
2215 [ "$needle" = "!$i" ] && return 1
2216 done
2217 return 1
2218}
2219
2220options_has() {
2221 list_has "$1" $options
2222}
2223
2224depends_has() {
2225 deplist_has "$1" $depends
2226}
2227
2228makedepends_has() {
2229 deplist_has "$1" $makedepends
2230}
2231
2232md5sums_has() {
2233 list_has "$1" $md5sums
2234}
2235
2236install_has() {
2237 list_has "$1" $install
2238}
2239
2240deps() {
2241 [ -z "$hostdeps" -a -z "$builddeps" ] && calcdeps
2242
2243 local _quiet="$1"
2244 [ -z "$_quiet" ] && msg "Installing for build:$builddeps"
2245 $SUDO_APK add $_quiet $apk_opt_wait --repository "$REPODEST/$repo" \
2246 --virtual .makedepends-$pkgname \
2247 $builddeps \
2248 || return 1
2249 if [ -n "$CBUILDROOT" ]; then
2250 [ -z "$_quiet" ] && msg "Installing for host:$hostdeps"
2251 $SUDO_APK add $_quiet --root "$CBUILDROOT" --arch "$CTARGET_ARCH" --repository "$REPODEST/$repo" $apk_opt_wait \
2252 --no-scripts --virtual .makedepends-$pkgname $hostdeps || return 1
2253 fi
2254}
2255
2256undeps() {
2257 local _quiet="$@"
2258 $SUDO_APK del $_quiet $apk_opt_wait .makedepends-$pkgname || :
2259 if [ -n "$CBUILDROOT" ]; then
2260 $SUDO_APK del $_quiet --root "$CBUILDROOT" --arch "$CTARGET_ARCH" $apk_opt_wait \
2261 --no-scripts .makedepends-$pkgname || :
2262 fi
2263}
2264
2265# compat
2266installdeps() { deps; }
2267uninstalldeps() { undeps; }
2268index() { update_abuildrepo_index; }
2269
2270all() {
2271 if ! [ -n "$force" ]; then
2272 if ! check_arch; then
2273 echo "Package not available for the target architecture ($CARCH). Aborting."
2274 return 0
2275 fi
2276 check_libc || return 0
2277 fi
2278 if up2date && [ -z "$force" ]; then
2279 msg "Package is up to date"
2280 else
2281 build_abuildrepo
2282 fi
2283}
2284
2285# This abuild hook will checkout an svn or git repository by specifying
2286# $svnurl or $giturl in APKBUILD. You can checkout a specific branch in
2287# git by adding -b $branch in $giturl. $reporev will select the correct
2288# commit, revision or tag for you. If you specify $disturl your distfile
2289# will automatically be uploaded with rsync to the url provided.
2290# Base version defaults to 0 except if specified by $verbase.
2291
2292snapshot() {
2293 # check if we setup vars correctly
2294 [ -z "$disturl" ] && warning "Missing disturl in APKBUILD, auto uploading disabled."
2295 [ -z "$svnurl" ] && [ -z "$giturl" ] && die "Missding repository url in APKBUILD!"
2296 [ -n "$svnurl" ] && [ -n "$giturl" ] && die "You can only use a single repository!"
2297 local _date=$(date +%Y%m%d)
2298 local _format="tar.gz"
2299 # remove any repositories left in srcdir
2300 abuild clean
2301 mkdir -p "$srcdir" && cd "$srcdir"
2302 # clone git repo and archive
2303 if [ -n "$giturl" ]; then
2304 local _version=${verbase:-0}_git${_date}
2305 command -v git >/dev/null || \
2306 die "Missing git! Install git to support git clone."
2307 local _rev="${reporev:-HEAD}"
2308 [ "$_rev" = "HEAD" ] && local _depth="--depth=1"
2309 msg "Creating git snapshot: $pkgname-$_version"
2310 git clone $_depth --bare $giturl $pkgname-$_version || return 1
2311 git --git-dir $pkgname-$_version archive \
2312 --format=$_format \
2313 -o $pkgname-$_version.$_format \
2314 --prefix=$pkgname-$_version/ $_rev \
2315 || return 1
2316 fi
2317 # export svn repo and archive
2318 if [ -n "$svnurl" ]; then
2319 local _version=${verbase:-0}_svn${_date}
2320 command -v svn >/dev/null || \
2321 die "Missing svn! Install subverion to support svn export."
2322 [ -n "$reporev" ] && local _rev="-r $reporev"
2323 msg "Creating svn snapshot: $pkgname-$_version"
2324 svn co $_rev $svnurl $pkgname-$_version || return 1
2325 tar zcf $pkgname-$_version.$_format $pkgname-$_version || return 1
2326 fi
2327 # upload to defined distfiles url
2328 if [ -n "$disturl" ]; then
2329 command -v rsync >/dev/null || \
2330 die "Missing rsync! Install rsync to enable automatic uploads."
2331 msg "Uploading to $disturl"
2332 rsync --progress -La $pkgname-$_version.$_format \
2333 $disturl || return 1
2334 cd "$startdir"
2335 # set the pkgver to current date and update checksum
2336 sed -i -e "s/^pkgver=.*/pkgver=${_version}/" \
2337 APKBUILD || return 1
2338 abuild checksum
2339 fi
2340}
2341
2342usage() {
2343 cat <<-EOF
2344 usage: $program [options] [-P REPODEST] [-s SRCDEST] [-D DESCRIPTION] [cmd] ...
2345 $program [-c] -n PKGNAME[-PKGVER]
2346 Options:
2347 -A Print CARCH and exit
2348 -c Enable colored output
2349 -d Disable dependency checking
2350 -D Set APKINDEX description (default: \$repo \$(git describe))
2351 -f Force specified cmd, even if they are already done
2352 -F Force run as root
2353 -h Show this help
2354 -i Install PKG after successful build
2355 -k Keep built packages, even if APKBUILD or sources are newer
2356 -K Keep buildtime temp dirs and files (srcdir/pkgdir/deps)
2357 -m Disable colors (monochrome)
2358 -P Set REPODEST as the repository location for created packages
2359 -q Quiet
2360 -r Install missing dependencies from system repository (using sudo)
2361 -R Recursively build and install missing dependencies (using sudo)
2362 -s Set source package destination directory
2363 -u Recursively build and upgrade all dependencies (using sudo)
2364 -v Verbose: show every command as it is run (very noisy)
2365
2366 Commands:
2367 build Compile and install package into \$pkgdir
2368 check Run any defined tests concerning the package
2369 checksum Generate checksum to be included in APKBUILD
2370 clean Remove temp build and install dirs
2371 cleancache Remove downloaded files from \$SRCDEST
2372 cleanoldpkg Remove binary packages except current version
2373 cleanpkg Remove already built binary and source package
2374 deps Install packages listed in makedepends and depends
2375 fetch Fetch sources to \$SRCDEST and verify checksums
2376 index Regenerate indexes in \$REPODEST
2377 listpkg List target packages
2378 package Create package in \$REPODEST
2379 prepare Apply patches
2380 rootbld Build package in clean chroot
2381 rootpkg Run 'package', the split functions and create apks as fakeroot
2382 sanitycheck Basic sanity check of APKBUILD
2383 snapshot Create a \$giturl or \$svnurl snapshot and upload to \$disturl
2384 sourcecheck Check if remote source package exists upstream
2385 srcpkg Make a source package
2386 undeps Uninstall packages listed in makedepends and depends
2387 unpack Unpack sources to \$srcdir
2388 up2date Compare target and sources dates
2389 verify Verify checksums
2390
2391 To activate cross compilation specify in environment:
2392 CHOST Arch or hostspec of machine to generate packages for
2393 CTARGET Arch or hostspec of machine to generate compiler for
2394
2395 EOF
2396 exit 0
2397}
2398
2399APKBUILD="${APKBUILD:-./APKBUILD}"
2400unset force
2401unset recursive
2402while getopts "AcdD:fFhkKimnp:P:qrRs:uv" opt; do
2403 case $opt in
2404 'A') echo "$CARCH"; exit 0;;
2405 'c') enable_colors
2406 color_opt="-c";;
2407 'd') nodeps="-d";;
2408 'D') DESCRIPTION=$OPTARG;;
2409 'f') force="-f";;
2410 'F') forceroot="-F";;
2411 'h') usage;;
2412 'k') keep="-k";;
2413 'K') keep_build="-K";;
2414 'm') disable_colors
2415 color_opt="-m";;
2416 'n') die "Use newapkbuild to create new aports";;
2417 'P') REPODEST=$OPTARG;;
2418 'q') quiet="-q";;
2419 'r') install_deps="-r";;
2420 'R') recursive="-R";;
2421 's') SRCDEST=$OPTARG;;
2422 'u') upgrade="-u"
2423 recursive="-R";;
2424 'v') set -x;;
2425 esac
2426done
2427shift $(( $OPTIND - 1 ))
2428
2429# check so we are not root
2430if [ $(id -u) -eq 0 ] && [ -z "$FAKEROOTKEY" ]; then
2431 [ -z "$forceroot" ] && die "Do not run abuild as root"
2432 FAKEROOT=
2433fi
2434
2435# find startdir
2436[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
2437APKBUILD=$(readlink -f "$APKBUILD")
2438
2439startdir="${APKBUILD%/*}"
2440srcdir=${srcdir:-"$startdir/src"}
2441pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
2442
2443repo=${startdir%/*}
2444repo=${repo##*/}
2445
2446SRCDEST=${SRCDEST:-$startdir}
2447
2448BUILD_ROOT=
2449
2450# set a default CC
2451: ${CC:=gcc}
2452export CC
2453
2454cd "$startdir" || die
2455. "$APKBUILD"
2456
2457builddir=${builddir:-"$srcdir/$pkgname-$pkgver"}
2458
2459# If REPODEST is set then it will override the PKGDEST
2460if [ -z "$REPODEST" ]; then
2461 warning "REPODEST is not set and is now required. Defaulting to ~/packages"
2462 [ -n "$PKGDEST" ] && die "PKGDEST is no longer supported."
2463 REPODEST="~/packages"
2464fi
2465
2466# for recursive action
2467export REPODEST SRCDEST
2468
2469# add dbg subpackage if its enabled globally
2470if [ -n "$DEFAULT_DBG" ] && ! subpackage_types_has "dbg" && ! options_has "!dbg" && [ "$arch" != "noarch" ]; then
2471 subpackages="$pkgname-dbg $subpackages"
2472fi
2473
2474# if we want build debug package
2475if [ -n "$DEBUG" ] || subpackage_types_has "dbg"; then
2476 CFLAGS="$CFLAGS -g"
2477 CXXFLAGS="$CXXFLAGS -g"
2478 options="$options !strip"
2479fi
2480
2481if [ -n "$subpkgname" ]; then
2482 # If we are handling a sub package then reset subpackages and install
2483 origsubpackages="$subpackages"
2484 subpackages=
2485else
2486 allpackages="$pkgname $subpackages"
2487 for i in $linguas; do
2488 allpackages="$allpackages $pkgname-lang-$i::noarch"
2489 done
2490fi
2491apkbuild_arch="$arch"
2492pkgdir="$pkgbasedir/$pkgname"
2493if [ -z "$pkgarch" ]; then
2494 pkgarch=$CARCH
2495 list_has noarch $arch && pkgarch=noarch
2496fi
2497controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
2498
2499trap 'die "Aborted by user"' INT
2500
2501[ -z "$subpkgdir" ] && set_xterm_title "abuild${CROSS_COMPILE+-$CARCH}: $pkgname"
2502
2503if [ -z "$1" ]; then
2504 set all
2505fi
2506
2507while [ $# -gt 0 ]; do
2508 runpart $1
2509 shift
2510done
2511
2512cleanup