projects/aports·blob v2.17.0 · refs

2030 lines · 49.3 KiB

1#!/bin/sh
2
3# abuild - build apk packages (light version of makepkg)
4# Copyright (c) 2008 Natanael Copa <[email protected]>
5#
6# Distributed under GPL-2
7#
8
9abuild_ver=@VERSION@
10sysconfdir=@sysconfdir@
11abuildrepo_base=@abuildrepo@
12datadir=@datadir@
13
14program=${0##*/}
15abuild_path=$(readlink -f $0)
16
17# defaults
18BUILD_BASE="build-base"
19FAKEROOT=${FAKEROOT:-"fakeroot"}
20
21: ${SUDO_APK:=abuild-apk}
22: ${APK:=apk}
23: ${ADDUSER:=abuild-adduser}
24: ${ADDGROUP:=abuild-addgroup}
25
26apk_opt_wait="--wait 30"
27
28# read config
29ABUILD_CONF=${ABUILD_CONF:-"$sysconfdir/abuild.conf"}
30[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"
31
32default_colors() {
33 NORMAL="\033[1;0m"
34 STRONG="\033[1;1m"
35 RED="\033[1;31m"
36 GREEN="\033[1;32m"
37 YELLOW="\033[1;33m"
38 BLUE="\033[1;34m"
39}
40
41monochrome() {
42 NORMAL=""
43 STRONG=""
44 RED=""
45 GREEN=""
46 YELLOW=""
47 BLUE=""
48}
49
50#colors
51if [ -n "$USE_COLORS" ]; then
52 default_colors
53fi
54
55# run optional log command for remote logging
56logcmd() {
57 ${ABUILD_LOG_CMD:-true} "$@"
58 return 0
59}
60
61# functions
62msg() {
63 [ -n "$quiet" ] && return 0
64 local prompt="$GREEN>>>${NORMAL}"
65 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
66 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
67 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
68}
69
70msg2() {
71 [ -n "$quiet" ] && return 0
72 # ">>> %s"
73 printf " %s\n" "$1" >&2
74}
75
76warning() {
77 local prompt="${YELLOW}>>> WARNING:${NORMAL}"
78 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
79 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
80 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
81}
82
83warning2() {
84 # ">>> WARNING:
85 printf " %s\n" "$1" >&2
86}
87
88error() {
89 local prompt="${RED}>>> ERROR:${NORMAL}"
90 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
91 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
92 printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
93 logcmd "ERROR: $pkgname: $1"
94}
95
96error2() {
97 # ">>> ERROR:
98 printf " %s\n" "$1" >&2
99}
100
101set_xterm_title() {
102 if [ "$TERM" = xterm ] && [ -n "$USE_COLORS" ]; then
103 printf "\033]0;$1\007" >&2
104 fi
105}
106
107cross_compiling() {
108 test "$CBUILD" != "$CHOST" -a -n "$CBUILDROOT"
109}
110
111cleanup() {
112 local i=
113 set_xterm_title ""
114 if [ -n "$CLEANUP_FILES" ]; then
115 rm -f $CLEANUP_FILES
116 fi
117 for i; do
118 case $i in
119 pkgdir) msg "Cleaning up pkgdir"; rm -rf "$pkgbasedir";;
120 srcdir) msg "Cleaning up srcdir"; rm -rf "$srcdir";;
121 deps)
122 if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
123 msg "Uninstalling dependencies..."
124 $SUDO_APK del --quiet $apk_opt_wait $uninstall_after
125 if cross_compiling; then
126 $SUDO_APK del --root "$CBUILDROOT" \
127 --quiet $apk_opt_wait \
128 $uninstall_after
129 fi
130 fi
131 ;;
132 esac
133 done
134}
135
136die() {
137 error "$@"
138 cleanup $ERROR_CLEANUP
139 exit 1
140}
141
142spell_error() {
143 die "APKBUILD contains '$1'. It should be '$2'"
144}
145
146# check if apkbuild is basicly sane
147default_sanitycheck() {
148 local i= j= suggestion=
149 msg "Checking sanity of $APKBUILD..."
150 [ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
151 [ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
152 [ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
153 if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
154 $APK version --check --quiet "$pkgver" ||\
155 die "$pkgver is not a valid version"
156 fi
157 [ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
158 [ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
159 [ -z "$url" ] && die "Missing url in APKBUILD"
160 [ -z "$license" ] && die "Missing license in APKBULID"
161 if [ $(echo "$pkgdesc" | wc -c) -gt 128 ]; then
162 die "pkgdesc is too long"
163 fi
164 is_function package || warning "Missing package() function in APKBUILD"
165
166 if [ -n "$replaces_priority" ] \
167 && ! echo $replaces_priority | egrep -q '^[0-9]+$'; then
168 die "replaces_priority must be a number"
169 fi
170 # check so no package names starts with -
171 for i in $pkgname $subpackages; do
172 case $i in
173 -*) die "${i%:*} is not a valid package name";;
174 esac
175 done
176
177 # check if CARCH, CBUILD, CHOST and CTARGET is set
178 [ -z "$CHOST" ] && die "Please set CHOST in /etc/abuild.conf"
179
180 if [ -z "$CARCH" ]; then
181 die "Please fix CHOST, or set CARCH in abuild.conf"
182 fi
183
184 for i in $install; do
185 local n=${i%.*}
186 local suff=${i##*.}
187 case "$suff" in
188 pre-install|post-install|pre-upgrade|post-upgrade|pre-deinstall|post-deinstall);;
189 *) die "$i: unknown install script suffix"
190 esac
191 if ! subpackages_has "$n" && [ "$n" != "$pkgname" ]; then
192 die "$i: install script does not match pkgname or any subpackage"
193 fi
194 [ -e "$startdir/$i" ] || die "install script $i is missing"
195 for j in chown chmod chgrp; do
196 if grep -q $j "$startdir"/$i; then
197 warning "$i: found $j"
198 warning2 "Permissions should be fixed in APKBUILD package()"
199 fi
200 done
201 done
202
203 for i in $triggers; do
204 local f=${i%=*}
205 local p=${f%.trigger}
206 [ "$f" = "$i" ] && die "$f: triggers must contain '='"
207 [ "$p" = "$f" ] && die "$f: triggers scripts must have .trigger suffix"
208 if ! subpackages_has "$p" && [ "$p" != "$pkgname" ]; then
209 die "$p: trigger script does not match pkgname or any subpackage"
210 fi
211
212 [ -e "$startdir"/$f ] || die "trigger script $f is missing"
213 done
214 if [ -n "$source" ]; then
215 for i in $source; do
216 if install_has "$i"; then
217 warning "You should not have \$install in source"
218 continue
219 fi
220 case "$i" in
221 *::*) i=${i%%::*};;
222 https://*) makedepends_has wget && warning "wget no longer need to be in makedepends when source has https://" ;;
223 esac
224 list_has ${i##*/} $md5sums $sha256sums $sha512sums \
225 || die "${i##*/} is missing in checksums"
226 done
227 fi
228
229 # verify that things listed in checksum also is listed in source
230 local algo=
231 for algo in md5 sha256 sha512; do
232 eval set -- \$${algo}sums
233 while [ $# -gt 1 ]; do
234 local file="$2"
235 shift 2
236 source_has $file || die "$file exists in ${algo}sums but is missing in source"
237 done
238 done
239
240 # common spelling errors
241 [ -n "$depend" ] && spell_error depend depends
242 [ -n "$makedepend" ] && spell_error makedepend makedepends
243 [ -n "$pkguser" ] && spell_error pkguser pkgusers
244 [ -n "$pkggroup" ] && spell_error pkggroup pkggroups
245 [ -n "$subpackage" ] && spell_error subpackage subpackages
246
247 grep '^# Maintainer:' $APKBUILD >/dev/null || warning "No maintainer"
248
249 makedepends_has 'g++' && warning "g++ should not be in makedepends"
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 echo "$src" | ${algo}sum -c
277 if [ $? -ne 0 ]; then
278 endreturnval=1
279 is_remote $origin || continue
280 echo "Because the remote file above failed the ${algo}sum check it will be deleted."
281 echo "Rebuilding will cause it to re-download which in some cases may fix the problem."
282 file=`echo "$src" | sed 's/.*[ \t\n]\(.*\)/\1/'`
283 echo "Deleting: $file"
284 rm $file
285 fi
286 done
287 unset IFS
288 return $endreturnval
289}
290
291# for compatibility
292md5check() {
293 warning "'md5check' is deprecated. Use 'verify' instead"
294 sumcheck md5 "$md5sums"
295}
296
297# verify checksums
298verify() {
299 local verified=false algo=
300 for algo in sha512 sha256 sha1 md5; do
301 local sums=
302 eval sums=\"\$${algo}sums\"
303 if [ -z "$sums" ] || [ -z "$source" ]; then
304 continue
305 fi
306 sumcheck "$algo" "$sums" || return 1
307 verified=true
308 break
309 done
310 if [ -n "$source" ] && ! $verified; then
311 die "Use 'abuild checksum' to generate/update the checksum(s)"
312 fi
313 return 0
314}
315
316# verify upstream sources
317sourcecheck() {
318 local uri
319 for uri in $source; do
320 is_remote $uri || continue
321 case "$uri" in
322 saveas-*://*)
323 uri=${uri#saveas-}
324 uri=${uri%/*}
325 ;;
326 *::*)
327 uri=${uri##*::}
328 ;;
329 esac
330 wget -q -s "$uri" || return 1
331 done
332 return 0
333}
334
335# convert curl options to wget options and call wget instead of curl
336wget_fallback() {
337 local wget_opts= outfile= opt=
338 while getopts "C:Lko:s" opt; do
339 case $opt in
340 'L') ;; # --location. wget does this by default
341 'f') ;; # --fail. wget does this by default
342 'C') wget_opts="$wget_opts -c";; # --continue-at
343 's') wget_opts="$wget_opts -q";; # --silent
344 'o') wget_opts="$wget_opts -O $OPTARG";; # --output
345 'k') wget_opts="$wget_opts --no-check-certificate";; #gnu wget
346 esac
347 done
348 shift $(( $OPTIND - 1 ))
349 wget $wget_opts "$1"
350}
351
352uri_fetch() {
353 local uri="$1"
354 local d="${uri##*/}" # $(basename $uri)
355 local opts
356 [ -n "$quiet" ] && opts="-s"
357
358 local lockfile="$SRCDEST/$d".lock
359
360 # fix saveas-*://* URIs
361 case "$uri" in
362 # remove 'saveas-' from beginning and
363 # '/filename' from end of URI
364 saveas-*://*) uri="${uri:7:$(expr ${#uri} - 7 - ${#d} - 1)}";;
365
366 *::*)
367 d=${uri%%::*}
368 uri=${uri#$d::}
369 ;;
370 esac
371
372 case "$uri" in
373 https://*) opts="-k";;
374 esac
375
376 mkdir -p "$SRCDEST"
377
378 CLEANUP_FILES="$CLEANUP_FILES $lockfile"
379 (
380 flock -n -x 9 || msg "Waiting for ${lockfile##*/}..."
381 flock -x 9
382
383 [ -f "$SRCDEST/$d" ] && exit 0 # use exit since its a subshell
384
385 if [ -f "$SRCDEST/$d.part" ]; then
386 msg "Partial download found. Trying to resume"
387 opts="$opts -C -"
388 fi
389 msg "Fetching $uri"
390
391 # fallback to wget if curl is missing. useful for bootstrapping
392 local fetcher=
393 if ! [ -x "$(which curl)" ]; then
394 fetcher=wget_fallback
395 else
396 fetcher=curl
397 opts="$opts -L -f -k"
398 fi
399
400 $fetcher $opts -o "$SRCDEST/$d.part" "$uri" \
401 && mv "$SRCDEST/$d.part" "$SRCDEST/$d"
402
403 ) 9>$lockfile
404
405 local rc=$?
406 rm -f "$lockfile"
407 return $rc
408}
409
410is_remote() {
411 case "${1#*::}" in
412 http://*|ftp://*|https://*|saveas-*://*)
413 return 0;;
414 esac
415 return 1
416}
417
418filename_from_uri() {
419 local uri="$1"
420 local filename="${uri##*/}" # $(basename $uri)
421 case "$uri" in
422 *::*) filename=${uri%%::*};;
423 esac
424 echo "$filename"
425}
426
427# try download from file from mirror first
428uri_fetch_mirror() {
429 local uri="$1"
430 if [ -n "$DISTFILES_MIRROR" ]; then
431 if is_remote "$DISTFILES_MIRROR"; then
432 uri_fetch "$DISTFILES_MIRROR"/$(filename_from_uri $uri)\
433 && return 0
434 else
435 cp "$DISTFILES_MIRROR"/$(filename_from_uri $uri) \
436 "$SRCDEST" && return 0
437 fi
438 fi
439 uri_fetch "$uri"
440}
441
442default_fetch() {
443 local s
444 mkdir -p "$srcdir"
445 for s in $source; do
446 if is_remote "$s"; then
447 uri_fetch_mirror "$s" || return 1
448 ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
449 else
450 ln -sf "$startdir/$s" "$srcdir/"
451 fi
452 done
453}
454
455fetch() {
456 default_fetch
457}
458
459# verify that all init.d scripts are openrc runscripts
460initdcheck() {
461 local i
462 for i in $source; do
463 case $i in
464 *.initd)
465 head -n 1 "$srcdir"/$i | grep -q '/sbin/runscript' \
466 && continue
467 error "$i is not an openrc #!/sbin/runscript"
468 return 1
469 ;;
470 esac
471 done
472}
473
474# unpack the sources
475default_unpack() {
476 local u
477 if [ -z "$force" ]; then
478 verify || return 1
479 initdcheck || return 1
480 fi
481 mkdir -p "$srcdir"
482 for u in $source; do
483 local s="$SRCDEST/$(filename_from_uri $u)"
484 case "$s" in
485 *.tar)
486 msg "Unpacking $s..."
487 tar -C "$srcdir" -xf "$s" || return 1;;
488 *.tar.gz|*.tgz)
489 msg "Unpacking $s..."
490 tar -C "$srcdir" -zxf "$s" || return 1;;
491 *.tar.bz2)
492 msg "Unpacking $s..."
493 tar -C "$srcdir" -jxf "$s" || return 1;;
494 *.tar.lzma)
495 msg "Unpacking $s..."
496 unlzma -c "$s" | tar -C "$srcdir" -x \
497 || return 1;;
498 *.tar.xz)
499 msg "Unpacking $s..."
500 unxz -c "$s" | tar -C "$srcdir" -x || return 1;;
501 *.zip)
502 msg "Unpacking $s..."
503 unzip "$s" -d "$srcdir" || return 1;;
504 esac
505 done
506}
507
508unpack() {
509 default_unpack
510}
511
512# cleanup source and package dir
513clean() {
514 msg "Cleaning temporary build dirs..."
515 rm -rf "$srcdir"
516 rm -rf "$pkgbasedir"
517}
518
519# cleanup fetched sources
520cleancache() {
521 local s
522 for s in $source; do
523 if is_remote "$s"; then
524 s=$(filename_from_uri $s)
525 msg "Cleaning downloaded $s ..."
526 rm -f "$SRCDEST/$s"
527 fi
528 done
529}
530
531listpkgnames() {
532 local i
533 for i in $pkgname $subpackages; do
534 echo ${i%:*}
535 done
536 for i in $linguas; do
537 echo $pkgname-lang-$i
538 done
539}
540
541cleanpkg() {
542 local i
543 getpkgver || return 1
544 msg "Cleaning built packages..."
545 for i in $(listpkgnames); do
546 local p="${i%:*}-$pkgver-r$pkgrel"
547 rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
548 "$abuildrepo"/$p.apk "$abuildrepo"/*/$p.apk
549 done
550 # remove given packages from index
551 update_abuildrepo_index
552}
553
554# clean all packages except current
555cleanoldpkg() {
556 local i j
557 getpkgver || return 1
558 msg "Cleaning all packages except $pkgver-r$pkgrel..."
559 for i in $(listpkgnames); do
560 local pn=${i%:*}
561 for j in "$PKGDEST"/$pn-[0-9]*.apk ; do
562 [ "$j" = "$PKGDEST/$pn-$pkgver-r$pkgrel.apk" ] \
563 && continue
564 rm -f "$j" "$abuildrepo"/*/${j##*/}
565 done
566 done
567 return 0
568}
569
570mkusers() {
571 local i
572 for i in $pkggroups; do
573 if ! getent group $i >/dev/null; then
574 msg "Creating group $i"
575 $ADDGROUP -S $i || return 1
576 fi
577 done
578 for i in $pkgusers; do
579 if ! getent passwd $i >/dev/null; then
580 local gopt=
581 msg "Creating user $i"
582 if getent group $i >/dev/null; then
583 gopt="-G $i"
584 fi
585 $ADDUSER -S -D -H $gopt $i || return 1
586 fi
587 done
588}
589
590# helper to update config.sub to a recent version
591update_config_sub() {
592 local changed=false
593 find . -name config.sub | while read f; do
594 if ! ./$f armv6-alpine-linux-muslgnueabihf 2>/dev/null; then
595 msg "Updating $f"
596 cp "$datadir"/${f##*/} "$f" || return 1
597 changed=true
598 else
599 msg "Not new enough $f"
600 fi
601 # pipe subshell will return status of last command
602 $changed
603 done
604 return $?
605}
606
607runpart() {
608 local part=$1
609 [ -n "$DEBUG" ] && msg "$part"
610 $part || die "$part failed"
611}
612
613# override those in your build script
614getpkgver() {
615 # this func is supposed to be overridden by volatile packages
616 if [ "$pkgver" = "volatile" ]; then
617 error "Please provide a getpkgver() function in your APKBUILD"
618 return 1
619 fi
620}
621
622prepare() {
623 :
624}
625
626build() {
627 :
628}
629
630# generate a simple tar.gz package of pkgdir
631targz() {
632 cd "$pkgdir" || return 1
633 mkdir -p "$PKGDEST"
634 tar -czf "$PKGDEST"/$pkgname-$pkgver-r$pkgrel.tar.gz *
635}
636
637get_split_func() {
638 # get the 'func' from "sub-pkg:func"
639 local func=${1##*:}
640
641 # get 'func' from "sub-pkg-func" if there was no :func
642 [ "$func" = "$1" ] && func=${func##*-}
643 echo $func
644}
645
646postcheck() {
647 local dir="$1" name="$2" i=
648 msg "Running postcheck for $name"
649 # checking for FHS compat
650 if ! options_has "!fhs"; then
651 for i in "$dir"/srv/* "$dir"/usr/local/* "$dir"/opt/*; do
652 if [ -e "$i" ]; then
653 error "Packages must not put anything under /srv, /usr/local or /opt"
654 return 1
655 fi
656 done
657 if [ -d "$dir"/usr/var ]; then
658 error "Found /usr/var, localstatedir is most likely wrong"
659 return 1
660 fi
661 fi
662 # look for *.la files
663 i=$(find "$dir" -name '*.la' | sed "s|^$dir|\t|")
664 if [ -n "$i" ] && ! options_has "libtool"; then
665 error "Libtool archives (*.la) files found and \$options has no 'libtool' flag:"
666 echo "$i"
667 return 1
668 fi
669 # look for /usr/lib/charset.alias
670 if [ -e "$dir"/usr/lib/charset.alias ] \
671 && ! options_has "charset.alias"; then
672 error "Found /usr/lib/charset.alias"
673 return 1
674 fi
675 # check directory permissions
676 i=$(find "$dir" -type d -perm -777 | sed "s|^$dir|\t|")
677 if [ -n "$i" ]; then
678 warning "World writeable directories found:"
679 echo "$i"
680 fi
681 # check so we dont have any suid root binaries that are not
682 i=$(find "$dir" -type f -perm +6000 \
683 | xargs scanelf --nobanner --etype ET_EXEC \
684 | sed "s|ET_EXEC $dir|\t|")
685 if [ -n "$i" ]; then
686 error "Found non-PIE files that has SUID:"
687 echo "$i"
688 return 1
689 fi
690 # test for textrels
691 if ! options_has "textrels"; then
692 local res="$(scanelf --recursive --textrel --quiet "$dir")"
693 if [ -n "$res" ]; then
694 error "Found textrels:"
695 echo "$res"
696 return 1
697 fi
698 fi
699 return 0
700}
701
702prepare_subpackages() {
703 local i
704 cd "$startdir"
705 for i in $subpackages; do
706 local func=$(get_split_func $i)
707 # call abuild recursively, setting subpkg{dir,name}
708 msg "Running split function $func..."
709 local dir="$pkgbasedir/${i%:*}" name="${i%:*}"
710 ( subpkgdir="$dir" subpkgname="$name" \
711 $0 $func prepare_package \
712 && postcheck "$dir" "$name" ) || return 1
713 done
714 postcheck "$pkgdir" "$pkgname" || return 1
715 # post check for /usr/share/locale
716 if [ -d "$pkgdir"/usr/share/locale ]; then
717 warning "Found /usr/share/locale"
718 warning2 "Maybe add \$pkgname-lang to subpackages?"
719 fi
720}
721
722default_lang() {
723 pkgdesc="Languages for package $pkgname"
724 install_if="$pkgname=$pkgver-r$pkgrel lang"
725 arch="noarch"
726 local dir
727 for dir in ${langdir:-/usr/share/locale}; do
728 mkdir -p "$subpkgdir"/${dir%/*}
729 mv "$pkgdir"/"$dir" "$subpkgdir"/"$dir" || return 1
730 done
731}
732
733lang() {
734 default_lang
735}
736
737default_lang_subpkg() {
738 if [ -z "$lang" ]; then
739 error "lang is not set"
740 return 1
741 fi
742 pkgdesc="$pkgname language pack for $lang"
743 arch="noarch"
744 install_if="$pkgname=$pkgver-r$pkgrel lang-$lang"
745 local dir
746 for dir in ${langdir:-/usr/share/locale}; do
747 mkdir -p "$subpkgdir"/$dir
748 mv "$pkgdir"/$dir/$lang* \
749 "$subpkgdir"/$dir/ \
750 || return 1
751 done
752}
753
754lang_subpkg() {
755 default_lang_subpkg
756}
757
758prepare_language_packs() {
759 for lang in $linguas; do
760 lang="$lang" \
761 subpkgname="$pkgname-lang-$lang" \
762 subpkgdir="$pkgbasedir"/$subpkgname \
763 $0 lang_subpkg prepare_package || return 1
764 done
765}
766
767# echo '-dirty' if git is not clean
768git_dirty() {
769 if [ $(git status -s "$startdir" | wc -l) -ne 0 ]; then
770 echo "-dirty"
771 fi
772}
773
774# echo last commit hash id
775git_last_commit() {
776 git log --format=oneline -n 1 "$startdir" | awk '{print $1}'
777}
778
779get_maintainer() {
780 if [ -z "$maintainer" ]; then
781 maintainer=$(awk -F': ' '/\# *Maintainer/ {print $2}' "$APKBUILD")
782 fi
783}
784
785prepare_metafiles() {
786 getpkgver || return 1
787 local name=${subpkgname:-$pkgname}
788 [ -z "${name##* *}" ] && die "package name contains spaces"
789 local dir=${subpkgdir:-$pkgdir}
790 local pkg="$name-$pkgver-r$pkgrel.apk"
791 local pkginfo="$controldir"/.PKGINFO
792 local sub
793
794 [ ! -d "$dir" ] && die "Missing $dir"
795 cd "$dir"
796 mkdir -p "$controldir"
797 local builddate=$(date -u "+%s")
798 local size=$(du -sk | awk '{print $1 * 1024}')
799 local parch="$CARCH"
800
801 # we need to wait with setting noarch til our build infra can handle it
802# if [ "$arch" = "noarch" ]; then
803# parch="noarch"
804# fi
805
806 echo "# Generated by $(basename $0) $abuild_ver" >"$pkginfo"
807 if [ -n "$FAKEROOTKEY" ]; then
808 echo "# using $($FAKEROOT -v)" >> "$pkginfo"
809 fi
810 echo "# $(date -u)" >> "$pkginfo"
811 cat >> "$pkginfo" <<EOF
812pkgname = $name
813pkgver = $pkgver-r$pkgrel
814pkgdesc = $pkgdesc
815url = $url
816builddate = $builddate
817packager = ${PACKAGER:-"Unknown"}
818size = $size
819arch = $parch
820origin = $pkgname
821EOF
822 local i deps
823 deps="$depends"
824 if [ "$pkgname" != "busybox" ] && ! depends_has busbox; then
825 for i in $install $triggers; do
826 local s=${i%=*}
827 [ "$name" != "${s%.*}" ] && continue
828 if head -n 1 "$startdir/$s" | grep '^#!/bin/sh' >/dev/null ; then
829 msg "Script found. busybox added as a dependency for $pkg"
830 deps="$deps busybox"
831 break
832 fi
833 done
834 fi
835
836 # store last_commit in global var so we only call git once
837 if [ -z "$last_commit" ]; then
838 last_commit="$(git_last_commit)$(git_dirty)"
839 fi
840 echo "commit = $last_commit" >> "$pkginfo"
841
842 get_maintainer
843 if [ -n "$maintainer" ]; then
844 echo "maintainer = $maintainer" >> "$pkginfo"
845 fi
846
847 if [ -n "$replaces_priority" ]; then
848 echo "replaces_priority = $replaces_priority" >> "$pkginfo"
849 fi
850
851 for i in $license; do
852 echo "license = $i" >> "$pkginfo"
853 done
854 for i in $replaces; do
855 echo "replaces = $i" >> "$pkginfo"
856 done
857 for i in $deps; do
858 echo "depend = $i" >> "$pkginfo"
859 done
860 for i in $conflicts; do
861 echo "conflict = $i" >> "$pkginfo"
862 done
863 for i in $provides; do
864 echo "provides = $i" >> "$pkginfo"
865 done
866 for i in $triggers; do
867 local f=${i%=*}
868 local dirs=${i#*=}
869 [ "${f%.trigger}" != "$name" ] && continue
870 echo "triggers = ${dirs//:/ }" >> "$pkginfo"
871 done
872 if [ -n "$install_if" ]; then
873 echo "install_if = $(echo $install_if)" >> "$pkginfo"
874 fi
875
876 local metafiles=".PKGINFO"
877 for i in $install $triggers; do
878 local f=${i%=*}
879 local n=${f%.*}
880 if [ "$n" != "$name" ]; then
881 continue
882 fi
883 script=${f#$name}
884 msg "Adding $script"
885 cp "$startdir/$f" "$controldir/$script" || return 1
886 chmod +x "$controldir/$script"
887 metafiles="$metafiles $script"
888 done
889 echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
890}
891
892prepare_tracedeps() {
893 local dir=${subpkgdir:-$pkgdir}
894 local etype= soname= file= sover=
895 [ "$arch" = "noarch" ] && return 0
896 options_has "!tracedeps" && return 0
897 # lets tell all the places we should look for .so files - all rpaths
898 scanelf --quiet --recursive --rpath "$dir" \
899 | sed -e 's/[[:space:]].*//' -e 's/:/\n/' | sort -u \
900 >"$controldir"/.rpaths
901 if grep -q -x '/usr/lib' "$controldir"/.rpaths; then
902 warning "Redundat /usr/lib in rpath found"
903 fi
904 if grep '^/home/' "$controldir"/.rpaths; then
905 error "Has /home/... in rpath"
906 return 1
907 fi
908}
909
910# check if dir has arch specific binaries
911dir_has_arch_binaries() {
912 local dir="$1"
913 # if scanelf returns something, then we have binaries
914 [ -n "$(scanelf -R "$dir" | head -n 1)" ] && return 0
915
916 # look for static *.a
917 [ -n "$(find "$dir" -type f -name '*.a' | head -n 1)" ] && return 0
918
919 return 1
920}
921
922# returns true if this is the -dev package
923is_dev_pkg() {
924 test "${subpkgname%-dev}" != "$subpkgname"
925}
926
927# check that noarch is set if needed
928archcheck() {
929 options_has "!archcheck" && return 0
930 if dir_has_arch_binaries "${subpkgdir:-$pkgdir}"; then
931 [ "$arch" != "noarch" ] && return 0
932 error "Arch specific binaries found so arch must not be set to \"noarch\""
933 return 1
934 elif [ "$arch" != "noarch" ] && ! is_dev_pkg; then
935 # we dont want -dev package go to noarch
936 warning "No arch specific binaries found so arch should probably be set to \"noarch\""
937 fi
938 return 0
939}
940
941prepare_package() {
942 msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
943 stripbin
944 prepare_metafiles && prepare_tracedeps || return 1
945 archcheck
946}
947
948pkginfo_val() {
949 local key="$1"
950 local file="$2"
951 awk -F ' = ' "\$1 == \"$key\" {print \$2}" "$file"
952}
953
954# find real path to so files
955real_so_path() {
956 local so="$1"
957 shift
958 while [ $# -gt 0 ]; do
959 [ -e "$1"/$so ] && realpath "$1/$so" && return 0
960 shift
961 done
962 error "$so: path not found"
963 return 1
964}
965
966# search rpaths and /usr/lib /lib for given so files
967find_so_files() {
968 local rpaths=$(cat "$1")
969 shift
970 while [ $# -gt 0 ]; do
971 real_so_path "$1" /usr/lib /lib $rpaths || return 1
972 shift
973 done
974 return 0
975}
976
977subpkg_provides() {
978 grep -q -w "^$1" "$pkgbasedir"/.control.*/.provides-so 2>/dev/null
979}
980
981trace_apk_deps() {
982 local name="$1"
983 local dir="$2"
984 local i= found= autodeps= deppkgs= missing=
985 msg "Tracing dependencies..."
986 # add pkgconfig if usr/lib/pkgconfig is found
987 if [ -d "$pkgbasedir"/$name/usr/lib/pkgconfig ] \
988 && ! grep -q '^depend = pkgconfig' "$dir"/.PKGINFO; then
989 msg " added pkgconfig (found /usr/lib/pkgconfig)"
990 autodeps="$autodeps pkgconfig"
991 fi
992
993 # special case for libpthread: we need depend on libgcc
994 if [ -f "$dir"/.needs-so ] && grep -q -w '^libpthread.so.*' "$dir"/.needs-so \
995 && ! grep -q -w "^depend = libgcc" "$dir"/.PKGINFO; then
996 autodeps="$autodeps libgcc"
997 msg " added libgcc (due to libpthread)"
998 fi
999 [ -f "$dir"/.needs-so ] && for i in $(cat "$dir"/.needs-so); do
1000 # first check if its provided by same apkbuild
1001 grep -q -w "^$i" "$dir"/.provides-so 2>/dev/null && continue
1002
1003 if subpkg_provides "$i" || cross_compiling \
1004 || $APK info --quiet --installed "so:$i"; then
1005 autodeps="$autodeps so:$i"
1006 else
1007 missing="$missing $i"
1008 fi
1009 done
1010
1011 # find all packages that holds the so files
1012 if [ -f "$dir"/.rpaths ]; then
1013 local so_files=$(find_so_files "$dir"/.rpaths $missing) \
1014 || return 1
1015 deppkgs=$($APK info --quiet --who-owns $so_files) || return 1
1016 fi
1017
1018 for found in $deppkgs; do
1019 if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
1020 warning "You can remove '$found' from depends"
1021 continue
1022 fi
1023 autodeps="$autodeps $found"
1024 done
1025
1026 echo "# automatically detected:" >> "$dir"/.PKGINFO
1027 if [ -f "$dir"/.provides-so ]; then
1028 sed 's/^\(.*\) \([0-9].*\)/provides = so:\1=\2/' "$dir"/.provides-so \
1029 >> "$dir"/.PKGINFO
1030 fi
1031 [ -z "$autodeps" ] && return 0
1032 for i in $autodeps; do
1033 echo "depend = $i"
1034 done | sort -u >> "$dir"/.PKGINFO
1035 # display all depends
1036 sed -n '/^depend =/s/depend = /\t/p' "$dir"/.PKGINFO >&2
1037}
1038
1039find_scanelf_paths() {
1040 local datadir="$1"
1041 local paths="$datadir/lib:$datadir/usr/lib" i= rpaths=
1042 if [ -n "$ldpath" ]; then
1043 paths="$paths:$(echo "${datadir}${ldpath}" | sed "s|:|:$datadir|g")"
1044 fi
1045 # search in all rpaths
1046 for rpaths in "$pkgbasedir"/.control.*/.rpaths; do
1047 [ -f "$rpaths" ] || continue
1048 while read i; do
1049 local dir="${datadir}${i}"
1050 IFS=:
1051 if [ -d "$dir" ] && ! list_has "$dir" $paths; then
1052 paths="$paths:${dir}"
1053 fi
1054 unset IFS
1055 done < "$rpaths"
1056 done
1057 echo "$paths"
1058}
1059
1060scan_shared_objects() {
1061 local name="$1" controldir="$2" datadir="$3"
1062 local opt= i=
1063
1064 # allow spaces in paths
1065 IFS=:
1066 set -- $(find_scanelf_paths "$datadir")
1067 unset IFS
1068
1069 # sanity check, verify that each path is prefixed with datadir
1070 for i; do
1071 if [ "${i#$datadir}" = "$i" ]; then
1072 error "Internal error in scanelf paths"
1073 return 1
1074 fi
1075 done
1076
1077 if options_has "ldpath-recursive"; then
1078 opt="--recursive"
1079 fi
1080 msg "Scanning shared objects"
1081 # lets tell all the .so files this package provides in .provides-so
1082 scanelf --nobanner --soname $opt "$@" | while read etype soname file; do
1083 # if soname field is missing, soname will be the filepath
1084 sover=0
1085 if [ -z "$file" ]; then
1086 file="$soname"
1087 soname=${soname##*/}
1088 fi
1089
1090 # we only want shared libs
1091 case $soname in
1092 *.so|*.so.[0-9]*|*.c32);;
1093 *) continue;;
1094 esac
1095
1096 case "$file" in
1097 *.so.[0-9]*) sover=${file##*.so.};;
1098 *.so)
1099 # filter out sonames with version when file does not
1100 # have version
1101 case "$soname" in
1102 *.so.[0-9]*)
1103 if options_has "sover-namecheck"; then
1104 continue
1105 fi
1106 esac
1107 ;;
1108 esac
1109 list_has "$soname" $somask && continue
1110 echo "$soname $sover"
1111 # use awk to filter out dupes that has sover = 0
1112 done | awk '{ if (so[$1] == 0) so[$1] = $2; }
1113 END { for (i in so) print(i " " so[i]); }' \
1114 | sort -u > "$controldir"/.provides-so
1115
1116 # verify that we dont have any duplicates
1117 local dupes="$(cut -d' ' -f1 "$controldir"/.provides-so | uniq -d)"
1118 if [ -n "$dupes" ]; then
1119 die "provides multiple versions of same shared object: $dupes"
1120 fi
1121
1122 # now find the so dependencies
1123 scanelf --nobanner --recursive --needed "$datadir" | tr ' ' ':' \
1124 | awk -F ":" '$1 == "ET_DYN" || $1 == "ET_EXEC" {print $2}' \
1125 | sed 's:,:\n:g' | sort -u \
1126 | while read soname; do
1127 # only add files that are not self provided
1128 grep -q -w "^$soname" "$controldir"/.provides-so \
1129 || list_has "$soname" $somask \
1130 || echo $soname
1131 done > "$controldir"/.needs-so
1132}
1133
1134# read size in bytes from stdin and show as human readable
1135human_size() {
1136 awk '{ split("B KB MB GB TB PB", type)
1137 for(i=5; y < 1; i--)
1138 y = $1 / (2**(10*i))
1139 printf("%.1f %s\n", y, type[i+2]) }'
1140}
1141
1142create_apks() {
1143 local file= dir= name= ver= apk= datadir= size=
1144 getpkgver || return 1
1145 mkdir -p "$PKGDEST"
1146 if [ "$arch" != "noarch" ] && ! options_has "!tracedeps"; then
1147 for file in "$pkgbasedir"/.control.*/.PKGINFO; do
1148 dir="${file%/.PKGINFO}"
1149 name="$(pkginfo_val pkgname $file)"
1150 datadir="$pkgbasedir"/$name
1151 subpkgname=$name
1152 scan_shared_objects "$name" "$dir" "$datadir"
1153 done
1154 fi
1155 for file in "$pkgbasedir"/.control.*/.PKGINFO; do
1156 dir="${file%/.PKGINFO}"
1157 name=$(pkginfo_val pkgname $file)
1158 ver=$(pkginfo_val pkgver $file)
1159 size=$(pkginfo_val size $file | human_size)
1160 apk=$name-$ver.apk
1161 datadir="$pkgbasedir"/$name
1162 subpkgname=$name
1163
1164 trace_apk_deps "$name" "$dir" || return 1
1165 msg "Package size: ${size}"
1166 msg "Compressing data..."
1167 (
1168 cd "$datadir"
1169 # data.tar.gz
1170 set -- *
1171 if [ "$1" = '*' ]; then
1172 touch .dummy
1173 set -- .dummy
1174 fi
1175 tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
1176
1177 msg "Create checksum..."
1178 # append the hash for data.tar.gz
1179 local sha256=$(sha256sum "$dir"/data.tar.gz | cut -f1 -d' ')
1180 echo "datahash = $sha256" >> "$dir"/.PKGINFO
1181
1182 # control.tar.gz
1183 cd "$dir"
1184 tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
1185 | gzip -9 > control.tar.gz
1186 abuild-sign -q control.tar.gz || exit 1
1187
1188 msg "Create $apk"
1189 # create the final apk
1190 cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
1191 )
1192 done
1193 subpkgname=
1194}
1195
1196clean_abuildrepo() {
1197 local apk
1198 cd "$abuildrepo" || return 1
1199
1200 # remove compat symlink
1201 for d in "$abuildrepo/$CARCH"; do
1202 [ -L "$d" ] && rm "$d"
1203 done
1204
1205 # remove broken links from abuildrepo
1206 for apk in *.apk */*.apk; do
1207 if [ -L "$apk" ] && [ ! -f "$apk" ]; then
1208 rm -f "$apk"
1209 fi
1210 done
1211}
1212
1213mklinks_abuildrepo() {
1214 [ -n "$REPODEST" ] && return 0
1215 local apk
1216 mkdir -p "$abuildrepo"/$CARCH
1217 cd "$abuildrepo" || return 1
1218 # create links for this package
1219 for apk in $(listpkg); do
1220 [ -f "$PKGDEST"/$apk ] || continue
1221 ln -sf "$PKGDEST"/$apk "$abuildrepo"/$CARCH/$apk
1222 done
1223}
1224
1225build_abuildrepo() {
1226 local d apk _build=build
1227 if ! is_function package; then
1228 # if package() is missing then build is called from rootpkg
1229 _build=true
1230 fi
1231 if ! apk_up2date || [ -n "$force" ]; then
1232 logcmd "building $pkgname"
1233 sanitycheck && builddeps && clean && fetch && unpack \
1234 && prepare && mkusers && $_build && rootpkg \
1235 && cleanup $CLEANUP \
1236 || return 1
1237 fi
1238 update_abuildrepo_index
1239}
1240
1241update_abuildrepo_index() {
1242 clean_abuildrepo
1243 mklinks_abuildrepo
1244
1245 cd "$abuildrepo"
1246 local index=$CARCH/APKINDEX.tar.gz
1247
1248 msg "Updating the cached abuild repository index..."
1249 local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
1250 local oldindex=
1251 if [ -f "$index" ]; then
1252 oldindex="--index $index"
1253 fi
1254 $APK index --quiet $oldindex --output "$index".unsigned \
1255 --description "$repo $(cd $startdir && git describe)" \
1256 --rewrite-arch $CARCH \
1257 $CARCH/*.apk || exit 1
1258 msg "Signing the index..."
1259 abuild-sign -q "$index".unsigned || exit 1
1260 mv "$index".unsigned "$index"
1261 chmod 644 "$index"
1262}
1263
1264# predefined splitfunc doc
1265default_doc() {
1266 depends="$depends_doc"
1267 pkgdesc="$pkgdesc (documentation)"
1268 arch=${arch_doc:-"noarch"}
1269
1270 local i
1271 for i in doc man info html sgml licenses gtk-doc ri; do
1272 if [ -d "$pkgdir/usr/share/$i" ]; then
1273 mkdir -p "$subpkgdir/usr/share"
1274 mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
1275 fi
1276 done
1277
1278 rm -f "$subpkgdir/usr/share/info/dir"
1279
1280 # remove if empty, ignore error (not empty)
1281 rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null
1282
1283 return 0
1284}
1285
1286doc() {
1287 default_doc
1288}
1289
1290# predefined splitfunc dev
1291default_dev() {
1292 local i= j=
1293 depends="$pkgname=$pkgver-r$pkgrel $depends_dev"
1294 pkgdesc="$pkgdesc (development files)"
1295
1296 for i in $origsubpackages; do
1297 [ "${i%:*}" = "$subpkgname" ] || depends="$depends ${i%:*}=$pkgver-r$pkgrel"
1298 done
1299
1300 cd "$pkgdir" || return 0
1301 for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
1302 usr/share/gettext usr/bin/*-config \
1303 usr/share/vala/vapi usr/share/gir-[0-9]*\
1304 usr/share/qt/mkspecs \
1305 $(find -name include -type d) \
1306 $(find lib/ usr/ -name '*.[acho]' 2>/dev/null); do
1307 if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
1308 d="$subpkgdir/${i%/*}" # dirname $i
1309 mkdir -p "$d"
1310 mv "$pkgdir/$i" "$d"
1311 rmdir "$pkgdir/${i%/*}" 2>/dev/null
1312 fi
1313 done
1314 # move *.so links needed when linking the apps to -dev packages
1315 for i in lib/*.so usr/lib/*.so; do
1316 if [ -L "$i" ]; then
1317 mkdir -p "$subpkgdir"/"${i%/*}"
1318 mv "$i" "$subpkgdir/$i" || return 1
1319 fi
1320 done
1321 return 0
1322}
1323
1324dev() {
1325 default_dev
1326}
1327
1328# predefined splitfunc libs
1329default_libs() {
1330 pkgdesc="$pkgdesc (libraries)"
1331 local dir= file=
1332 for dir in lib usr/lib; do
1333 for file in "$pkgdir"/$dir/lib*.so.[0-9]*; do
1334 [ -f "$file" ] || continue
1335 mkdir -p "$subpkgdir"/$dir
1336 mv "$file" "$subpkgdir"/$dir/
1337 done
1338 done
1339}
1340
1341libs() {
1342 default_libs
1343}
1344
1345is_function() {
1346 type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
1347}
1348
1349do_fakeroot() {
1350 if [ -n "$FAKEROOT" ]; then
1351 $FAKEROOT -- "$@"
1352 else
1353 "$@"
1354 fi
1355}
1356
1357# build and package in fakeroot
1358rootpkg() {
1359 local _package=package
1360 if ! is_function package; then
1361 # if package() is missing then run 'build' in fakeroot instead
1362 warning "No package() function in APKBUILD"
1363 _package=build
1364 fi
1365 cd "$startdir"
1366 rm -rf "$pkgdir"
1367 [ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
1368 do_fakeroot "$abuild_path" $color_opt \
1369 $_package \
1370 prepare_subpackages \
1371 prepare_language_packs \
1372 prepare_package \
1373 create_apks
1374}
1375
1376srcpkg() {
1377 getpkgver || return 1
1378 local p="$pkgname-$pkgver-$pkgrel"
1379 local prefix="${startdir##*/}"
1380 local i files="$prefix/APKBUILD"
1381 for i in $source; do
1382 files="$files $prefix/$(filename_from uri $i)"
1383 done
1384 mkdir -p "$PKGDEST"
1385 msg "Creating source package $p.src.tar.gz..."
1386 (cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files)
1387}
1388
1389# return true if arch is supported or noarch
1390check_arch() {
1391 list_has $CARCH $arch || [ "$arch" = "noarch" ] || [ "$arch" = "all" ]
1392}
1393
1394# return true if libc is not masked in options
1395check_libc() {
1396 ! list_has "!libc_$CLIBC" $options
1397}
1398
1399# check if package is up to date
1400apk_up2date() {
1401 getpkgver || return 1
1402 local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
1403 local i s
1404 cd "$startdir"
1405 for i in $pkgname $subpackages; do
1406 [ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
1407 done
1408 [ -n "$keep" ] && return 0
1409
1410 for i in $source APKBUILD; do
1411 local s
1412 if is_remote "$i"; then
1413 s="$SRCDEST/$(filename_from_uri $i)"
1414 else
1415 s="$startdir/${i##*/}"
1416 fi
1417 if [ "$s" -nt "$pkg" ]; then
1418 return 1
1419 fi
1420 done
1421 return 0
1422}
1423
1424abuildindex_up2date() {
1425 local i
1426 getpkgver || return 1
1427 local dir="$abuildrepo"/$CARCH
1428 local apk="${pkgname%:*}-$pkgver-r$pkgrel.apk"
1429 local idx="$dir"/APKINDEX.tar.gz
1430 local file="$dir"/$apk
1431
1432 # check if index is missing
1433 [ -f "$idx" ] || return 1
1434
1435 # if link or file is missing, then we need update abuildrepo index
1436 [ -f "$file" ] || return 1
1437
1438 # if file exists and is newer than index, then we need update index
1439 [ "$file" -nt "$idx" ] && return 1
1440
1441 return 0
1442}
1443
1444up2date() {
1445 check_arch || return 0
1446 check_libc || return 0
1447 apk_up2date && abuildindex_up2date
1448}
1449
1450# rebuild package and abuildrepo index if needed
1451abuildindex() {
1452 up2date && return 0
1453 build_abuildrepo
1454}
1455
1456# source all APKBUILDs and output:
1457# 1) origin of package
1458# 2) all dependencies
1459# the output is i in a format easy parseable for awk
1460depparse_aports() {
1461 # lets run this in a subshell since we source all APKBUILD here
1462 (
1463 aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
1464 for i in $aportsdir/*/APKBUILD; do
1465 pkgname=
1466 subpackages=
1467 depends=
1468 makedepends=
1469 . $i
1470 dir=${i%/APKBUILD}
1471 deps=
1472 # filter out conflicts from deps and version info
1473 for j in $depends $makedepends; do
1474 case "$j" in
1475 !*) continue;;
1476 esac
1477 deps="$deps ${j%%[<>=]*}"
1478 done
1479 for j in $pkgname $subpackages; do
1480 echo "o ${j%%:*} $dir"
1481 set -- $deps
1482 echo -n "d ${j%%:*} $1"
1483 shift
1484 while [ $# -gt 0 ]; do
1485 echo -n ",$1"
1486 shift
1487 done
1488 echo
1489 done
1490 done
1491 )
1492}
1493
1494deptrace() {
1495 local deps= i=
1496 # strip versions from deps
1497 for i in "$@"; do
1498 deps="$deps ${i%%[<>=]*}"
1499 done
1500 [ -z "$deps" ] && return 0
1501 ( depparse_aports
1502 if [ -z "$upgrade" ]; then
1503 # list installed pkgs and prefix with 'i '
1504 $APK info --quiet | sort | sed 's/^/i /'
1505 fi
1506 ) | awk -v pkgs="$deps" '
1507
1508 function depgraph(pkg, a, i) {
1509 if (visited[pkg])
1510 return 0;
1511 visited[pkg] = 1;
1512 split(deps[pkg], a, ",");
1513 for (i in a)
1514 depgraph(a[i]);
1515 print pkg ":" origin[pkg];
1516
1517 }
1518
1519 $1 == "i" { visited[$2] = 1 }
1520 $1 == "o" { origin[$2] = $3 }
1521 $1 == "d" { deps[$2] = $3 }
1522 END {
1523 split(pkgs, pkgarray);
1524 for (i in pkgarray)
1525 depgraph(pkgarray[i]);
1526 }
1527 '
1528}
1529
1530# build and install dependencies
1531builddeps() {
1532 local pkg= i= missing= conflicts=
1533 local hostdeps= builddeps= installed_hostdeps= installed_builddeps=
1534 [ -n "$nodeps" ] && return 0
1535 msg "Analyzing dependencies..."
1536
1537 # add depends unless it is a subpackage or package itself
1538 if cross_compiling && [ -n "$makedepends_build" -o -n "$makedepends_host" ]; then
1539 builddeps="$makedepends_build"
1540 for i in $BUILD_BASE; do
1541 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
1542 subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
1543 done
1544 hostdeps="$makedepends_host"
1545 for i in $depends; do
1546 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
1547 subpackages_has ${i%%[<>=]*} || hostdeps="$hostdeps $i"
1548 done
1549 else
1550 builddeps="$makedepends"
1551 for i in $BUILD_BASE $depends; do
1552 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
1553 subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
1554 done
1555 fi
1556
1557 installed_builddeps=$($APK info --installed $builddeps)
1558 [ -n "$hostdeps" ] && installed_hostdeps=$($APK info --root "$CBUILDROOT" --installed $hostdeps)
1559
1560 # find which deps are missing
1561 for i in $builddeps; do
1562 if [ "${i#\!}" != "$i" ]; then
1563 $APK info --quiet --installed "${i#\!}" \
1564 && conflicts="$conflicts ${i#\!}"
1565 elif ! deplist_has $i $installed_builddeps || [ -n "$upgrade" ]; then
1566 missing="$missing $i"
1567 fi
1568 done
1569 for i in $hostdeps; do
1570 if [ "${i#\!}" != "$i" ]; then
1571 $APK info --quiet --installed --root "$CBUILDROOT" "${i#\!}" \
1572 && conflicts="$conflicts ${i#\!}"
1573 elif ! deplist_has $i $installed_hostdeps || [ -n "$upgrade" ]; then
1574 missing="$missing $i"
1575 fi
1576 done
1577
1578 if [ -n "$conflicts" ]; then
1579 error "Conflicting package(s) installed:$conflicts"
1580 return 1
1581 fi
1582
1583 if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
1584 # if we dont have any missing deps we are done now
1585 [ -z "$missing" ] && return 0
1586 error "Missing dependencies: $missing Use -r to autoinstall or -R to build"
1587 return 1
1588 fi
1589
1590 uninstall_after=".makedepends-$pkgname $uninstall_after"
1591 if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
1592 # make a --simulate run first to detect missing deps
1593 # apk-tools --virtual is no goot at reporting those.
1594 msg "Installing packages on builder: $builddeps"
1595 $SUDO_APK add --repository "$abuildrepo" $apk_opt_wait \
1596 --simulate --quiet $builddeps || return 1
1597 $SUDO_APK add --repository "$abuildrepo" $apk_opt_wait \
1598 --virtual .makedepends-$pkgname $builddeps || return 1
1599 if [ -n "$hostdeps" ]; then
1600 msg "Installing packages on target host: $hostdeps"
1601 $SUDO_APK add --root "$CBUILDROOT" --repository "$abuildrepo" $apk_opt_wait \
1602 --simulate --quiet $hostdeps || return 1
1603 $SUDO_APK add --root "$CBUILDROOT" --repository "$abuildrepo" $apk_opt_wait \
1604 --virtual .makedepends-$pkgname $hostdeps || return 1
1605 fi
1606 return 0
1607 fi
1608
1609 if [ -n "$CBUILDROOT" ]; then
1610 error "Recursive rebuilding is not supported when cross compiling."
1611 return 1
1612 fi
1613 [ -z "$recursive" ] && return 1
1614
1615 # find dependencies that are installed but missing in repo.
1616 for i in $builddeps; do
1617 local m=$($APK search --repository "$abuildrepo" ${i%%[<>=]*})
1618 if [ -z "$m" ]; then
1619 missing="$missing $i"
1620 fi
1621 done
1622
1623 for i in $(deptrace $missing); do
1624 # i = pkg:dir
1625 local dir=${i#*:}
1626 local pkg=${i%:*}
1627
1628 # ignore if dependency is in other repo
1629 [ -d "$dir" ] || continue
1630
1631 # break circular deps
1632 list_has $pkg $ABUILD_VISITED && continue
1633 export ABUILD_VISITED="$ABUILD_VISITED $pkg"
1634
1635 msg "Entering $dir"
1636 cd "$dir" && $0 $forceroot $keep $quiet $install_deps \
1637 $recursive $upgrade $color_opt abuildindex || return 1
1638 done
1639 $SUDO_APK add --upgrade --repository "$abuildrepo" \
1640 $apk_opt_wait \
1641 --virtual .makedepends-$pkgname $builddeps
1642}
1643
1644# replace the md5sums in the APKBUILD
1645checksum() {
1646 local s files
1647 [ -z "$source" ] && [ -n "${md5sums}${sha256sums}${sha512sums}" ] \
1648 && msg "Removing checksums from APKBUILD"
1649 sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
1650 sed -i -e '/^sha512sums="/,/"\$/d; /^sha512sums=''/,/''\$/d' "$APKBUILD"
1651 sed -i -e '/^sha256sums="/,/"\$/d; /^sha256sums=''/,/''\$/d' "$APKBUILD"
1652 [ -z "$source" ] && return 0
1653 fetch
1654 for s in $source; do
1655 files="$files $(filename_from_uri $s)"
1656 done
1657
1658 # for compatibility/backporting reasons we still add md5sum
1659 msg "Updating the md5sums in APKBUILD..."
1660 md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
1661 echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
1662
1663 msg "Updating the sha256sums in APKBUILD..."
1664 sha256sums="$(cd "$srcdir" && sha256sum $files)" \
1665 || die "sha256sum failed"
1666 echo "sha256sums=\"$sha256sums\"" >>"$APKBUILD"
1667
1668 msg "Updating the sha512sums in APKBUILD..."
1669 sha512sums="$(cd "$srcdir" && sha512sum $files)" \
1670 || die "sha512sum failed"
1671 echo "sha512sums=\"$sha512sums\"" >>"$APKBUILD"
1672}
1673
1674stripbin() {
1675 local bin
1676 if options_has "!strip" || [ "$arch" = "noarch" ]; then
1677 return 0
1678 fi
1679 cd "${subpkgdir:-$pkgdir}" || return 1
1680 msg "Stripping binaries"
1681 scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
1682 | sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
1683 | xargs -r ${CROSS_COMPILE}strip
1684}
1685
1686# simply list target apks
1687listpkg() {
1688 local name
1689 getpkgver || return 1
1690 for name in $(listpkgnames) ; do
1691 echo "$name-$pkgver-r$pkgrel.apk"
1692 done
1693}
1694
1695source_has() {
1696 local i
1697 for i in $source; do
1698 [ "$1" = "${i##*/}" ] && return 0
1699 [ "$1" = "${i%%::*}" ] && return 0
1700 done
1701 return 1
1702}
1703
1704subpackages_has() {
1705 local i
1706 for i in $subpackages; do
1707 [ "$1" = "${i%:*}" ] && return 0
1708 done
1709 return 1
1710}
1711
1712list_has() {
1713 local needle="$1"
1714 local i
1715 shift
1716 for i in $@; do
1717 [ "$needle" = "$i" ] && return 0
1718 [ "$needle" = "!$i" ] && return 1
1719 done
1720 return 1
1721}
1722
1723# same as list_has but we filter version info
1724deplist_has() {
1725 local needle="$1"
1726 local i
1727 shift
1728 for i in $@; do
1729 i=${i%%[<>=]*}
1730 [ "$needle" = "$i" ] && return 0
1731 [ "$needle" = "!$i" ] && return 1
1732 done
1733 return 1
1734}
1735
1736options_has() {
1737 list_has "$1" $options
1738}
1739
1740depends_has() {
1741 deplist_has "$1" $depends
1742}
1743
1744makedepends_has() {
1745 deplist_has "$1" $makedepends
1746}
1747
1748md5sums_has() {
1749 list_has "$1" $md5sums
1750}
1751
1752install_has() {
1753 list_has "$1" $install
1754}
1755
1756# install package after build
1757post_add() {
1758 getpkgver || return 1
1759 local pkgf="$PKGDEST/$1-$pkgver-r$pkgrel.apk"
1760 local deps i
1761 if ! subpackages_has $1 && [ "$1" != "$pkgname" ]; then
1762 die "$1 is not built by this APKBUILD"
1763 fi
1764 # recursively install dependencies that are provided by this APKBUILD
1765 deps=$($APK index "$pkgf" 2>/dev/null | awk -F: '$1=="D" { print $2 }')
1766 for i in $deps; do
1767 if subpackages_has $i || [ "$i" = "$pkgname" ]; then
1768 post_add $i || return 1
1769 fi
1770 done
1771 $SUDO_APK add $apk_opt_wait --upgrade "$pkgf" \
1772 || die "Failed to install $1"
1773}
1774
1775deps() {
1776 local deps i
1777 $SUDO_APK add $apk_opt_wait --repository "$abuildrepo" \
1778 --virtual .makedepends-$pkgname \
1779 $makedepends
1780}
1781
1782undeps (){
1783 $SUDO_APK del $apk_opt_wait .makedepends-$pkgname
1784 if cross_compiling; then
1785 $SUDO_APK del --root "$CBUILDROOT" $apk_opt_wait \
1786 .makedepends-$pkgname
1787 fi
1788}
1789
1790# compat
1791installdeps() { deps; }
1792uninstalldeps() { undeps; }
1793
1794all() {
1795 if ! [ -n "$force" ]; then
1796 check_arch || return 0
1797 check_libc || return 0
1798 fi
1799 if up2date && [ -z "$force" ]; then
1800 msg "Package is up to date"
1801 else
1802 build_abuildrepo
1803 fi
1804}
1805
1806# This abuild hook will checkout an svn or git repository by specifying
1807# $svnurl or $giturl in APKBUILD. You can checkout a specific branch in
1808# git by adding -b $branch in $giturl. $reporev will select the correct
1809# commit, revision or tag for you. If you specify $disturl your distfile
1810# will automatically be uploaded with rsync to the url provided.
1811# Base version defaults to 0 except if specified by $basever.
1812
1813snapshot() {
1814 # check if we setup vars correctly
1815 [ -z "$disturl" ] && warning "Missing disturl in APKBUILD, auto uploading disabled."
1816 [ -z "$svnurl" ] && [ -z "$giturl" ] && die "Missding repository url in APKBUILD!"
1817 [ -n "$svnurl" ] && [ -n "$giturl" ] && die "You can only use a single repository!"
1818 local _date=$(date +%Y%m%d)
1819 local _format="tar.gz"
1820 # remove any repositories left in srcdir
1821 abuild clean
1822 mkdir -p "$srcdir" && cd "$srcdir"
1823 # clone git repo and archive
1824 if [ -n "$giturl" ]; then
1825 local _version=${verbase:-0}_git${_date}
1826 command -v git >/dev/null || \
1827 die "Missing git! Install git to support git clone."
1828 [ -z "$reporev" ] && local _rev="HEAD" && local _depth="--depth=1"
1829 msg "Creating git snapshot: $pkgname-$_version"
1830 git clone $_depth --bare $giturl $pkgname-$_version || return 1
1831 git --git-dir $pkgname-$_version archive \
1832 --format=$_format \
1833 -o $pkgname-$_version.$_format \
1834 --prefix=$pkgname-$_version/ $_rev \
1835 || return 1
1836 fi
1837 # export svn repo and archive
1838 if [ -n "$svnurl" ]; then
1839 local _version=${verbase:-0}_svn${_date}
1840 command -v svn >/dev/null || \
1841 die "Missing svn! Install subverion to support svn export."
1842 [ -n "$reporev" ] && local _rev="-r $reporev"
1843 msg "Creating svn snapshot: $pkgname-$_version"
1844 svn export $_rev $svnurl $pkgname-$_version || return 1
1845 tar zcf $pkgname-$_version.$_format $pkgname-$_version || return 1
1846 fi
1847 # upload to defined distfiles url
1848 if [ -n "$disturl" ]; then
1849 command -v rsync >/dev/null || \
1850 die "Missing rsync! Install rsync to enable automatic uploads."
1851 msg "Uploading to $disturl"
1852 rsync --progress -La $pkgname-$_version.$_format \
1853 $disturl || return 1
1854 cd "$startdir"
1855 # set the pkgver to current date and update checksum
1856 sed -i -e "s/^pkgver=.*/pkgver=${_version}/" \
1857 APKBUILD || return 1
1858 abuild checksum
1859 fi
1860}
1861
1862hostspec_to_arch() {
1863 case "$1" in
1864 arm*-*-*-*eabi) echo "armel" ;;
1865 arm*-*-*-*eabihf) echo "armhf" ;;
1866 i[0-9]86-*-*-*) echo "x86" ;;
1867 x86_64-*-*-*) echo "x86_64" ;;
1868 *) echo "unknown" ;;
1869 esac
1870}
1871
1872hostspec_to_libc() {
1873 case "$1" in
1874 *-*-*-uclibc*) echo "uclibc" ;;
1875 *-*-*-musl*) echo "musl" ;;
1876 *-*-*-gnu*) echo "eglibc" ;;
1877 *) echo "uclibc" ;;
1878 esac
1879}
1880
1881usage() {
1882 echo "$program $abuild_ver"
1883 echo "usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]"
1884 echo " [-s SRCDEST] [cmd] ..."
1885 echo " $program [-c] -n PKGNAME[-PKGVER]"
1886 echo "Options:"
1887 echo " -c Enable colored output"
1888 echo " -d Disable dependency checking"
1889 echo " -f Force specified cmd, even if they are already done"
1890 echo " -F Force run as root"
1891 echo " -h Show this help"
1892 echo " -i Install PKG after successful build"
1893 echo " -k Keep built packages, even if APKBUILD or sources are newer"
1894 echo " -m Disable colors (monochrome)"
1895 echo " -p Set package destination directory"
1896 echo " -P Set PKGDEST to REPODEST/<repo>/\$CARCH, where repo is the parents dir name"
1897 echo " -q Quiet"
1898 echo " -r Install missing dependencies from system repository (using sudo)"
1899 echo " -R Recursively build and install missing dependencies (using sudo)"
1900 echo " -s Set source package destination directory"
1901 echo " -u Recursively build and upgrade all dependencies (using sudo)"
1902 echo ""
1903 echo "Commands:"
1904 echo " checksum Generate checksum to be included in APKBUILD"
1905 echo " fetch Fetch sources to \$SRCDEST and verify checksums"
1906 echo " sanitycheck Basic sanity check of APKBUILD"
1907 echo " verify Verify checksums"
1908 echo " unpack Unpack sources to \$srcdir"
1909 echo " build Compile and install package into \$pkgdir"
1910 echo " listpkg List target packages"
1911 echo " package Create package in \$PKGDEST"
1912 echo " rootpkg Run 'package', the split functions and create apks as fakeroot"
1913 echo " clean Remove temp build and install dirs"
1914 echo " cleanoldpkg Remove binary packages except current version"
1915 echo " cleanpkg Remove already built binary and source package"
1916 echo " cleancache Remove downloaded files from \$SRCDEST"
1917 echo " srcpkg Make a source package"
1918 echo " sourcecheck Check if remote source package exists upstream"
1919 echo " up2date Compare target and sources dates"
1920 echo " deps Install packages listed in makedepends and depends"
1921 echo " undeps Uninstall packages listed in makedepends and depends"
1922 echo " snapshot Create a \$giturl or \$svnurl snapshot and upload to \$disturl"
1923 echo ""
1924 exit 0
1925}
1926
1927APKBUILD="${APKBUILD:-./APKBUILD}"
1928unset force
1929unset recursive
1930while getopts "cdfFhi:kimnp:P:qrRs:u" opt; do
1931 case $opt in
1932 'c') default_colors
1933 color_opt="-c";;
1934 'd') nodeps=1;;
1935 'f') force="-f";;
1936 'F') forceroot="-F";;
1937 'h') usage;;
1938 'i') install_after="$install_after $OPTARG";;
1939 'k') keep="-k";;
1940 'm') monochrome
1941 color_opt="-m";;
1942 'n') die "Use newapkbuild to create new aports";;
1943 'p') PKGDEST=$OPTARG;;
1944 'P') REPODEST=$OPTARG;;
1945 'q') quiet="-q";;
1946 'r') install_deps="-r";;
1947 'R') recursive="-R";;
1948 's') SRCDEST=$OPTARG;;
1949 'u') upgrade="-u"
1950 recursive="-R";;
1951 esac
1952done
1953shift $(( $OPTIND - 1 ))
1954
1955# check so we are not root
1956if [ "$(whoami)" = "root" ] && [ -z "$FAKEROOTKEY" ]; then
1957 [ -z "$forceroot" ] && die "Do not run abuild as root"
1958 FAKEROOT=
1959fi
1960
1961# find startdir
1962[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
1963APKBUILD=$(readlink -f "$APKBUILD")
1964
1965startdir="${APKBUILD%/*}"
1966srcdir=${srcdir:-"$startdir/src"}
1967pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
1968pkgrel=0
1969repo=${startdir%/*}
1970repo=${repo##*/}
1971
1972SRCDEST=${SRCDEST:-$startdir}
1973PKGDEST=${PKGDEST:-$startdir}
1974
1975[ -z "$CBUILD" ] && CBUILD="$CHOST"
1976[ -z "$CTARGET" ] && CTARGET="$CHOST"
1977[ -z "$CARCH" ] && CARCH="$(hostspec_to_arch $CHOST)"
1978[ -z "$CLIBC" ] && CLIBC="$(hostspec_to_libc $CHOST)"
1979[ -z "$CTARGET_ARCH" ] && CTARGET_ARCH="$(hostspec_to_arch $CTARGET)"
1980[ -z "$CTARGET_LIBC" ] && CTARGET_LIBC="$(hostspec_to_libc $CTARGET)"
1981
1982# set a default CC
1983: ${CC:=gcc}
1984export CC
1985
1986cd "$startdir" || die
1987. "$APKBUILD"
1988
1989# If REPODEST is set then it will override the PKGDEST
1990if [ -n "$REPODEST" ]; then
1991 PKGDEST="$REPODEST/$repo/$CARCH"
1992 # for recursive action
1993 export REPODEST
1994 abuildrepo="$REPODEST"/$repo
1995else
1996 abuildrepo="$abuildrepo_base"/$repo
1997fi
1998
1999# if we want build debug package
2000if [ -n "$DEBUG" ]; then
2001 CFLAGS="$CFLAGS -g"
2002 options="$options !strip"
2003fi
2004
2005# If we are handling a sub package then reset subpackages and install
2006if [ -n "$subpkgname" ]; then
2007 origsubpackages="$subpackages"
2008 subpackages=
2009fi
2010pkgdir="$pkgbasedir/$pkgname"
2011controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
2012
2013trap 'die "Aborted by user"' INT
2014set_xterm_title "abuild: $pkgname"
2015
2016if [ -z "$1" ]; then
2017 set all
2018fi
2019
2020while [ $# -gt 0 ]; do
2021 runpart $1
2022 shift
2023done
2024
2025for i in $install_after; do
2026 post_add $i
2027done
2028
2029cleanup
2030