projects/aports·blob v2.14.0 · refs

1877 lines · 45.1 KiB

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