abuild.in 26.4 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1 2
#!/bin/sh

3
# script to build apk packages (light version of makepkg)
Natanael Copa's avatar
Natanael Copa committed
4 5 6 7 8 9 10
# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
#
# Distributed under GPL-2
#
# Depends on: busybox utilities, fakeroot, 
#

Natanael Copa's avatar
Natanael Copa committed
11 12
abuild_ver=@VERSION@
sysconfdir=@sysconfdir@
13
abuildrepo=@abuildrepo@
Natanael Copa's avatar
Natanael Copa committed
14
datadir=@datadir@
Natanael Copa's avatar
Natanael Copa committed
15

16
program=${0##*/}
17
abuild_path=$(readlink -f $0)
Natanael Copa's avatar
Natanael Copa committed
18 19

# defaults
20
BUILD_BASE="build-base"
21
SUDO=${SUDO:-"sudo"}
22
FAKEROOT=${FAKEROOT:-"fakeroot"}
23
APK=${APK:-apk}
24

Natanael Copa's avatar
Natanael Copa committed
25
# read config
Natanael Copa's avatar
Natanael Copa committed
26
ABUILD_CONF=${ABUILD_CONF:-"$sysconfdir/abuild.conf"}
Natanael Copa's avatar
Natanael Copa committed
27 28
[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"

29
default_colors() {
Natanael Copa's avatar
Natanael Copa committed
30 31 32 33 34 35
	NORMAL="\033[1;0m"
	STRONG="\033[1;1m"
	RED="\033[1;31m"
	GREEN="\033[1;32m"
	YELLOW="\033[1;33m"
	BLUE="\033[1;34m"
36 37 38 39 40 41 42 43 44 45 46 47 48 49
}

monochrome() {
	NORMAL=""
	STRONG=""
	RED=""
	GREEN=""
	YELLOW=""
	BLUE=""
}

#colors
if [ -n "$USE_COLORS" ]; then
    default_colors
Natanael Copa's avatar
Natanael Copa committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
fi	
	

# functions
msg() {
	local prompt="$GREEN>>>${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	[ -z "$quiet" ] && printf "${prompt} ${name}${fake}: $@\n" >&2
}

warning() {
	local prompt="${YELLOW}>>> WARNING:${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	printf "${prompt} ${name}${fake}: $@\n" >&2
}

error() {
	local prompt="${RED}>>> ERROR:${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	printf "${prompt} ${name}${fake}: $@\n" >&2
}
Natanael Copa's avatar
Natanael Copa committed
74 75

	
Linux User's avatar
Linux User committed
76 77
set_xterm_title() {
	if [ "$TERM" = xterm ]; then
78
		 printf "\033]0;$1\007" >&2
Linux User's avatar
Linux User committed
79 80 81 82 83
	fi
} 

cleanup() {
	set_xterm_title ""
84
	if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
85
		$SUDO $APK del $uninstall_after
86
	fi
Linux User's avatar
Linux User committed
87 88
}

Natanael Copa's avatar
Natanael Copa committed
89
die() {
Linux User's avatar
Linux User committed
90
	error "$@"
Linux User's avatar
Linux User committed
91
	cleanup
Natanael Copa's avatar
Natanael Copa committed
92 93 94
	exit 1
}

95 96
# check if apkbuild is basicly sane
sanitycheck() {
Natanael Copa's avatar
Natanael Copa committed
97
	local i
98
	msg "Checking sanity of $APKBUILD..."
99 100 101
	[ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
	[ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
	[ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
102
	if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
103
		$APK version --check -q "$pkgver" ||\
Natanael Copa's avatar
Natanael Copa committed
104 105
			die "$pkgver is not a valid version"
	fi
106
	[ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
107 108 109 110
	[ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
	[ -z "$url" ] && die "Missing url in APKBUILD"
	[ -z "$license" ] && die "Missing license in APKBULID"

Natanael Copa's avatar
Natanael Copa committed
111 112 113 114 115 116 117
	for i in $install; do
		[ -e "$startdir/$i" ] || die "install script $startdir/$i is missing"
	done
	
	[ -n "${triggers%%:*}" ] && [ ! -e "$startdir"/${triggers%%:*} ] \
		&& die "trigger script $startdir/${triggers%%:*} is missing"

118 119
	if [ -n "$source" ]; then
		for i in $source; do
Natanael Copa's avatar
Natanael Copa committed
120 121 122 123
			if install_has "$i"; then
				warning "You should not have \$install in source"
				continue
			fi
124
			md5sums_has ${i##*/} || die "${i##*/} is missing in md5sums"
Natanael Copa's avatar
Natanael Copa committed
125 126 127
			case "$i" in
				https://*) makedepends_has wget || die "wget must be in makedepends when source has https://" ;;
			esac
128 129
		done
	fi
Natanael Copa's avatar
Natanael Copa committed
130

131 132
	if [ -n "$md5sums" ]; then
		for i in $(echo "$md5sums" | awk '{ print $2 }'); do
Natanael Copa's avatar
Natanael Copa committed
133
			source_has $i || die "$i exists in md5sums but is missing in source"
134 135
		done
	fi
136

137 138 139
	# common spelling errors
	[ -n "$depend" ] && die "APKBUILD contains 'depend'. It should be depends"
	[ -n "$makedepend" ] && die "APKBUILD contains 'makedepend'. It should be makedepends"
Natanael Copa's avatar
Natanael Copa committed
140 141

	grep '^# Maintainer:' $APKBUILD >/dev/null || warning "No maintainer"
142 143

	makedepends_has 'g++' && warning "g++ should not be in makedepends"
144 145 146 147
	return 0
}

md5check() {
Natanael Copa's avatar
Natanael Copa committed
148
	local dummy f
149 150 151
	if [ -z "$source" ]; then
		return 0
	fi
152
	if [ -z "$md5sums" ]; then
153
		die "Use 'abuild checksum' to generate/update the checksum(s)"
154
	fi
155 156 157
	if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
		die "Number of md5sums does not correspond to number of sources"
	fi
158
	fetch || return 1
159
	msg "Checking md5sums..."
160
	cd "$srcdir" && echo "$md5sums" | md5sum -c 
Natanael Copa's avatar
Natanael Copa committed
161 162 163 164
}

uri_fetch() {
	local uri="$1"
165
	local d="${uri##*/}"	# $(basename $uri)
166 167 168 169
	local opts
	[ -n "$quiet" ] && opts="-q"
	[ -f "$SRCDEST/$d" ] && return 0

Natanael Copa's avatar
Natanael Copa committed
170 171 172 173 174
	# we need GNU wget for this
	case "$uri" in
		https://*) opts="--no-check-certificate";;
	esac
	
Natanael Copa's avatar
Natanael Copa committed
175
	mkdir -p "$SRCDEST"
176 177 178
	if [ -f "$SRCDEST/$d.part" ]; then
		msg "Partial download found. Trying to resume"
		opts="$opts -c"
Natanael Copa's avatar
Natanael Copa committed
179
	fi
Linux User's avatar
Linux User committed
180
	msg "Fetching $uri"
181 182
	wget $opts -O "$SRCDEST/$d.part" "$uri" \
		&& mv "$SRCDEST/$d.part" "$SRCDEST/$d"
Natanael Copa's avatar
Natanael Copa committed
183 184
}

185 186
is_remote() {
	case "$1" in
Natanael Copa's avatar
Natanael Copa committed
187
		http://*|ftp://*|https://*)
188 189 190 191 192
			return 0;;
	esac
	return 1
}

193 194 195 196 197
# try download from file from mirror first
uri_fetch_mirror() {
	local uri="$1"
	local d="${uri##*/}"	# $(basename $uri)
	if [ -n "$DISTFILES_MIRROR" ]; then
198 199 200 201 202
		if is_remote "$DISTFILES_MIRROR"; then
			uri_fetch "$DISTFILES_MIRROR"/$d && return 0
		else
			cp "$DISTFILES_MIRROR"/$d "$SRCDEST" && return 0
		fi
203 204 205 206
	fi
	uri_fetch "$uri"
}

207
default_fetch() {
Natanael Copa's avatar
Natanael Copa committed
208 209
	local s
	mkdir -p "$srcdir"
210 211
	for s in $source; do
		if is_remote "$s"; then
212
			uri_fetch_mirror "$s" || return 1
213 214 215 216
			ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
		else		
			ln -sf "$startdir/$s" "$srcdir/"
		fi
Natanael Copa's avatar
Natanael Copa committed
217 218 219
	done
}

220 221 222 223
fetch() {
	default_fetch
}

Natanael Copa's avatar
Natanael Copa committed
224
# unpack the sources
225
default_unpack() {
Natanael Copa's avatar
Natanael Copa committed
226
	local u
227
	md5check || return 1
Natanael Copa's avatar
Natanael Copa committed
228 229 230 231
	mkdir -p "$srcdir"
	for u in $source; do
		local s="$SRCDEST/${u##*/}"	# $(basename $s)
		case "$s" in
Natanael Copa's avatar
Natanael Copa committed
232
			*.tar.gz|*.tgz)
233
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
234 235
				tar -C "$srcdir" -zxf "$s" || return 1;;
			*.tar.bz2)
236
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
237
				tar -C "$srcdir" -jxf "$s" || return 1;;
238 239 240 241
			*.tar.lzma)
				msg "Unpacking $s..."
				unlzma -c "$s" | tar -C "$srcdir" -x  \
					|| return 1;;
Natanael Copa's avatar
Natanael Copa committed
242 243 244
			*.zip)
				msg "Unpacking $s..."
				unzip "$s" -d "$srcdir" || return 1;;
Natanael Copa's avatar
Natanael Copa committed
245 246 247 248
		esac
	done
}

249 250 251 252
unpack() {
	default_unpack
}

Natanael Copa's avatar
Natanael Copa committed
253 254
# cleanup source and package dir
clean() {
255
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
256
	rm -rf "$srcdir"
257
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
258 259 260 261 262 263
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
264 265 266 267
		if is_remote "$s"; then
			msg "Cleaning downloaded ${s##*/}..."
			rm -f "$SRCDEST/${s##*/}"
		fi
Natanael Copa's avatar
Natanael Copa committed
268 269 270 271 272
	done
}

cleanpkg() {
	local i
273
	getpkgver || return 1
274
	msg "Cleaning built packages..."
275
	for i in $pkgname $subpackages; do
276 277
		local p="${i%:*}-$pkgver-r$pkgrel"
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
278
			"$abuildrepo"/$p.apk
Natanael Copa's avatar
Natanael Copa committed
279
	done
280
	# remove given packages from index
Natanael Copa's avatar
Natanael Copa committed
281 282
}

283 284 285
# clean all packages except current
cleanoldpkg() {
	local i j
286
	getpkgver || return 1
287 288 289 290 291 292 293 294 295
	msg "Cleaning all packages except $pkgver-r$pkgrel..."
	for i in $pkgname $subpackages; do
		for j in "$PKGDEST"/${i%:*}-[0-9]*.apk; do
			[ "$j" != "$PKGDEST/${i%:*}-$pkgver-r$pkgrel.apk" ] \
				&& rm -f "$j"
		done
	done
	return 0
}
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

mkusers() {
	local i
	for i in $pkgusers; do
		if ! getent passwd $i >/dev/null; then
			msg "Creating user $i"
			$SUDO adduser -D -H $i || return 1
		fi
	done
	for i in $pkggroups; do
		if ! getent group $i >/dev/null; then
			msg "Creating group $i"
			$SUDO addgroup $i || return 1
		fi
	done
}


Natanael Copa's avatar
Natanael Copa committed
314 315
runpart() {
	local part=$1
316
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
317 318 319 320
	$part || die "$part failed"
}

# override those in your build script
321 322 323 324 325 326 327 328
getpkgver() {
	# this func is supposed to be overridden by volatile packages
	if [ "$pkgver" = "volatile" ]; then
		error "Please provide a getpkgver() function in your APKBUILD"
		return 1
	fi
}

Natanael Copa's avatar
Natanael Copa committed
329 330 331 332
prepare() {
	:
}

Natanael Copa's avatar
Natanael Copa committed
333
build() {
334
	:
Natanael Copa's avatar
Natanael Copa committed
335 336
}

337 338 339 340 341 342
# generate a simple tar.gz package of pkgdir
targz() {
	cd "$pkgdir" || return 1
	tar -czf "$PKGDEST"/$pkgname-$pkgver-r$pkgrel.tar.gz *
}

Natanael Copa's avatar
Natanael Copa committed
343 344 345 346 347 348 349 350 351
get_split_func() {
	# get the 'func' from "sub-pkg:func"
	local func=${1##*:}

	# get 'func' from "sub-pkg-func" if there was no :func
	[ "$func" = "$1" ] && func=${func##*-}
	echo $func
}

352
prepare_subpackages() {
Natanael Copa's avatar
Natanael Copa committed
353
	if [ -z "$subpackages" ]; then
354 355
		return 0
	fi
Natanael Copa's avatar
Natanael Copa committed
356 357
	local i
	cd "$startdir"
358
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
359 360
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
361
		msg "Running split function $func..."
362
		subpkgdir="$pkgbasedir/${i%:*}" subpkgname="${i%:*}" \
363
			$0 $func prepare_package || return 1
Natanael Copa's avatar
Natanael Copa committed
364 365 366
	done
}

367
prepare_metafiles() {
368
	getpkgver || return 1
369 370
	local name=${subpkgname:-$pkgname}
	[ -z "${name##* *}" ] && die "package name contains spaces"
371
	local dir=${subpkgdir:-$pkgdir}
372
	local pkg="$name-$pkgver-r$pkgrel.apk"
373
	local pkginfo="$controldir"/.PKGINFO
374
	local sub
Natanael Copa's avatar
Natanael Copa committed
375 376 377
	
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
378
	mkdir -p "$controldir"
Natanael Copa's avatar
Natanael Copa committed
379 380 381
	local builddate=$(date -u "+%s")
	local size=$(du -sk | awk '{print $1 * 1024}')

382
	echo "# Generated by $(basename $0) $abuild_ver" >"$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
383
	if [ -n "$FAKEROOTKEY" ]; then
384
		echo "# using $($FAKEROOT -v)" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
385
	fi
386 387
	echo "# $(date -u)" >> "$pkginfo"
	cat >> "$pkginfo" <<EOF
388
pkgname = $name
389
pkgver = $pkgver-r$pkgrel
Natanael Copa's avatar
Natanael Copa committed
390 391 392 393 394 395
pkgdesc = $pkgdesc
url = $url
builddate = $builddate
packager = ${PACKAGER:-"Unknown"}
size = $size
EOF
396 397
	local i deps
	deps="$depends"
398
	if [ "$pkgname" != "busybox" ] && ! depends_has busbox; then
Natanael Copa's avatar
Natanael Copa committed
399 400
		for i in $install ${triggers%%:*}; do
			if head -n 1 "$startdir/$i" | grep '^#!/bin/sh' >/dev/null ; then
401 402 403 404 405
				msg "Script found. busybox added as a dependency for $pkg"
				deps="$deps busybox"
				break
			fi
		done
406 407
	fi
	
Natanael Copa's avatar
Natanael Copa committed
408
	for i in $license; do
409
		echo "license = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
410 411
	done
	for i in $replaces; do
412
		echo "replaces = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
413
	done
414
	for i in $deps; do
415
		echo "depend = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
416 417
	done
	for i in $conflicts; do
418
		echo "conflict = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
419 420
	done
	for i in $provides; do
421
		echo "provides = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
422 423
	done
	for i in $backup; do
424
		echo "backup = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
425
	done
Natanael Copa's avatar
Natanael Copa committed
426 427 428
	if [ -n "$triggers" ]; then
		echo "triggers = ${triggers#*:}" >> "$pkginfo"
	fi
Natanael Copa's avatar
Natanael Copa committed
429 430

	local metafiles=".PKGINFO"
Natanael Copa's avatar
Natanael Copa committed
431
	for i in $install ${triggers%%:*}; do
432 433
		script=${i#$name}
		case "$script" in
Natanael Copa's avatar
Natanael Copa committed
434
			.pre-install|.post-install|.pre-upgrade|.post-upgrade|.pre-deinstall|.post-deinstall|.trigger)
435 436
				msg "Adding $script"
				;;
Natanael Copa's avatar
Natanael Copa committed
437
			*) 	error "$script: Invalid install/trigger script"
438 439 440
				return 1
				;;
		esac
Natanael Copa's avatar
Natanael Copa committed
441
		cp "$startdir/$i" "$controldir/$script" || return 1
442
		chmod +x "$controldir/$script"
443 444
		metafiles="$metafiles $script"
	done
445
	echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
446
}
447

448 449 450
prepare_tracedeps() {
	local dir=${subpkgdir:-$pkgdir}
	options_has "!tracedeps" && return 0
451 452
	find -name '*.so' -o -name '*.so.[0-9]*' | sed 's:.*/::' \
		>"$controldir"/.provides-so
453
	scanelf -Rn "$dir" | awk -F "\ " '$1 == "ET_DYN" || $1 == "ET_EXEC" {print $2}'  \
454 455 456
		| sed 's:,:\n:g' | sort | uniq \
	| while read i; do
		# only add files that are not self provided
457 458
		grep "^$i$" "$controldir"/.provides-so >/dev/null \
			|| echo $i >> "$controldir"/.needs-so
459
	done
Natanael Copa's avatar
Natanael Copa committed
460 461
}

462
prepare_package() {
463
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
464
	stripbin
465
	prepare_metafiles && prepare_tracedeps
466 467 468 469 470 471 472 473
}

pkginfo_val() {
	local key="$1"
	local file="$2"
	awk -F ' = ' "\$1 == \"$key\" {print \$2}" "$file"
}

474 475 476
trace_apk_deps() {
	local name="$1"
	local dir="$2"
477 478
	local i j found autodeps=
	msg "Tracing dependencies for $name..."
479 480 481 482 483 484
	# add pkgconfig if usr/lib/pkgconfig is found
	if [ -d "$pkgbasedir"/$name/usr/lib/pkgconfig ] \
			&& ! grep -q '^depend = pkgconfig' "$dir"/.PKGINFO; then
		msg "Added pkgconfig as dependency"
		echo "depend = pkgconfig" >> "$dir"/.PKGINFO
	fi
485
	for i in $(cat "$dir"/.needs-so 2>/dev/null); do
486
		found=
487
		# first check if its provide by same apkbuild
488
		for j in "$dir"/../.control.*/.provides-so; do
489
			grep -w "$i" "$j" >/dev/null || continue
490
			found=${j%/.provides-so}
491
			found=${found##*/.control.}
492
			break
493 494 495
		done
		# check apk db if not provided by a subpackage
		if [ -z "$found" ]; then
496
			found=$($APK info -q -W /lib/$i /usr/lib/$i)
497 498 499 500 501
		fi
		if [ -z "$found" ]; then
			error "Could not find dependency for $i"
			return 1
		fi
502
		if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
503 504 505
			warning "You can remove '$found' from depends"
			continue
		fi
506 507
		list_has "$found" $autodeps || autodeps="$autodeps $found"
		msg "Added '$found' as dependency as it has $i"
508 509 510 511 512 513 514 515
	done
	[ -z "$autodeps" ] && return 0
	echo "# automatically detected:" >> "$dir"/.PKGINFO
	for i in $autodeps; do
		echo "depend = $i" >> "$dir"/.PKGINFO
	done
}

516 517
create_apks() {
	local file
518
	getpkgver || return 1
519
	for file in "$pkgbasedir"/.control.*/.PKGINFO; do
520 521 522
		local dir="${file%/.PKGINFO}"
		local name=$(pkginfo_val pkgname $file)
		local ver=$(pkginfo_val pkgver $file)
523
		local apk=$name-$ver.apk
524
		local datadir="$pkgbasedir"/$name
525 526

		trace_apk_deps "$name" "$dir" || return 1
527
		msg "Creating $apk..."
528
		(
529 530
		cd "$datadir"
		# data.tar.gz
531 532 533 534 535 536
		set -- *
		if [ "$1" = '*' ]; then
			touch .dummy
			set -- .dummy
		fi
		tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
537 538 539 540 541 542

		# append the hash for data.tar.gz
		local sha256=$(sha256sum "$dir"/data.tar.gz | cut -f1 -d' ')
		echo "datahash = $sha256" >> "$dir"/.PKGINFO

		# control.tar.gz
543
		cd "$dir"
544 545
		tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
			| gzip -9 > control.tar.gz
546
		abuild-sign -q control.tar.gz || exit 1
Natanael Copa's avatar
Natanael Copa committed
547

548 549 550
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
551 552 553
	done
}

554
update_abuildrepo() {
555
	if ! apk_up2date || [ -n "$force" ]; then
556
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
557
			&& prepare && mkusers && rootpkg || return 1
558
	fi
559

560
	local apk
561 562
	mkdir -p "$abuildrepo" || return 1
	cd "$abuildrepo"
563 564 565 566 567 568 569 570 571

	# remove broken links
	for apk in *.apk; do
		if [ -L "$apk" ] && [ ! -f "$apk" ]; then
			rm -f "$apk"
		fi
	done

	# create links for this package
572
	for apk in $(listpkg); do
573
		ln -sf "$PKGDEST"/$apk "$abuildrepo"/$apk
574 575
	done

576
	msg "Updating the cached abuild repository index..."
577 578 579 580 581
	local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
	local oldindex=
	if [ -f APKINDEX.tar.gz ]; then
		oldindex="--index APKINDEX.tar.gz"
	fi
582
	$APK index $oldindex --output APKINDEX.tar.gz.unsigned \
583 584
		--description "$repo $(cd $startdir && git describe)" \
		*.apk || exit 1
585 586 587
	msg "Signing the index..."
	abuild-sign -q APKINDEX.tar.gz.unsigned || exit 1
	mv APKINDEX.tar.gz.unsigned APKINDEX.tar.gz
Natanael Copa's avatar
Natanael Copa committed
588
	chmod 644 APKINDEX.tar.gz
589 590
}

591
# predefined splitfunc doc
592
default_doc() {
593
	depends="$depends_doc"
594
	install="$install_doc"
Natanael Copa's avatar
Natanael Copa committed
595
	triggers="$triggers_doc"
Natanael Copa's avatar
Natanael Copa committed
596
	local i
597
	for i in doc man info html sgml licenses gtk-doc; do
598 599 600
		if [ -d "$pkgdir/usr/share/$i" ]; then
			mkdir -p "$subpkgdir/usr/share"
			mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
Natanael Copa's avatar
Natanael Copa committed
601 602
		fi
	done
603 604 605
	
	rm -f "$subpkgdir/usr/share/info/dir"

606 607 608
#	# compress info and man pages
#	find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
#		-o -name '*.[1-9]' \) -exec gzip {} \;
609 610 611 612

	# remove if empty, ignore error (not empty)
	rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null

Natanael Copa's avatar
Natanael Copa committed
613
#	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
614 615 616
	return 0
}

617 618 619 620
doc() {
	default_doc
}

621
# predefined splitfunc mod
622
default_mod() {
623
	depends="$kernel $depends_mod"
624
	install="$install_mod"
Natanael Copa's avatar
Natanael Copa committed
625
	for i in firmware modules; do
626 627 628
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
629
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
630 631 632 633
		fi
	done
}

634 635 636 637
mod() {
	default_mod
}

638
# predefined splitfunc dev
639
default_dev() {
640
	local i
641
	depends="$pkgname $depends_dev"
642
	install="$install_dev"
Natanael Copa's avatar
Natanael Copa committed
643
	triggers="$triggers_dev"
644 645 646 647
	for i in $origsubpackages; do
		[ "${i%:*}" = "$subpkgname" ] || depends="$depends ${i%:*}"
	done
		
648
	cd "$pkgdir" || return 0
649 650 651 652 653
	for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
			usr/share/gettext usr/bin/*-config	\
			$(find -name include -type d) 		\
			$(find usr/ -name '*.[acho]' -o -name '*.la' \
			2>/dev/null); do
654 655
		if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
			d="$subpkgdir/${i%/*}"	# dirname $i
Natanael Copa's avatar
Natanael Copa committed
656
			mkdir -p "$d"
657
			mv "$pkgdir/$i" "$d"
658
			rmdir "$pkgdir/${i%/*}" 2>/dev/null
Natanael Copa's avatar
Natanael Copa committed
659 660
		fi
	done
Natanael Copa's avatar
Natanael Copa committed
661
	return 0
Natanael Copa's avatar
Natanael Copa committed
662 663
}

664 665 666 667
dev() {
	default_dev
}

668 669 670 671
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

Natanael Copa's avatar
Natanael Copa committed
672 673
# build and package in fakeroot
rootpkg() {
674 675 676 677
	local do_build=build
	cd "$startdir"
	if is_function package; then
		build || return 1
678
		do_build=package
679
	fi
Natanael Copa's avatar
Natanael Copa committed
680
	cd "$startdir"
681
	[ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
682
	$FAKEROOT -- "$abuild_path" $color_opt $do_build \
683 684
		prepare_subpackages \
		prepare_package \
685
		create_apks
Natanael Copa's avatar
Natanael Copa committed
686 687 688
}

srcpkg() {
689
	getpkgver || return 1
690
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
691
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
692 693 694 695 696
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
697
	msg "Creating source package $p.src.tar.gz..."
698
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
699 700
}

701
# check if package is up to date
702
apk_up2date() {
703
	getpkgver || return 1
704
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
705
	local i s
Natanael Copa's avatar
Natanael Copa committed
706
	cd "$startdir"
707 708 709 710 711
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

712
	for i in $source APKBUILD; do
713 714 715 716 717 718
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
719 720 721 722 723 724 725
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

726
abuildindex_up2date() {
727
	local i apk
728
	getpkgver || return 1
729 730
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
731
		[ "$abuildrepo"/APKINDEX.tar.gz -nt "$abuildrepo"/$apk ] || return 1
732 733 734 735 736
	done
	return 0
}

up2date() {
737 738 739 740 741 742 743
	apk_up2date && abuildindex_up2date
}

# rebuild package and abuildrepo index if needed
abuildindex() {
	up2date && return 0
	update_abuildrepo
744 745
}

746 747 748 749 750 751 752
# source all APKBUILDs and output:
#  1) origin of package
#  2) all dependencies
# the output is i in a format easy parseable for awk
depparse_aports() {
	# lets run this in a subshell since we source all APKBUILD here
	(
753 754
	aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
	for i in $aportsdir/*/APKBUILD; do
755 756 757 758
		pkgname=
		subpackages=
		depends=
		makedepends=
759
		. $i
760
		dir=${i%/APKBUILD}
761
		deps=
762
		# filter out conflicts from deps and version info
763 764 765 766
		for j in $depends $makedepends; do
			case "$j" in
				!*) continue;;
			esac
767
			deps="$deps ${j%%[<>=]*}"
768
		done
769
		for j in $pkgname $subpackages; do
770
			echo "o ${j%%:*} $dir"
771
			set -- $deps
772 773 774 775 776 777 778
			echo -n "d ${j%%:*} $1"
			shift
			while [ $# -gt 0 ]; do
				echo -n ",$1"
				shift
			done
			echo
779 780
		done
	done
781
	)
782 783
}

784
deptrace() {
785 786 787
	local deps= i=
	# strip versions from deps
	for i in "$@"; do
788
		deps="$deps ${i%%[<>=]*}"
789
	done
790
	[ -z "$deps" ] && return 0
791 792 793
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
794
			$APK info -q | sort |  sed 's/^/i /'
795
		fi
796
	) | awk -v pkgs="$deps" '
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821

	function depgraph(pkg,	a, i) {
		if (visited[pkg])
			return 0;
		visited[pkg] = 1;
		split(deps[pkg], a, ",");
		for (i in a)
			depgraph(a[i]);
		print pkg ":" origin[pkg];

	}

	$1 == "i" { visited[$2] = 1 }
	$1 == "o" { origin[$2] = $3 }
	$1 == "d" { deps[$2] = $3 }
	END {
		split(pkgs, pkgarray);
		for (i in pkgarray)
			depgraph(pkgarray[i]);
	}
	'
}

# build and install dependencies
builddeps() {
822
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
823
	local filtered_deps= conflicts=
824
	[ -n "$nodeps" ] && return 0
825
	msg "Analyzing dependencies..."
826

827 828 829
	# add depends unless it is a subpackage or package itself
	for i in $BUILD_BASE $depends $makedepends; do
		[ "$pkgname" = "${i%%[<>=]*}" ] && continue
830
		subpackages_has ${i%%[<>=]*} || deps="$deps $i"
831 832
	done

833
	installed_deps=$($APK info -e $deps)
834
	# find which deps are missing
835
	for i in $deps; do
836
		if [ "${i#\!}" != "$i" ]; then
837
			list_has ${i#\!} $installed_deps \
838
				&& conflicts="$conflicts ${i#\!}"
839
		elif ! deplist_has $i $installed_deps || [ -n "$upgrade" ]; then
840 841 842 843
			missing="$missing $i"
		fi
	done

844 845 846 847 848 849 850 851 852 853
	if [ -n "$conflicts" ]; then
		die "Conflicting package(s) installed:$conflics"
	fi
	
	if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
		# if we dont have any missing deps we are done now
		[ -z "$missing" ] && return 0
		error "Missing dependencies: $missing Use -r to autoinstall or -R to build"
		return 1
	fi
854

855
	uninstall_after=".makedepends-$pkgname $uninstall_after"
856
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
857 858
		# make a --simluate run first to detect missing deps
		# apk-tools --virtual is no goot at reporting those.
859
		$SUDO $APK add --repository "$abuildrepo" \
860 861
			--wait 30 \
			--simulate --quiet $deps || return 1
862
		$SUDO $APK add --repository "$abuildrepo" \
863
			--wait 30 \
864 865
			--virtual .makedepends-$pkgname $deps \
			&& return 0
866
	fi
867 868
	
	[ -z "$recursive" ] && return 1
869 870 871

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
872
		local m=$($APK search --repository "$abuildrepo" ${i%%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
873
		if [ -z "$m" ]; then
874 875 876
			missing="$missing $i"
		fi
	done
877 878
	
	for i in $(deptrace $missing); do
879 880 881
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
882 883 884 885 886 887 888 889 890 891

		# ignore if dependency is in other repo
		[ -d "$dir" ] || continue
		
		# break cricular deps
		list_has $pkg $ABUILD_VISITED && continue
		export ABUILD_VISITED="$ABUILD_VISITED $pkg"

		msg "Entering $dir"
		cd "$dir" && $0 $forceroot $keep $quiet $install_deps \
892
			$recursive $upgrade $color_opt abuildindex || return 1
893
	done
894
	$SUDO $APK add -u --repository "$abuildrepo" \
895
		--wait 30 \
896
		--virtual .makedepends-$pkgname $deps
897