projects/aports·blob v2.6 · refs

1235 lines · 28.5 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=@abuildrepo@
14datadir=@datadir@
15
16program=${0##*/}
17abuild_path=$(readlink -f $0)
18
19# defaults
20BUILD_BASE="build-base"
21SUDO=${SUDO:-"sudo"}
22FAKEROOT=${FAKEROOT:-"fakeroot"}
23APK=${APK:-apk}
24
25# read config
26ABUILD_CONF=${ABUILD_CONF:-"$sysconfdir/abuild.conf"}
27[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"
28
29default_colors() {
30 NORMAL="\033[1;0m"
31 STRONG="\033[1;1m"
32 RED="\033[1;31m"
33 GREEN="\033[1;32m"
34 YELLOW="\033[1;33m"
35 BLUE="\033[1;34m"
36}
37
38monochrome() {
39 NORMAL=""
40 STRONG=""
41 RED=""
42 GREEN=""
43 YELLOW=""
44 BLUE=""
45}
46
47#colors
48if [ -n "$USE_COLORS" ]; then
49 default_colors
50fi
51
52
53# functions
54msg() {
55 local prompt="$GREEN>>>${NORMAL}"
56 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
57 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
58 [ -z "$quiet" ] && printf "${prompt} ${name}${fake}: $@\n" >&2
59}
60
61warning() {
62 local prompt="${YELLOW}>>> WARNING:${NORMAL}"
63 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
64 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
65 printf "${prompt} ${name}${fake}: $@\n" >&2
66}
67
68error() {
69 local prompt="${RED}>>> ERROR:${NORMAL}"
70 local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
71 local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
72 printf "${prompt} ${name}${fake}: $@\n" >&2
73}
74
75
76set_xterm_title() {
77 if [ "$TERM" = xterm ]; then
78 printf "\033]0;$1\007" >&2
79 fi
80}
81
82cleanup() {
83 set_xterm_title ""
84 if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
85 $SUDO $APK del $uninstall_after
86 fi
87}
88
89die() {
90 error "$@"
91 cleanup
92 exit 1
93}
94
95# check if apkbuild is basicly sane
96sanitycheck() {
97 local i suggestion
98 msg "Checking sanity of $APKBUILD..."
99 [ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
100 [ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
101 [ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
102 if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
103 $APK version --check -q "$pkgver" ||\
104 die "$pkgver is not a valid version"
105 fi
106 [ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
107 [ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
108 [ -z "$url" ] && die "Missing url in APKBUILD"
109 [ -z "$license" ] && die "Missing license in APKBULID"
110
111 # check if CARCH, CBUILD, CHOST and CTARGET is set
112 if [ -z "$CARCH" ]; then
113 case "$(uname -m)" in
114 i[0-9]86) suggestion=" (Suggestion: CARCH=x86)";;
115 x86_64) suggestion=" (Suggestion: CARCH=x86_64)";;
116 esac
117 die "Please set CARCH in /etc/abuild.conf$suggestion"
118 fi
119 [ -z "$CHOST" ] && die "Please set CHOST in /etc/abuild.conf"
120
121 for i in $install; do
122 [ -e "$startdir/$i" ] || die "install script $startdir/$i is missing"
123 done
124
125 [ -n "${triggers%%:*}" ] && [ ! -e "$startdir"/${triggers%%:*} ] \
126 && die "trigger script $startdir/${triggers%%:*} is missing"
127
128 if [ -n "$source" ]; then
129 for i in $source; do
130 if install_has "$i"; then
131 warning "You should not have \$install in source"
132 continue
133 fi
134 md5sums_has ${i##*/} || die "${i##*/} is missing in md5sums"
135 case "$i" in
136 https://*) makedepends_has wget || die "wget must be in makedepends when source has https://" ;;
137 esac
138 done
139 fi
140
141 if [ -n "$md5sums" ]; then
142 for i in $(echo "$md5sums" | awk '{ print $2 }'); do
143 source_has $i || die "$i exists in md5sums but is missing in source"
144 done
145 fi
146
147 # common spelling errors
148 [ -n "$depend" ] && die "APKBUILD contains 'depend'. It should be depends"
149 [ -n "$makedepend" ] && die "APKBUILD contains 'makedepend'. It should be makedepends"
150
151 grep '^# Maintainer:' $APKBUILD >/dev/null || warning "No maintainer"
152
153 makedepends_has 'g++' && warning "g++ should not be in makedepends"
154 return 0
155}
156
157md5check() {
158 local dummy f
159 if [ -z "$source" ]; then
160 return 0
161 fi
162 if [ -z "$md5sums" ]; then
163 die "Use 'abuild checksum' to generate/update the checksum(s)"
164 fi
165 if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
166 die "Number of md5sums does not correspond to number of sources"
167 fi
168 fetch || return 1
169 msg "Checking md5sums..."
170 cd "$srcdir" && echo "$md5sums" | md5sum -c
171}
172
173uri_fetch() {
174 local uri="$1"
175 local d="${uri##*/}" # $(basename $uri)
176 local opts
177 [ -n "$quiet" ] && opts="-q"
178 [ -f "$SRCDEST/$d" ] && return 0
179
180 # we need GNU wget for this
181 case "$uri" in
182 https://*) opts="--no-check-certificate";;
183 esac
184
185 mkdir -p "$SRCDEST"
186 if [ -f "$SRCDEST/$d.part" ]; then
187 msg "Partial download found. Trying to resume"
188 opts="$opts -c"
189 fi
190 msg "Fetching $uri"
191 wget $opts -O "$SRCDEST/$d.part" "$uri" \
192 && mv "$SRCDEST/$d.part" "$SRCDEST/$d"
193}
194
195is_remote() {
196 case "$1" in
197 http://*|ftp://*|https://*)
198 return 0;;
199 esac
200 return 1
201}
202
203# try download from file from mirror first
204uri_fetch_mirror() {
205 local uri="$1"
206 local d="${uri##*/}" # $(basename $uri)
207 if [ -n "$DISTFILES_MIRROR" ]; then
208 if is_remote "$DISTFILES_MIRROR"; then
209 uri_fetch "$DISTFILES_MIRROR"/$d && return 0
210 else
211 cp "$DISTFILES_MIRROR"/$d "$SRCDEST" && return 0
212 fi
213 fi
214 uri_fetch "$uri"
215}
216
217default_fetch() {
218 local s
219 mkdir -p "$srcdir"
220 for s in $source; do
221 if is_remote "$s"; then
222 uri_fetch_mirror "$s" || return 1
223 ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
224 else
225 ln -sf "$startdir/$s" "$srcdir/"
226 fi
227 done
228}
229
230fetch() {
231 default_fetch
232}
233
234# unpack the sources
235default_unpack() {
236 local u
237 md5check || return 1
238 mkdir -p "$srcdir"
239 for u in $source; do
240 local s="$SRCDEST/${u##*/}" # $(basename $s)
241 case "$s" in
242 *.tar.gz|*.tgz)
243 msg "Unpacking $s..."
244 tar -C "$srcdir" -zxf "$s" || return 1;;
245 *.tar.bz2)
246 msg "Unpacking $s..."
247 tar -C "$srcdir" -jxf "$s" || return 1;;
248 *.tar.lzma)
249 msg "Unpacking $s..."
250 unlzma -c "$s" | tar -C "$srcdir" -x \
251 || return 1;;
252 *.tar.xz)
253 msg "Unpacking $s..."
254 unxz -c "$s" | tar -C "$srcdir" -x || return 1;;
255 *.zip)
256 msg "Unpacking $s..."
257 unzip "$s" -d "$srcdir" || return 1;;
258 esac
259 done
260}
261
262unpack() {
263 default_unpack
264}
265
266# cleanup source and package dir
267clean() {
268 msg "Cleaning temporary build dirs..."
269 rm -rf "$srcdir"
270 rm -rf "$pkgbasedir"
271}
272
273# cleanup fetched sources
274cleancache() {
275 local s
276 for s in $source; do
277 if is_remote "$s"; then
278 msg "Cleaning downloaded ${s##*/}..."
279 rm -f "$SRCDEST/${s##*/}"
280 fi
281 done
282}
283
284cleanpkg() {
285 local i
286 getpkgver || return 1
287 msg "Cleaning built packages..."
288 for i in $pkgname $subpackages; do
289 local p="${i%:*}-$pkgver-r$pkgrel"
290 rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
291 "$abuildrepo"/$p.apk
292 done
293 # remove given packages from index
294}
295
296# clean all packages except current
297cleanoldpkg() {
298 local i j
299 getpkgver || return 1
300 msg "Cleaning all packages except $pkgver-r$pkgrel..."
301 for i in $pkgname $subpackages; do
302 for j in "$PKGDEST"/${i%:*}-[0-9]*.apk; do
303 [ "$j" != "$PKGDEST/${i%:*}-$pkgver-r$pkgrel.apk" ] \
304 && rm -f "$j"
305 done
306 done
307 return 0
308}
309
310mkusers() {
311 local i
312 for i in $pkgusers; do
313 if ! getent passwd $i >/dev/null; then
314 msg "Creating user $i"
315 $SUDO adduser -D -H $i || return 1
316 fi
317 done
318 for i in $pkggroups; do
319 if ! getent group $i >/dev/null; then
320 msg "Creating group $i"
321 $SUDO addgroup $i || return 1
322 fi
323 done
324}
325
326
327runpart() {
328 local part=$1
329 [ -n "$DEBUG" ] && msg "$part"
330 $part || die "$part failed"
331}
332
333# override those in your build script
334getpkgver() {
335 # this func is supposed to be overridden by volatile packages
336 if [ "$pkgver" = "volatile" ]; then
337 error "Please provide a getpkgver() function in your APKBUILD"
338 return 1
339 fi
340}
341
342prepare() {
343 :
344}
345
346build() {
347 :
348}
349
350# generate a simple tar.gz package of pkgdir
351targz() {
352 cd "$pkgdir" || return 1
353 tar -czf "$PKGDEST"/$pkgname-$pkgver-r$pkgrel.tar.gz *
354}
355
356get_split_func() {
357 # get the 'func' from "sub-pkg:func"
358 local func=${1##*:}
359
360 # get 'func' from "sub-pkg-func" if there was no :func
361 [ "$func" = "$1" ] && func=${func##*-}
362 echo $func
363}
364
365prepare_subpackages() {
366 if [ -z "$subpackages" ]; then
367 return 0
368 fi
369 local i
370 cd "$startdir"
371 for i in $subpackages; do
372 local func=$(get_split_func $i)
373 # call abuild recursively, setting subpkg{dir,name}
374 msg "Running split function $func..."
375 subpkgdir="$pkgbasedir/${i%:*}" subpkgname="${i%:*}" \
376 $0 $func prepare_package || return 1
377 done
378}
379
380prepare_metafiles() {
381 getpkgver || return 1
382 local name=${subpkgname:-$pkgname}
383 [ -z "${name##* *}" ] && die "package name contains spaces"
384 local dir=${subpkgdir:-$pkgdir}
385 local pkg="$name-$pkgver-r$pkgrel.apk"
386 local pkginfo="$controldir"/.PKGINFO
387 local sub
388
389 [ ! -d "$dir" ] && die "Missing $dir"
390 cd "$dir"
391 mkdir -p "$controldir"
392 local builddate=$(date -u "+%s")
393 local size=$(du -sk | awk '{print $1 * 1024}')
394 local parch="$CARCH"
395 if [ "$arch" = "noarch" ]; then
396 parch="noarch"
397 fi
398
399 echo "# Generated by $(basename $0) $abuild_ver" >"$pkginfo"
400 if [ -n "$FAKEROOTKEY" ]; then
401 echo "# using $($FAKEROOT -v)" >> "$pkginfo"
402 fi
403 echo "# $(date -u)" >> "$pkginfo"
404 cat >> "$pkginfo" <<EOF
405pkgname = $name
406pkgver = $pkgver-r$pkgrel
407pkgdesc = $pkgdesc
408url = $url
409builddate = $builddate
410packager = ${PACKAGER:-"Unknown"}
411size = $size
412arch = $parch
413EOF
414 local i deps
415 deps="$depends"
416 if [ "$pkgname" != "busybox" ] && ! depends_has busbox; then
417 for i in $install ${triggers%%:*}; do
418 if head -n 1 "$startdir/$i" | grep '^#!/bin/sh' >/dev/null ; then
419 msg "Script found. busybox added as a dependency for $pkg"
420 deps="$deps busybox"
421 break
422 fi
423 done
424 fi
425
426 for i in $license; do
427 echo "license = $i" >> "$pkginfo"
428 done
429 for i in $replaces; do
430 echo "replaces = $i" >> "$pkginfo"
431 done
432 for i in $deps; do
433 echo "depend = $i" >> "$pkginfo"
434 done
435 for i in $conflicts; do
436 echo "conflict = $i" >> "$pkginfo"
437 done
438 for i in $provides; do
439 echo "provides = $i" >> "$pkginfo"
440 done
441 for i in $backup; do
442 echo "backup = $i" >> "$pkginfo"
443 done
444 if [ -n "$triggers" ]; then
445 echo "triggers = ${triggers#*:}" >> "$pkginfo"
446 fi
447
448 local metafiles=".PKGINFO"
449 for i in $install ${triggers%%:*}; do
450 script=${i#$name}
451 case "$script" in
452 .pre-install|.post-install|.pre-upgrade|.post-upgrade|.pre-deinstall|.post-deinstall|.trigger)
453 msg "Adding $script"
454 ;;
455 *) error "$script: Invalid install/trigger script"
456 return 1
457 ;;
458 esac
459 cp "$startdir/$i" "$controldir/$script" || return 1
460 chmod +x "$controldir/$script"
461 metafiles="$metafiles $script"
462 done
463 echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
464}
465
466prepare_tracedeps() {
467 local dir=${subpkgdir:-$pkgdir}
468 options_has "!tracedeps" && return 0
469 # lets tell all the .so files this package provides in .provides-so
470 find -name '*.so' -o -name '*.so.[0-9]*' | sed 's:.*/::' \
471 >"$controldir"/.provides-so
472 # lets tell all the places we should look for .so files - all rpaths
473 scanelf -q -Rr "$dir" | sed -e 's/[[:space:]].*//' -e 's/:/\n/' \
474 | sort | uniq \
475 >"$controldir"/.rpaths
476 # now find the so dependencies
477 scanelf -Rn "$dir" | tr ' ' ':' | awk -F ":" '$1 == "ET_DYN" || $1 == "ET_EXEC" {print $2}' \
478 | sed 's:,:\n:g' | sort | uniq \
479 | while read i; do
480 # only add files that are not self provided
481 grep "^$i$" "$controldir"/.provides-so >/dev/null \
482 || echo $i >> "$controldir"/.needs-so
483 done
484}
485
486prepare_package() {
487 msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
488 stripbin
489 prepare_metafiles && prepare_tracedeps
490}
491
492pkginfo_val() {
493 local key="$1"
494 local file="$2"
495 awk -F ' = ' "\$1 == \"$key\" {print \$2}" "$file"
496}
497
498# find real path to so files
499real_so_path() {
500 local so="$1"
501 shift
502 while [ $# -gt 0 ]; do
503 [ -e "$1"/$so ] && realpath "$1/$so" && return 0
504 shift
505 done
506 error "$so: path not found"
507 return 1
508}
509
510# search rpaths and /usr/lib /lib for given so files
511find_so_files() {
512 local rpaths=$(cat "$1")
513 shift
514 while [ $# -gt 0 ]; do
515 real_so_path "$1" /usr/lib /lib $rpaths || return 1
516 shift
517 done
518 return 0
519}
520
521trace_apk_deps() {
522 local name="$1"
523 local dir="$2"
524 local i= j= found= autodeps= deppkgs= missing= so_paths=
525 msg "Tracing dependencies for $name..."
526 # add pkgconfig if usr/lib/pkgconfig is found
527 if [ -d "$pkgbasedir"/$name/usr/lib/pkgconfig ] \
528 && ! grep -q '^depend = pkgconfig' "$dir"/.PKGINFO; then
529 msg "Added pkgconfig as dependency"
530 autodeps="$autodeps pkgconfig"
531 fi
532
533 # special case for libpthread: we need depend on libgcc
534 if grep -q -w '^libpthread.so.*' "$dir"/.needs-so 2>/dev/null \
535 && ! grep -q -w "^depend = libgcc" "$dir"/.PKGINFO; then
536 autodeps="$autodeps libgcc"
537 msg "Added libgcc as dependency due to libpthread"
538 fi
539 for i in $(cat "$dir"/.needs-so 2>/dev/null); do
540 found=
541 # first check if its provide by same apkbuild
542 for j in "$dir"/../.control.*/.provides-so; do
543 grep -w "$i" "$j" >/dev/null || continue
544 found=${j%/.provides-so}
545 found=${found##*/.control.}
546 break
547 done
548 if [ -n "$found" ]; then
549 if ! list_has "$found" $self_provided; then
550 self_provided="$self_provided $found"
551 fi
552 else
553 missing="$missing $i"
554 fi
555 done
556
557 # find all packages that holds the so files
558 so_files=$(find_so_files "$dir"/.rpaths $missing) || return 1
559 deppkgs=$($APK info -q -W $so_files) || return 1
560
561 for found in $self_provided $deppkgs; do
562 if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
563 warning "You can remove '$found' from depends"
564 continue
565 fi
566 if [ "$found" != "$name" ] && ! list_has "$found" $autodeps; then
567 autodeps="$autodeps $found"
568 msg "Added '$found' as dependency"
569 fi
570 done
571
572 [ -z "$autodeps" ] && return 0
573 echo "# automatically detected:" >> "$dir"/.PKGINFO
574 for i in $autodeps; do
575 echo "depend = $i" >> "$dir"/.PKGINFO
576 done
577}
578
579create_apks() {
580 local file
581 getpkgver || return 1
582 for file in "$pkgbasedir"/.control.*/.PKGINFO; do
583 local dir="${file%/.PKGINFO}"
584 local name=$(pkginfo_val pkgname $file)
585 local ver=$(pkginfo_val pkgver $file)
586 local apk=$name-$ver.apk
587 local datadir="$pkgbasedir"/$name
588
589 trace_apk_deps "$name" "$dir" || return 1
590 msg "Creating $apk..."
591 (
592 cd "$datadir"
593 # data.tar.gz
594 set -- *
595 if [ "$1" = '*' ]; then
596 touch .dummy
597 set -- .dummy
598 fi
599 tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
600
601 # append the hash for data.tar.gz
602 local sha256=$(sha256sum "$dir"/data.tar.gz | cut -f1 -d' ')
603 echo "datahash = $sha256" >> "$dir"/.PKGINFO
604
605 # control.tar.gz
606 cd "$dir"
607 tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
608 | gzip -9 > control.tar.gz
609 abuild-sign -q control.tar.gz || exit 1
610
611 # create the final apk
612 cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
613 )
614 done
615}
616
617update_abuildrepo() {
618 if ! apk_up2date || [ -n "$force" ]; then
619 sanitycheck && builddeps && clean && fetch && unpack \
620 && prepare && mkusers && rootpkg || return 1
621 fi
622
623 local apk
624 mkdir -p "$abuildrepo" || return 1
625 cd "$abuildrepo"
626
627 # remove broken links
628 for apk in *.apk; do
629 if [ -L "$apk" ] && [ ! -f "$apk" ]; then
630 rm -f "$apk"
631 fi
632 done
633
634 # create links for this package
635 for apk in $(listpkg); do
636 ln -sf "$PKGDEST"/$apk "$abuildrepo"/$apk
637 done
638
639 msg "Updating the cached abuild repository index..."
640 local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
641 local oldindex=
642 if [ -f APKINDEX.tar.gz ]; then
643 oldindex="--index APKINDEX.tar.gz"
644 fi
645 $APK index $oldindex --output APKINDEX.tar.gz.unsigned \
646 --description "$repo $(cd $startdir && git describe)" \
647 *.apk || exit 1
648 msg "Signing the index..."
649 abuild-sign -q APKINDEX.tar.gz.unsigned || exit 1
650 mv APKINDEX.tar.gz.unsigned APKINDEX.tar.gz
651 chmod 644 APKINDEX.tar.gz
652}
653
654# predefined splitfunc doc
655default_doc() {
656 depends="$depends_doc"
657 install="$install_doc"
658 triggers="$triggers_doc"
659 local i
660 for i in doc man info html sgml licenses gtk-doc; do
661 if [ -d "$pkgdir/usr/share/$i" ]; then
662 mkdir -p "$subpkgdir/usr/share"
663 mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
664 fi
665 done
666
667 rm -f "$subpkgdir/usr/share/info/dir"
668
669# # compress info and man pages
670# find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
671# -o -name '*.[1-9]' \) -exec gzip {} \;
672
673 # remove if empty, ignore error (not empty)
674 rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null
675
676# [ -d "$subpkgdir/usr/share/man" ] && depends="man"
677 return 0
678}
679
680doc() {
681 default_doc
682}
683
684# predefined splitfunc mod
685default_mod() {
686 depends="$kernel $depends_mod"
687 install="$install_mod"
688 for i in firmware modules; do
689 if [ -d "$pkgdir/lib/$i" ]; then
690 rm -rf "$subpkgdir/lib"
691 mkdir -p "$subpkgdir/lib"
692 mv "$pkgdir/lib/$i" "$subpkgdir/lib"
693 fi
694 done
695}
696
697mod() {
698 default_mod
699}
700
701# predefined splitfunc dev
702default_dev() {
703 local i= j=
704 depends="$pkgname $depends_dev"
705 install="$install_dev"
706 triggers="$triggers_dev"
707 for i in $origsubpackages; do
708 [ "${i%:*}" = "$subpkgname" ] || depends="$depends ${i%:*}"
709 done
710
711 cd "$pkgdir" || return 0
712 for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
713 usr/share/gettext usr/bin/*-config \
714 usr/share/vala/vapi usr/share/gir-[0-9]*\
715 $(find -name include -type d) \
716 $(find usr/ -name '*.[acho]' -o -name '*.la' \
717 2>/dev/null); do
718 if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
719 d="$subpkgdir/${i%/*}" # dirname $i
720 mkdir -p "$d"
721 mv "$pkgdir/$i" "$d"
722 rmdir "$pkgdir/${i%/*}" 2>/dev/null
723 fi
724 done
725 # move *.so links needed when linking the apps to -dev packages
726 for i in lib/*.so usr/lib/*.so; do
727 if [ -L "$i" ]; then
728 mkdir -p "$subpkgdir"/"${i%/*}"
729 mv "$i" "$subpkgdir/$i" || return 1
730 fi
731 done
732 return 0
733}
734
735dev() {
736 default_dev
737}
738
739is_function() {
740 type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
741}
742
743# build and package in fakeroot
744rootpkg() {
745 local do_build=build
746 cd "$startdir"
747 if is_function package; then
748 build || return 1
749 do_build=package
750 fi
751 cd "$startdir"
752 [ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
753 $FAKEROOT -- "$abuild_path" $color_opt $do_build \
754 prepare_subpackages \
755 prepare_package \
756 create_apks
757}
758
759srcpkg() {
760 getpkgver || return 1
761 local p="$pkgname-$pkgver-$pkgrel"
762 local prefix="${startdir##*/}"
763 local i files="$prefix/APKBUILD"
764 for i in $source; do
765 files="$files $prefix/${i##*/}"
766 done
767 mkdir -p "$PKGDEST"
768 msg "Creating source package $p.src.tar.gz..."
769 (cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files)
770}
771
772# return true if arch is supported or noarch
773check_arch() {
774 list_has $CARCH $arch || [ "$arch" = "noarch" ] || [ "$arch" = "all" ]
775}
776
777# check if package is up to date
778apk_up2date() {
779 getpkgver || return 1
780 local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
781 local i s
782 cd "$startdir"
783 for i in $pkgname $subpackages; do
784 [ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
785 done
786 [ -n "$keep" ] && return 0
787
788 for i in $source APKBUILD; do
789 local s
790 if is_remote "$i"; then
791 s="$SRCDEST/${i##*/}" # $(basename $i)
792 else
793 s="$startdir/${i##*/}"
794 fi
795 if [ "$s" -nt "$pkg" ]; then
796 return 1
797 fi
798 done
799 return 0
800}
801
802abuildindex_up2date() {
803 local i apk
804 getpkgver || return 1
805 for i in $pkgname $subpackages; do
806 apk="${i%:*}-$pkgver-r$pkgrel.apk"
807 [ "$abuildrepo"/APKINDEX.tar.gz -nt "$abuildrepo"/$apk ] || return 1
808 done
809 return 0
810}
811
812up2date() {
813 check_arch || return 0
814 apk_up2date && abuildindex_up2date
815}
816
817# rebuild package and abuildrepo index if needed
818abuildindex() {
819 up2date && return 0
820 update_abuildrepo
821}
822
823# source all APKBUILDs and output:
824# 1) origin of package
825# 2) all dependencies
826# the output is i in a format easy parseable for awk
827depparse_aports() {
828 # lets run this in a subshell since we source all APKBUILD here
829 (
830 aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
831 for i in $aportsdir/*/APKBUILD; do
832 pkgname=
833 subpackages=
834 depends=
835 makedepends=
836 . $i
837 dir=${i%/APKBUILD}
838 deps=
839 # filter out conflicts from deps and version info
840 for j in $depends $makedepends; do
841 case "$j" in
842 !*) continue;;
843 esac
844 deps="$deps ${j%%[<>=]*}"
845 done
846 for j in $pkgname $subpackages; do
847 echo "o ${j%%:*} $dir"
848 set -- $deps
849 echo -n "d ${j%%:*} $1"
850 shift
851 while [ $# -gt 0 ]; do
852 echo -n ",$1"
853 shift
854 done
855 echo
856 done
857 done
858 )
859}
860
861deptrace() {
862 local deps= i=
863 # strip versions from deps
864 for i in "$@"; do
865 deps="$deps ${i%%[<>=]*}"
866 done
867 [ -z "$deps" ] && return 0
868 ( depparse_aports
869 if [ -z "$upgrade" ]; then
870 # list installed pkgs and prefix with 'i '
871 $APK info -q | sort | sed 's/^/i /'
872 fi
873 ) | awk -v pkgs="$deps" '
874
875 function depgraph(pkg, a, i) {
876 if (visited[pkg])
877 return 0;
878 visited[pkg] = 1;
879 split(deps[pkg], a, ",");
880 for (i in a)
881 depgraph(a[i]);
882 print pkg ":" origin[pkg];
883
884 }
885
886 $1 == "i" { visited[$2] = 1 }
887 $1 == "o" { origin[$2] = $3 }
888 $1 == "d" { deps[$2] = $3 }
889 END {
890 split(pkgs, pkgarray);
891 for (i in pkgarray)
892 depgraph(pkgarray[i]);
893 }
894 '
895}
896
897# build and install dependencies
898builddeps() {
899 local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
900 local filtered_deps= conflicts=
901 [ -n "$nodeps" ] && return 0
902 msg "Analyzing dependencies..."
903
904 # add depends unless it is a subpackage or package itself
905 for i in $BUILD_BASE $depends $makedepends; do
906 [ "$pkgname" = "${i%%[<>=]*}" ] && continue
907 subpackages_has ${i%%[<>=]*} || deps="$deps $i"
908 done
909
910 installed_deps=$($APK info -e $deps)
911 # find which deps are missing
912 for i in $deps; do
913 if [ "${i#\!}" != "$i" ]; then
914 $APK info -q -e "${i#\!}" \
915 && conflicts="$conflicts ${i#\!}"
916 elif ! deplist_has $i $installed_deps || [ -n "$upgrade" ]; then
917 missing="$missing $i"
918 fi
919 done
920
921 if [ -n "$conflicts" ]; then
922 error "Conflicting package(s) installed:$conflicts"
923 return 1
924 fi
925
926 if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
927 # if we dont have any missing deps we are done now
928 [ -z "$missing" ] && return 0
929 error "Missing dependencies: $missing Use -r to autoinstall or -R to build"
930 return 1
931 fi
932
933 uninstall_after=".makedepends-$pkgname $uninstall_after"
934 if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
935 # make a --simluate run first to detect missing deps
936 # apk-tools --virtual is no goot at reporting those.
937 $SUDO $APK add --repository "$abuildrepo" \
938 --wait 30 \
939 --simulate --quiet $deps || return 1
940 $SUDO $APK add --repository "$abuildrepo" \
941 --wait 30 \
942 --virtual .makedepends-$pkgname $deps \
943 && return 0
944 fi
945
946 [ -z "$recursive" ] && return 1
947
948 # find dependencies that are installed but missing in repo.
949 for i in $deps; do
950 local m=$($APK search --repository "$abuildrepo" ${i%%[<>=]*})
951 if [ -z "$m" ]; then
952 missing="$missing $i"
953 fi
954 done
955
956 for i in $(deptrace $missing); do
957 # i = pkg:dir
958 local dir=${i#*:}
959 local pkg=${i%:*}
960
961 # ignore if dependency is in other repo
962 [ -d "$dir" ] || continue
963
964 # break cricular deps
965 list_has $pkg $ABUILD_VISITED && continue
966 export ABUILD_VISITED="$ABUILD_VISITED $pkg"
967
968 msg "Entering $dir"
969 cd "$dir" && $0 $forceroot $keep $quiet $install_deps \
970 $recursive $upgrade $color_opt abuildindex || return 1
971 done
972 $SUDO $APK add -u --repository "$abuildrepo" \
973 --wait 30 \
974 --virtual .makedepends-$pkgname $deps
975}
976
977# replace the md5sums in the APKBUILD
978checksum() {
979 local s files
980 [ -z "$source" ] && return 0
981 fetch
982 msg "Updating the md5sums in APKBUILD..."
983 for s in $source; do
984 files="$files ${s##*/}"
985 done
986 md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
987 sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
988 echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
989}
990
991stripbin() {
992 local bin
993 options_has "!strip" && return 0
994 cd "${subpkgdir:-$pkgdir}" || return 1
995 msg "Stripping binaries"
996 scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
997 | sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
998 | xargs -r strip
999}
1000
1001# simply list target apks
1002listpkg() {
1003 local i
1004 getpkgver || return 1
1005 for i in $pkgname $subpackages; do
1006 echo "${i%:*}-$pkgver-r$pkgrel.apk"
1007 done
1008}
1009
1010source_has() {
1011 local i
1012 for i in $source; do
1013 [ "$1" = "${i##*/}" ] && return 0
1014 done
1015 return 1
1016}
1017
1018subpackages_has() {
1019 local i
1020 for i in $subpackages; do
1021 [ "$1" = "${i%:*}" ] && return 0
1022 done
1023 return 1
1024}
1025
1026list_has() {
1027 local needle="$1"
1028 local i
1029 shift
1030 for i in $@; do
1031 [ "$needle" = "$i" ] && return 0
1032 [ "$needle" = "!$i" ] && return 1
1033 done
1034 return 1
1035}
1036
1037# same as list_has but we filter version info
1038deplist_has() {
1039 local needle="$1"
1040 local i
1041 shift
1042 for i in $@; do
1043 i=${i%%[<>=]*}
1044 [ "$needle" = "$i" ] && return 0
1045 [ "$needle" = "!$i" ] && return 1
1046 done
1047 return 1
1048}
1049
1050options_has() {
1051 list_has "$1" $options
1052}
1053
1054depends_has() {
1055 deplist_has "$1" $depends
1056}
1057
1058makedepends_has() {
1059 deplist_has "$1" $makedepends
1060}
1061
1062md5sums_has() {
1063 list_has "$1" $md5sums
1064}
1065
1066install_has() {
1067 list_has "$1" $install
1068}
1069
1070# install package after build
1071post_add() {
1072 getpkgver || return 1
1073 local pkgf="$PKGDEST/$1-$pkgver-r$pkgrel.apk"
1074 local deps i
1075 if ! subpackages_has $1 && [ "$1" != "$pkgname" ]; then
1076 die "$1 is not built by this APKBUILD"
1077 fi
1078 # recursively install dependencies that are provided by this APKBUILD
1079 deps=$($APK index "$pkgf" 2>/dev/null | awk -F: '$1=="D" { print $2 }')
1080 for i in $deps; do
1081 if subpackages_has $i || [ "$i" = "$pkgname" ]; then
1082 post_add $i || return 1
1083 fi
1084 done
1085 $SUDO $APK add --wait 30 -u "$pkgf" || die "Failed to install $1"
1086}
1087
1088installdeps() {
1089 local deps i
1090 sudo $APK add --wait 30 --repository "$abuildrepo" \
1091 --virtual .makedepends-$pkgname \
1092 $makedepends
1093}
1094
1095uninstalldeps (){
1096 sudo $APK del .makedepends-$pkgname
1097}
1098
1099all() {
1100 check_arch || return 0
1101 if up2date && [ -z "$force" ]; then
1102 msg "Package is up to date"
1103 else
1104 update_abuildrepo
1105 fi
1106}
1107
1108usage() {
1109 echo "$program $abuild_ver"
1110 echo "usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]"
1111 echo " [-s SRCDEST] [cmd] ..."
1112 echo " $program [-c] -n PKGNAME[-PKGVER]"
1113 echo "Options:"
1114 echo " -c Enable colored output"
1115 echo " -d Disable dependency checking"
1116 echo " -f Force specified cmd, even if they are already done"
1117 echo " -F Force run as root"
1118 echo " -h Show this help"
1119 echo " -i Install PKG after successul build"
1120 echo " -k Keep built packages, even if APKBUILD or sources are newer"
1121 echo " -m Disable colors (monochrome)"
1122 echo " -p Set package destination directory"
1123 echo " -P Set PKGDEST to REPODEST/<repo>, where repo is the parents dir name"
1124 echo " -q Quiet"
1125 echo " -r Install missing dependencies from system repository (using sudo)"
1126 echo " -R Recursively build and install missing dependencies (using sudo)"
1127 echo " -s Set source package destination directory"
1128 echo " -u Recursively build and upgrade all dependencies (using sudo)"
1129 echo ""
1130 echo "Commands:"
1131 echo " checksum Generate checksum to be included in APKBUILD"
1132 echo " fetch Fetch sources to \$SRCDEST and verify checksums"
1133 echo " sanitycheck Basic sanity check of APKBUILD"
1134 echo " md5check Check md5sums"
1135 echo " unpack Unpack sources to \$srcdir"
1136 echo " build Compile and install package into \$pkgdir"
1137 echo " listpkg List target packages"
1138 echo " package Create package in \$PKGDEST"
1139 echo " rootpkg Run '$0 build package' as fakeroot"
1140 echo " clean Remove temp build and install dirs"
1141 echo " cleanoldpkg Remove binary packages except current version"
1142 echo " cleanpkg Remove already built binary and source package"
1143 echo " cleancache Remove downloaded files from \$SRCDEST"
1144 echo " srcpkg Make a source package"
1145 echo " up2date Compare target and sources dates"
1146 echo " installdeps Install packages listed in makedepends and depends"
1147 echo " uninstalldeps Uninstall packages listed in makedepends and depends"
1148 echo ""
1149 exit 0
1150}
1151
1152APKBUILD="${APKBUILD:-./APKBUILD}"
1153unset force
1154unset recursive
1155while getopts "cdfFhi:kimnp:P:qrRs:u" opt; do
1156 case $opt in
1157 'c') default_colors
1158 color_opt="-c";;
1159 'd') nodeps=1;;
1160 'f') force="-f";;
1161 'F') forceroot="-F";;
1162 'h') usage;;
1163 'i') install_after="$install_after $OPTARG";;
1164 'k') keep="-k";;
1165 'm') monochrome
1166 color_opt="-m";;
1167 'n') die "Use newapkbuild to create new aports";;
1168 'p') PKGDEST=$OPTARG;;
1169 'P') REPODEST=$OPTARG;;
1170 'q') quiet="-q";;
1171 'r') install_deps="-r";;
1172 'R') recursive="-R";;
1173 's') SRCDEST=$OPTARG;;
1174 'u') upgrade="-u"
1175 recursive="-R";;
1176 esac
1177done
1178shift $(( $OPTIND - 1 ))
1179
1180# check so we are not root
1181if [ "$(whoami)" = "root" ] && [ -z "$FAKEROOTKEY" ]; then
1182 [ -z "$forceroot" ] && die "Do not run abuild as root"
1183 SUDO=
1184 FAKEROOT=
1185fi
1186
1187# find startdir
1188[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
1189APKBUILD=$(readlink -f "$APKBUILD")
1190
1191startdir="${APKBUILD%/*}"
1192srcdir=${srcdir:-"$startdir/src"}
1193pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
1194pkgrel=0
1195repo=${startdir%/*}
1196repo=${repo##*/}
1197
1198SRCDEST=${SRCDEST:-$startdir}
1199PKGDEST=${PKGDEST:-$startdir}
1200
1201cd "$startdir" || die
1202. "$APKBUILD"
1203
1204# If REPODEST is set then it will override the PKGDEST
1205if [ -n "$REPODEST" ]; then
1206 PKGDEST="$REPODEST/$repo"
1207fi
1208
1209# If we are handling a sub package then reset subpackages and install
1210if [ -n "$subpkgname" ]; then
1211 origsubpackages="$subpackages"
1212 subpackages=
1213 install=
1214fi
1215pkgdir="$pkgbasedir/$pkgname"
1216controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
1217
1218trap 'die "Aborted by user"' INT
1219set_xterm_title "abuild: $pkgname"
1220
1221if [ -z "$1" ]; then
1222 set all
1223fi
1224
1225while [ $# -gt 0 ]; do
1226 runpart $1
1227 shift
1228done
1229
1230for i in $install_after; do
1231 post_add $i
1232done
1233
1234cleanup
1235