projects/aports·blob v2.7 · refs

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