projects/aports·blob v3.3.0_pre2 · refs

2612 lines · 64.4 KiB

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