abuild.in 24.3 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
apkcache=@apkcache@
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

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

28

Natanael Copa's avatar
Natanael Copa committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#colors
if [ -n "$USE_COLORS" ]; then
	NORMAL="\033[1;0m"
	STRONG="\033[1;1m"
	RED="\033[1;31m"
	GREEN="\033[1;32m"
	YELLOW="\033[1;33m"
	BLUE="\033[1;34m"
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
61 62

	
Linux User's avatar
Linux User committed
63 64
set_xterm_title() {
	if [ "$TERM" = xterm ]; then
65
		 printf "\033]0;$1\007" >&2
Linux User's avatar
Linux User committed
66 67 68 69 70
	fi
} 

cleanup() {
	set_xterm_title ""
71
	if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
72
		$SUDO apk del $uninstall_after
73
	fi
Linux User's avatar
Linux User committed
74 75
}

Natanael Copa's avatar
Natanael Copa committed
76
die() {
Linux User's avatar
Linux User committed
77
	error "$@"
Linux User's avatar
Linux User committed
78
	cleanup
Natanael Copa's avatar
Natanael Copa committed
79 80 81
	exit 1
}

82 83
# check if apkbuild is basicly sane
sanitycheck() {
Natanael Copa's avatar
Natanael Copa committed
84
	local i
85
	msg "Checking sanity of $APKBUILD..."
86 87 88
	[ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
	[ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
	[ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
89 90 91 92
	if [ "$pkgver" != "volatile" ]; then
		apk version --check -q "$pkgver" ||\
			die "$pkgver is not a valid version"
	fi
93 94 95 96 97
	[ -z "$pkgrel" ] && warning "Missing pkgrel in APKBUILD. Using pkgrel=0"
	[ -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
98 99 100 101 102 103 104
	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"

105 106
	if [ -n "$source" ]; then
		for i in $source; do
Natanael Copa's avatar
Natanael Copa committed
107 108 109 110
			if install_has "$i"; then
				warning "You should not have \$install in source"
				continue
			fi
111
			md5sums_has ${i##*/} || die "${i##*/} is missing in md5sums"
Natanael Copa's avatar
Natanael Copa committed
112 113 114
			case "$i" in
				https://*) makedepends_has wget || die "wget must be in makedepends when source has https://" ;;
			esac
115 116
		done
	fi
Natanael Copa's avatar
Natanael Copa committed
117

118 119
	if [ -n "$md5sums" ]; then
		for i in $(echo "$md5sums" | awk '{ print $2 }'); do
Natanael Copa's avatar
Natanael Copa committed
120
			source_has $i || die "$i exists in md5sums but is missing in source"
121 122
		done
	fi
123

124 125 126
	# 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
127 128

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

	makedepends_has 'g++' && warning "g++ should not be in makedepends"
131 132 133 134
	return 0
}

md5check() {
Natanael Copa's avatar
Natanael Copa committed
135
	local dummy f
136 137 138
	if [ -z "$source" ]; then
		return 0
	fi
139
	if [ -z "$md5sums" ]; then
140
		die "Use 'abuild checksum' to generate/update the checksum(s)"
141
	fi
142 143 144
	if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
		die "Number of md5sums does not correspond to number of sources"
	fi
145
	fetch || return 1
146
	msg "Checking md5sums..."
147
	cd "$srcdir" && echo "$md5sums" | md5sum -c 
Natanael Copa's avatar
Natanael Copa committed
148 149 150 151 152
}

uri_fetch() {
	local uri="$1"
	local d="${s##*/}"	# $(basename $s)
153 154 155 156
	local opts
	[ -n "$quiet" ] && opts="-q"
	[ -f "$SRCDEST/$d" ] && return 0

Natanael Copa's avatar
Natanael Copa committed
157 158 159 160 161 162
	
	# we need GNU wget for this
	case "$uri" in
		https://*) opts="--no-check-certificate";;
	esac
	
Natanael Copa's avatar
Natanael Copa committed
163
	mkdir -p "$SRCDEST"
164 165 166
	if [ -f "$SRCDEST/$d.part" ]; then
		msg "Partial download found. Trying to resume"
		opts="$opts -c"
Natanael Copa's avatar
Natanael Copa committed
167
	fi
Linux User's avatar
Linux User committed
168
	msg "Fetching $uri"
169 170
	wget $opts -O "$SRCDEST/$d.part" "$uri" \
		&& mv "$SRCDEST/$d.part" "$SRCDEST/$d"
Natanael Copa's avatar
Natanael Copa committed
171 172
}

173 174
is_remote() {
	case "$1" in
Natanael Copa's avatar
Natanael Copa committed
175
		http://*|ftp://*|https://*)
176 177 178 179 180
			return 0;;
	esac
	return 1
}

Natanael Copa's avatar
Natanael Copa committed
181 182 183
fetch() {
	local s
	mkdir -p "$srcdir"
184 185 186 187 188 189 190
	for s in $source; do
		if is_remote "$s"; then
			uri_fetch "$s" || return 1
			ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
		else		
			ln -sf "$startdir/$s" "$srcdir/"
		fi
Natanael Copa's avatar
Natanael Copa committed
191 192 193 194 195 196
	done
}

# unpack the sources
unpack() {
	local u
197
	md5check || return 1
Natanael Copa's avatar
Natanael Copa committed
198 199 200 201
	mkdir -p "$srcdir"
	for u in $source; do
		local s="$SRCDEST/${u##*/}"	# $(basename $s)
		case "$s" in
Natanael Copa's avatar
Natanael Copa committed
202
			*.tar.gz|*.tgz)
203
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
204 205
				tar -C "$srcdir" -zxf "$s" || return 1;;
			*.tar.bz2)
206
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
207
				tar -C "$srcdir" -jxf "$s" || return 1;;
208 209 210 211
			*.tar.lzma)
				msg "Unpacking $s..."
				unlzma -c "$s" | tar -C "$srcdir" -x  \
					|| return 1;;
Natanael Copa's avatar
Natanael Copa committed
212 213 214
			*.zip)
				msg "Unpacking $s..."
				unzip "$s" -d "$srcdir" || return 1;;
Natanael Copa's avatar
Natanael Copa committed
215 216 217 218 219 220
		esac
	done
}

# cleanup source and package dir
clean() {
221
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
222
	rm -rf "$srcdir"
223
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
224 225 226 227 228 229
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
230 231 232 233
		if is_remote "$s"; then
			msg "Cleaning downloaded ${s##*/}..."
			rm -f "$SRCDEST/${s##*/}"
		fi
Natanael Copa's avatar
Natanael Copa committed
234 235 236 237 238
	done
}

cleanpkg() {
	local i
239
	msg "Cleaning built packages..."
240
	for i in $pkgname $subpackages; do
241 242
		local p="${i%:*}-$pkgver-r$pkgrel"
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
243
			"$apkcache"/$p.apk
Natanael Copa's avatar
Natanael Copa committed
244
	done
245
	# remove given packages from index
Natanael Copa's avatar
Natanael Copa committed
246 247
}

248 249 250 251 252 253 254 255 256 257 258 259
# clean all packages except current
cleanoldpkg() {
	local i j
	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
}
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

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
278 279
runpart() {
	local part=$1
280
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
281 282 283 284
	$part || die "$part failed"
}

# override those in your build script
Natanael Copa's avatar
Natanael Copa committed
285 286 287 288
prepare() {
	:
}

Natanael Copa's avatar
Natanael Copa committed
289
build() {
290
	:
Natanael Copa's avatar
Natanael Copa committed
291 292
}

Natanael Copa's avatar
Natanael Copa committed
293 294 295 296 297 298 299 300 301
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
}

302
prepare_subpackages() {
Natanael Copa's avatar
Natanael Copa committed
303
	if [ -z "$subpackages" ]; then
304 305
		return 0
	fi
Natanael Copa's avatar
Natanael Copa committed
306 307
	local i
	cd "$startdir"
308
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
309 310
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
311
		msg "Running split function $func..."
312
		subpkgdir="$pkgbasedir/${i%:*}" subpkgname="${i%:*}" \
313
			$0 $func prepare_package || return 1
Natanael Copa's avatar
Natanael Copa committed
314 315 316
	done
}

317
prepare_metafiles() {
318 319
	local name=${subpkgname:-$pkgname}
	[ -z "${name##* *}" ] && die "package name contains spaces"
320
	local dir=${subpkgdir:-$pkgdir}
321
	local pkg="$name-$pkgver-r$pkgrel.apk"
322
	local pkginfo="$controldir"/.PKGINFO
323
	local sub
Natanael Copa's avatar
Natanael Copa committed
324 325 326
	
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
327
	mkdir -p "$controldir"
Natanael Copa's avatar
Natanael Copa committed
328 329 330
	local builddate=$(date -u "+%s")
	local size=$(du -sk | awk '{print $1 * 1024}')

331
	echo "# Generated by $(basename $0) $abuild_ver" >"$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
332
	if [ -n "$FAKEROOTKEY" ]; then
333
		echo "# using $($FAKEROOT -v)" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
334
	fi
335 336
	echo "# $(date -u)" >> "$pkginfo"
	cat >> "$pkginfo" <<EOF
337
pkgname = $name
338
pkgver = $pkgver-r$pkgrel
Natanael Copa's avatar
Natanael Copa committed
339 340 341 342 343 344
pkgdesc = $pkgdesc
url = $url
builddate = $builddate
packager = ${PACKAGER:-"Unknown"}
size = $size
EOF
345 346
	local i deps
	deps="$depends"
347
	if [ "$pkgname" != "busybox" ] && ! depends_has busbox; then
Natanael Copa's avatar
Natanael Copa committed
348 349
		for i in $install ${triggers%%:*}; do
			if head -n 1 "$startdir/$i" | grep '^#!/bin/sh' >/dev/null ; then
350 351 352 353 354
				msg "Script found. busybox added as a dependency for $pkg"
				deps="$deps busybox"
				break
			fi
		done
355 356
	fi
	
Natanael Copa's avatar
Natanael Copa committed
357
	for i in $license; do
358
		echo "license = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
359 360
	done
	for i in $replaces; do
361
		echo "replaces = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
362
	done
363
	for i in $deps; do
364
		echo "depend = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
365 366
	done
	for i in $conflicts; do
367
		echo "conflict = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
368 369
	done
	for i in $provides; do
370
		echo "provides = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
371 372
	done
	for i in $backup; do
373
		echo "backup = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
374
	done
Natanael Copa's avatar
Natanael Copa committed
375 376 377
	if [ -n "$triggers" ]; then
		echo "triggers = ${triggers#*:}" >> "$pkginfo"
	fi
Natanael Copa's avatar
Natanael Copa committed
378 379

	local metafiles=".PKGINFO"
Natanael Copa's avatar
Natanael Copa committed
380
	for i in $install ${triggers%%:*}; do
381 382
		script=${i#$name}
		case "$script" in
Natanael Copa's avatar
Natanael Copa committed
383
			.pre-install|.post-install|.pre-upgrade|.post-upgrade|.pre-deinstall|.post-deinstall|.trigger)
384 385
				msg "Adding $script"
				;;
Natanael Copa's avatar
Natanael Copa committed
386
			*) 	error "$script: Invalid install/trigger script"
387 388 389
				return 1
				;;
		esac
Natanael Copa's avatar
Natanael Copa committed
390
		cp "$startdir/$i" "$controldir/$script" || return 1
391
		chmod +x "$controldir/$script"
392 393
		metafiles="$metafiles $script"
	done
394
	echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
395
}
396

397 398 399
prepare_tracedeps() {
	local dir=${subpkgdir:-$pkgdir}
	options_has "!tracedeps" && return 0
400 401
	find -name '*.so' -o -name '*.so.[0-9]*' | sed 's:.*/::' \
		>"$controldir"/.provides-so
402
	scanelf -Rn "$dir" | awk -F "\ " '$1 == "ET_DYN" || $1 == "ET_EXEC" {print $2}'  \
403 404 405
		| sed 's:,:\n:g' | sort | uniq \
	| while read i; do
		# only add files that are not self provided
406 407
		grep "^$i$" "$controldir"/.provides-so >/dev/null \
			|| echo $i >> "$controldir"/.needs-so
408
	done
Natanael Copa's avatar
Natanael Copa committed
409 410
}

411
prepare_package() {
412
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
413
	stripbin
414
	prepare_metafiles
415
	prepare_tracedeps
416 417 418 419 420 421 422 423
}

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

424 425 426
trace_apk_deps() {
	local name="$1"
	local dir="$2"
427 428
	local i j found autodeps=
	msg "Tracing dependencies for $name..."
429 430 431 432 433 434
	# 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
435
	for i in $(cat "$dir"/.needs-so 2>/dev/null); do
436
		found=
437
		# first check if its provide by same apkbuild
438
		for j in "$dir"/../.control.*/.provides-so; do
439
			grep -w "$i" "$j" >/dev/null || continue
440
			found=${j%/.provides-so}
441
			found=${found##*/.control.}
442
			break
443 444 445 446 447 448 449 450 451
		done
		# check apk db if not provided by a subpackage
		if [ -z "$found" ]; then
			found=$(apk info -q -W /lib/$i /usr/lib/$i)
		fi
		if [ -z "$found" ]; then
			error "Could not find dependency for $i"
			return 1
		fi
452
		if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
453 454 455
			warning "You can remove '$found' from depends"
			continue
		fi
456 457
		list_has "$found" $autodeps || autodeps="$autodeps $found"
		msg "Added '$found' as dependency as it has $i"
458 459 460 461 462 463 464 465
	done
	[ -z "$autodeps" ] && return 0
	echo "# automatically detected:" >> "$dir"/.PKGINFO
	for i in $autodeps; do
		echo "depend = $i" >> "$dir"/.PKGINFO
	done
}

466 467
create_apks() {
	local file
468
	for file in "$pkgbasedir"/.control.*/.PKGINFO; do
469 470 471
		local dir="${file%/.PKGINFO}"
		local name=$(pkginfo_val pkgname $file)
		local ver=$(pkginfo_val pkgver $file)
472
		local apk=$name-$ver.apk
473
		local datadir="$pkgbasedir"/$name
474 475

		trace_apk_deps "$name" "$dir" || return 1
476
		msg "Creating $apk..."
477
		(
478 479
		cd "$datadir"
		# data.tar.gz
480 481 482 483 484 485
		set -- *
		if [ "$1" = '*' ]; then
			touch .dummy
			set -- .dummy
		fi
		tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
486 487 488 489 490 491

		# 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
492
		cd "$dir"
493 494
		tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
			| gzip -9 > control.tar.gz
495
		abuild-sign -q control.tar.gz || exit 1
Natanael Copa's avatar
Natanael Copa committed
496

497 498 499
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
500 501 502
	done
}

503
apkcache() {
504
	if ! apk_up2date || [ -n "$force" ]; then
505
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
506
			&& prepare && mkusers && rootpkg || return 1
507
	fi
508

509
	local apk
510
	mkdir -p "$apkcache" || return 1
511 512 513 514 515 516 517 518 519 520
	cd "$apkcache"

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

	# create links for this package
521
	for apk in $(listpkg); do
522
		ln -sf "$PKGDEST"/$apk "$apkcache"/$apk
523 524
	done

525
	msg "Updating the cached abuild repository index..."
526 527 528 529 530
	local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
	local oldindex=
	if [ -f APKINDEX.tar.gz ]; then
		oldindex="--index APKINDEX.tar.gz"
	fi
531 532 533
	apk index $oldindex --output APKINDEX.tar.gz.unsigned \
		--description "$repo $(cd $startdir && git describe)" \
		*.apk || exit 1
534 535 536
	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
537
	chmod 644 APKINDEX.tar.gz
538 539
}

540
# predefined splitfunc doc
541
default_doc() {
542
	depends="$depends_doc"
543
	install="$install_doc"
Natanael Copa's avatar
Natanael Copa committed
544
	triggers="$triggers_doc"
Natanael Copa's avatar
Natanael Copa committed
545
	local i
546
	for i in doc man info html sgml licenses gtk-doc; do
547 548 549
		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
550 551
		fi
	done
552 553 554
	
	rm -f "$subpkgdir/usr/share/info/dir"

555 556 557
#	# compress info and man pages
#	find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
#		-o -name '*.[1-9]' \) -exec gzip {} \;
558 559 560 561

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

Natanael Copa's avatar
Natanael Copa committed
562
#	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
563 564 565
	return 0
}

566 567 568 569
doc() {
	default_doc
}

570
# predefined splitfunc mod
571
default_mod() {
572
	depends="$kernel $depends_mod"
573
	install="$install_mod"
Natanael Copa's avatar
Natanael Copa committed
574
	for i in firmware modules; do
575 576 577
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
578
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
579 580 581 582
		fi
	done
}

583 584 585 586
mod() {
	default_mod
}

587
# predefined splitfunc dev
588
default_dev() {
589
	local i
590
	depends="$pkgname $depends_dev"
591
	install="$install_dev"
Natanael Copa's avatar
Natanael Copa committed
592
	triggers="$triggers_dev"
593 594 595 596
	for i in $origsubpackages; do
		[ "${i%:*}" = "$subpkgname" ] || depends="$depends ${i%:*}"
	done
		
597
	cd "$pkgdir" || return 0
598 599 600 601 602
	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
603 604
		if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
			d="$subpkgdir/${i%/*}"	# dirname $i
Natanael Copa's avatar
Natanael Copa committed
605
			mkdir -p "$d"
606
			mv "$pkgdir/$i" "$d"
607
			rmdir "$pkgdir/${i%/*}" 2>/dev/null
Natanael Copa's avatar
Natanael Copa committed
608 609
		fi
	done
Natanael Copa's avatar
Natanael Copa committed
610
	return 0
Natanael Copa's avatar
Natanael Copa committed
611 612
}

613 614 615 616
dev() {
	default_dev
}

617 618 619 620
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

Natanael Copa's avatar
Natanael Copa committed
621 622
# build and package in fakeroot
rootpkg() {
623 624 625 626
	local do_build=build
	cd "$startdir"
	if is_function package; then
		build || return 1
627
		do_build=package
628
	fi
Natanael Copa's avatar
Natanael Copa committed
629
	cd "$startdir"
630 631 632 633
	[ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
	$FAKEROOT "$abuild_path" $do_build \
		prepare_subpackages \
		prepare_package \
634
		create_apks
Natanael Copa's avatar
Natanael Copa committed
635 636 637
}

srcpkg() {
638
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
639
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
640 641 642 643 644
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
645
	msg "Creating source package $p.src.tar.gz..."
646
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
647 648
}

649
# check if package is up to date
650
apk_up2date() {
651
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
652
	local i s
Natanael Copa's avatar
Natanael Copa committed
653
	cd "$startdir"
654 655 656 657 658
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

659
	for i in $source APKBUILD; do
660 661 662 663 664 665
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
666 667 668 669 670 671 672
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

673 674 675 676
cache_up2date() {
	local i apk
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
677
		[ "$apkcache"/APKINDEX.tar.gz -nt "$apkcache"/$apk ] || return 1
678 679 680 681 682 683 684 685
	done
	return 0
}

up2date() {
	apk_up2date && cache_up2date
}

686 687 688 689 690 691 692 693 694 695 696 697 698
# 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
	(
	aportsdir=$(realpath ${APKBUILD%/APKBUILD}/../..)
	for i in $aportsdir/*/*/APKBUILD; do
		pkgname=
		subpackages=
		depends=
		makedepends=
699
		. $i
700
		dir=${i%/APKBUILD}
701
		deps=
702
		# filter out conflicts from deps and version info
703 704 705 706
		for j in $depends $makedepends; do
			case "$j" in
				!*) continue;;
			esac
707
			deps="$deps ${j%[<>=]*}"
708
		done
709
		for j in $pkgname $subpackages; do
710
			echo "o ${j%%:*} $dir"
711
			set -- $deps
712 713 714 715 716 717 718
			echo -n "d ${j%%:*} $1"
			shift
			while [ $# -gt 0 ]; do
				echo -n ",$1"
				shift
			done
			echo
719 720
		done
	done
721
	)
722 723
}

724
deptrace() {
725 726 727 728 729
	local deps= i=
	# strip versions from deps
	for i in "$@"; do
		deps="$deps ${i%[<>=]*}"
	done
730
	[ -z "$deps" ] && return 0
731 732 733
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
Natanael Copa's avatar
abuild:  
Natanael Copa committed
734
			apk info -q | sort |  sed 's/^/i /'
735
		fi
736
	) | awk -v pkgs="$deps" '
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761

	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() {
762 763
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
764
	[ -n "$nodeps" ] && return 0
765
	msg "Analyzing dependencies..."
766 767 768 769
	deps="$BUILD_BASE $makedepends"

	# add depends unless it is a subpackage
	for i in $depends; do
770
		subpackages_has ${i%[<>=]*} || deps="$deps $i"
771 772
	done

773
	installed_deps=$(apk info -e $deps)
774
	# find which deps are missing
775
	for i in $deps; do
776
		if [ "${i#\!}" != "$i" ]; then
777
			list_has ${i#\!} $installed_deps \
778
				&& die "Conflicting package ${i#\!} is installed."
779
		elif ! deplist_has $i $installed_deps; then
780 781 782 783 784 785 786
			if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
				die "Missing dependency $i. Use -r to autoinstall or -R to build"
			fi
			missing="$missing $i"
		fi
	done

787 788
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
789

790
	uninstall_after=".makedepends-$pkgname $uninstall_after"
791
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
792
		$SUDO apk add --repository "$apkcache" \
793 794
			--virtual .makedepends-$pkgname $deps \
			&& return 0
795
	fi
796 797
	
	[ -z "$recursive" ] && return 1
798 799 800

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
801
		local m=$(apk search --repository "$apkcache" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
802
		if [ -z "$m" ]; then
803 804 805
			missing="$missing $i"
		fi
	done
806 807
	
	for i in $(deptrace $missing); do
808 809 810 811
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
		msg "Entering $dir"
812
		cd "$dir" && $0 -k -r apkcache || return 1
813
	done
814
	$SUDO apk add -u --repository "$apkcache" \
815
		--virtual .makedepends-$pkgname $deps
816 817
}

818
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
819 820
checksum() {
	local s files
821
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
822
	fetch
823
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
824 825 826 827
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
828 829
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
830 831
}

832
stripbin() {
833
	local bin
834
	options_has "!strip" && return 0
835 836
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
837 838 839
	scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
		| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
		| xargs -r strip
840 841
}

842 843 844 845 846 847 848 849
# simply list target apks
listpkg() {
	local i 
	for i in $pkgname $subpackages; do
		echo "${i%:*}-$pkgver-r$pkgrel.apk"
	done
}

Natanael Copa's avatar
Natanael Copa committed
850 851 852 853 854 855 856 857
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:  
Natanael Copa committed
858 859 860 861 862 863 864 865
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

866 867 868 869 870 871 872 873 874 875 876
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

877 878 879 880 881 882 883 884 885 886 887 888 889
# same as list_has but we filter version info
deplist_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		i=${i%[<>=]*}
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

890 891 892 893
options_has() {
	list_has "$1" $options
}

894
depends_has() {
895
	deplist_has "$1" $depends
896 897
}

Natanael Copa's avatar
Natanael Copa committed
898
makedepends_has() {
899
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
900 901
}

Natanael Copa's avatar
Natanael Copa committed
902 903 904 905
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
906 907 908 909
install_has() {
	list_has "$1" $install
}

Natanael Copa's avatar
abuild:  
Natanael Copa committed
910 911 912 913 914 915 916 917 918 919 920 921 922 923
# install package after build
post_add() {
	local pkgf="$PKGDEST/$1-$pkgver-r$pkgrel.apk"
	local deps i
	if ! subpackages_has $1 && [ "$1" != "$pkgname" ]; then
		die "$1 is not built by this APKBUILD"
	fi
	# recursively install dependencies that are provided by this APKBUILD
	deps=$(apk index "$pkgf" 2>/dev/null | awk -F: '$1=="D" { print $2 }')
	for i in $deps; do
		if subpackages_has $i || [ "$i" = "$pkgname" ]; then
			post_add $i || return 1
		fi
	done
924
	$SUDO apk add -u "$pkgf" || die "Failed to install $1"
Natanael Copa's avatar
abuild:  
Natanael Copa committed
925 926
}

927
installdeps() {
928
	local deps i
929
	sudo apk add --repository "$apkcache" --virtual .makedepends-$pkgname \
930
		$makedepends
931 932 933
}

uninstalldeps (){
934
	sudo apk del .makedepends-$pkgname
935
}
936 937 938 939 940 941 942 943 944

all() {
	if up2date && [ -z "$force" ]; then
		msg "Package is up to date"
	else
		apkcache
	fi
}

Natanael Copa's avatar
Natanael Copa committed
945
usage() {
946 947
	echo "$program $abuild_ver"
	echo "usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]"
948
	echo "              [-s SRCDEST] [cmd] ..."
949
	echo "       $program [-c] -n PKGNAME[-PKGVER]"
Natanael Copa's avatar
Natanael Copa committed
950
	echo "Options:"
951
	echo " -d  Disable dependency checking"
Natanael Copa's avatar
Natanael Copa committed
952
	echo " -f  Force specified cmd, even if they are already done"
953
	echo " -F  Force run as root"
954 955
	echo " -h  Show this help"
	echo " -i  Install PKG after successul build"
956
	echo " -k  Keep built packages, even if APKBUILD or sources are newer"
957
	echo " -p  Set package destination directory"
958
	echo " -P  Set PKGDEST to REPODEST/<repo>, where repo is the parents dir name" 
Natanael Copa's avatar
Natanael Copa committed
959
	echo " -q  Quiet"
960 961
	echo " -r  Install missing dependencies from system repository (using sudo)"
	echo " -R  Recursively build and install missing dependencies (using sudo)"
962
	echo " -s  Set source package destination directory"
963
	echo " -u  Recursively build and upgrade all dependencies (using sudo)"
Natanael Copa's avatar
Natanael Copa committed
964 965
	echo ""
	echo "Commands:"
966
	echo "  checksum    Generate checksum to be included in APKBUILD"
967 968 969 970 971
	echo "  fetch       Fetch sources to \$SRCDEST and verify checksums"
	echo "  sanitycheck Basic sanity check of APKBUILD"
	echo "  md5check    Check md5sums"
	echo "  unpack      Unpack sources to \$srcdir"
	echo "  build       Compile and install package into \$pkgdir"
972
	echo "  listpkg     List target packages"
973 974 975
	echo "  package     Create package in \$PKGDEST"
	echo "  rootpkg     Run '$0 build package' as fakeroot"
	echo "  clean       Remove temp build and install dirs"
976
	echo "  cleanoldpkg Remove binary packages except current version"
977 978 979 980
	echo "  cleanpkg    Remove already built binary and source package"
	echo "  cleancache  Remove downloaded files from \$SRCDEST"
	echo "  srcpkg      Make a source package"
	echo "  up2date     Compare target and sources dates"
981 982
	echo "  installdeps Install packages listed in makedepends and depends"
	echo "  uninstalldeps Uninstall packages listed in makedepends and depends"
Natanael Copa's avatar
Natanael Copa committed
983 984 985 986 987
	echo ""
	exit 0
}

APKBUILD="${APKBUILD:-./APKBUILD}"
988 989
unset force
unset recursive
990
while getopts "dfFhi:kinp:P:qrRs:u" opt; do
Natanael Copa's avatar
Natanael Copa committed
991
	case $opt in
992
		'd') nodeps=1;;
Natanael Copa's avatar
Natanael Copa committed
993
		'f') force=1;;
994
		'F') forceroot=1;;
995 996
		'h') usage;;
		'i') install_after="$install_after $OPTARG";;
997
		'k') keep=1;;
998
		'n') die "Use newapkbuild to create new aports";;
999
		'p') PKGDEST=$OPTARG;;
1000
		'P') REPODEST=$OPTARG;;
Natanael Copa's avatar
Natanael Copa committed
1001
		'q') quiet=1;;
1002 1003
		'r') install_deps=1;;
		'R') recursive=1;;
1004
		's') SRCDEST=$OPTARG;;
1005 1006
		'u') upgrade=1
		     recursive=1;;
Natanael Copa's avatar
Natanael Copa committed
1007 1008 1009 1010
	esac
done
shift $(( $OPTIND - 1 ))

1011 1012 1013 1014 1015 1016 1017
# check so we are not root
if [ "$(whoami)" = "root" ] && [ -z "$FAKEROOTKEY" ]; then
	[ -z "$forceroot" ] && die "Do not run abuild as root"
	SUDO=
	FAKEROOT=
fi

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
# find startdir
[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
APKBUILD=$(readlink -f "$APKBUILD")

startdir="${APKBUILD%/*}"
srcdir=${srcdir:-"$startdir/src"}
pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
pkgrel=0
repo=${startdir%/*}
repo=${repo##*/}

SRCDEST=${SRCDEST:-$startdir}
PKGDEST=${PKGDEST:-$startdir}

cd "$startdir" || die
. "$APKBUILD"

1035 1036 1037 1038 1039
# If REPODEST is set then it will override the PKGDEST
if [ -n "$REPODEST" ]; then
	PKGDEST="$REPODEST/$repo"
fi

1040
# If we are handling a sub package then reset subpackages and install
1041
if [ -n "$subpkgname" ]; then
1042
	origsubpackages="$subpackages"
1043
	subpackages=
1044
	install=
1045
fi
1046
pkgdir="$pkgbasedir/$pkgname"
1047
controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
Natanael Copa's avatar
Natanael Copa committed
1048 1049

trap 'die "Aborted by user"' INT
Linux User's avatar
Linux User committed
1050
set_xterm_title "abuild: $pkgname"
Natanael Copa's avatar
Natanael Copa committed
1051 1052

if [ -z "$1" ]; then
1053
	set all
Natanael Copa's avatar
Natanael Copa committed
1054 1055 1056 1057 1058 1059
fi

while [ $# -gt 0 ]; do
	runpart $1
	shift
done
1060 1061

for i in $install_after; do
Natanael Copa's avatar
abuild:  
Natanael Copa committed
1062
	post_add $i
1063 1064
done

Linux User's avatar
Linux User committed
1065
cleanup
Natanael Copa's avatar
Natanael Copa committed
1066