abuild.in 65.3 KB
Newer Older
A. Wilcox's avatar
A. Wilcox committed
1
#!/bin/sh -e
Natanael Copa's avatar
Natanael Copa committed
2

3
# abuild - build apk packages (light version of makepkg)
4
# Copyright (c) 2008-2015 Natanael Copa <ncopa@alpinelinux.org>
5
# Copyright (c) 2016 Timo Teräs <timo.teras@iki.fi>
Natanael Copa's avatar
Natanael Copa committed
6
7
8
9
#
# Distributed under GPL-2
#

10
program_version=@VERSION@
Natanael Copa's avatar
Natanael Copa committed
11
sysconfdir=@sysconfdir@
Natanael Copa's avatar
Natanael Copa committed
12
datadir=@datadir@
Natanael Copa's avatar
Natanael Copa committed
13

14
abuild_path=$(readlink -f $0)
Natanael Copa's avatar
Natanael Copa committed
15

16
17
18
19
20
21
if ! [ -f "$datadir/functions.sh" ]; then
	echo "$datadir/functions.sh: not found" >&2
	exit 1
fi
. "$datadir/functions.sh"

Natanael Copa's avatar
Natanael Copa committed
22
# defaults
23
24
: ${FAKEROOT:="fakeroot"}
: ${SUDO_APK:="abuild-apk"}
25
: ${APK:="/sbin/apk"}
26
27
: ${ADDUSER:="abuild-adduser"}
: ${ADDGROUP:="abuild-addgroup"}
28
: ${ABUILD_FETCH:="abuild-fetch"}
29

30
apk_opt_wait="--wait 30"
31

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
32
33
umask 022

34
35
36
37
38
# run optional log command for remote logging
logcmd() {
	${ABUILD_LOG_CMD:-true} "$@"
	return 0
}
Natanael Copa's avatar
Natanael Copa committed
39

40
# we override the default msg, warning and error as we want the pkgname
Natanael Copa's avatar
Natanael Copa committed
41
msg() {
42
	[ -n "$quiet" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
43
44
45
	local prompt="$GREEN>>>${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
46
47
48
	printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
}

Natanael Copa's avatar
Natanael Copa committed
49
50
51
52
warning() {
	local prompt="${YELLOW}>>> WARNING:${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
53
54
55
	printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
}

Natanael Copa's avatar
Natanael Copa committed
56
57
58
59
error() {
	local prompt="${RED}>>> ERROR:${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
60
	printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
61
	logcmd "ERROR: $pkgname: $1"
62
63
}

64
65
66
67
cross_creating() {
	test "$CHOST" != "$CTARGET" -a -n "$CBUILDROOT"
}

68
69
70
71
cross_compiling() {
	test "$CBUILD" != "$CHOST" -a -n "$CBUILDROOT"
}

72
want_check() {
73
	[ -n "$ABUILD_BOOTSTRAP" ] && return 1
74
75
76
77
78
	cross_compiling && return 1
	options_has "!check" && return 1
	return 0
}

Linux User's avatar
Linux User committed
79
cleanup() {
80
	local i=
81
	[ -z "$subpkgdir" ] && set_xterm_title ""
Natanael Copa's avatar
Natanael Copa committed
82
83
	if [ -n "$keep_build" ]; then
		return 0
84
	fi
85
86
	for i; do
		case $i in
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
87
88
89
90
91
		bldroot)
			if [ "$BUILD_ROOT" ]; then
				msg "Cleaning up build chroot"
				abuild-rmtemp "$BUILD_ROOT"
			fi;;
92
93
94
95
96
		pkgdir) msg "Cleaning up pkgdir"; rm -rf "$pkgbasedir";;
		srcdir) msg "Cleaning up srcdir"; rm -rf "$srcdir";;
		deps)
			if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
				msg "Uninstalling dependencies..."
97
				undeps
98
99
100
101
			fi
			;;
		esac
	done
Linux User's avatar
Linux User committed
102
103
}

Natanael Copa's avatar
Natanael Copa committed
104
die() {
105
	trap - EXIT
Linux User's avatar
Linux User committed
106
	error "$@"
107
	cleanup $ERROR_CLEANUP
Natanael Copa's avatar
Natanael Copa committed
108
109
110
	exit 1
}

111
112
113
114
spell_error() {
	die "APKBUILD contains '$1'. It should be '$2'"
}

115
116
117
118
print_version() {
	msg "$program $program_version"
}

119
# check if apkbuild is basicly sane
120
default_sanitycheck() {
121
	local i= j= suggestion=
122
	msg "Checking sanity of $APKBUILD..."
123
124
125
	[ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
	[ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
	[ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
126
	if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
127
		$APK version --check --quiet "$pkgver" ||\
Natanael Copa's avatar
Natanael Copa committed
128
129
			die "$pkgver is not a valid version"
	fi
130
	[ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
131
132
	[ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
	[ -z "$url" ] && die "Missing url in APKBUILD"
A. Wilcox's avatar
A. Wilcox committed
133
	[ -z "$license" ] && die "Missing license in APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
134
135
136
	if [ $(echo "$pkgdesc" | wc -c) -gt 128 ]; then
		die "pkgdesc is too long"
	fi
137

Natanael Copa's avatar
Natanael Copa committed
138
139
	if [ -n "$replaces_priority" ] \
		&& ! echo $replaces_priority | egrep -q '^[0-9]+$'; then
140
141
		die "replaces_priority must be a number"
	fi
142
143
144
145
146
147

	if [ -n "$provider_priority" ] \
		&& ! echo $provider_priority | egrep -q '^[0-9]+$'; then
		die "provider_priority must be a number"
	fi

148
149
150
	# check so no package names starts with -
	for i in $pkgname $subpackages; do
		case $i in
151
		-*) die "${i%%:*} is not a valid package name";;
152
153
154
		esac
	done

Natanael Copa's avatar
Natanael Copa committed
155
	for i in $install; do
156
157
		local n="${i%.*}"
		local suff="${i##*.}"
158
159
160
161
162
		case "$suff" in
		pre-install|post-install|pre-upgrade|post-upgrade|pre-deinstall|post-deinstall);;
		*) die "$i: unknown install script suffix"
		esac
		if ! subpackages_has "$n" && [ "$n" != "$pkgname" ]; then
163
			die "$i: install script does not match pkgname or any subpackage"
164
		fi
165
		[ -e "$startdir/$i" ] || die "install script $i is missing"
166
167
168
169
170
171
		for j in chown chmod chgrp; do
			if grep -q $j "$startdir"/$i; then
				warning "$i: found $j"
				warning2 "Permissions should be fixed in APKBUILD package()"
			fi
		done
Natanael Copa's avatar
Natanael Copa committed
172
	done
173

174
	for i in $triggers; do
175
176
		local f="${i%=*}"
		local p="${f%.trigger}"
177
		[ "$f" = "$i" ] && die "$f: triggers must contain '='"
178
179
180
181
		[ "$p" = "$f" ] && die "$f: triggers scripts must have .trigger suffix"
		if ! subpackages_has "$p" && [ "$p" != "$pkgname" ]; then
			die "$p: trigger script does not match pkgname or any subpackage"
		fi
Natanael Copa's avatar
Natanael Copa committed
182

183
184
185
186
187
		if source_has "$f"; then
			warning "You should not have \$triggers in source"
			continue
		fi

188
189
		[ -e "$startdir"/$f ] || die "trigger script $f is missing"
	done
190
191
	if [ -n "$source" ]; then
		for i in $source; do
Natanael Copa's avatar
Natanael Copa committed
192
193
194
195
			if install_has "$i"; then
				warning "You should not have \$install in source"
				continue
			fi
Natanael Copa's avatar
Natanael Copa committed
196
			case "$i" in
197
				*::*) i=${i%%::*};;
198
				https://*) makedepends_has wget && warning "wget no longer need to be in makedepends when source has https://" ;;
Natanael Copa's avatar
Natanael Copa committed
199
			esac
200
201
			list_has ${i##*/} $md5sums $sha256sums $sha512sums \
				|| die "${i##*/} is missing in checksums"
202
203
204
205
206
207
208
209
210
211

			# verify that our source does not have git tag version
			# name as tarball (typicallly github)
			if is_remote "$i" && [ "${i#*::}" = "$i" ]; then
				case ${i##*/} in
				v$pkgver.tar.*|$pkgver.tar.*)
					die "source ${i##*/} needs to be renamed to avoid possible collisions"
					;;
				esac
			fi
212
213
		done
	fi
Natanael Copa's avatar
Natanael Copa committed
214

215
216
217
218
219
220
221
	# verify that things listed in checksum also is listed in source
	local algo=
	for algo in md5 sha256 sha512; do
		eval set -- \$${algo}sums
		while [ $# -gt 1 ]; do
			local file="$2"
			shift 2
222
			source_has $file || die "$file exists in ${algo}sums but is missing in \$source"
223
		done
224
	done
225

226
	# common spelling errors
227
228
229
230
231
	[ -n "$depend" ] && spell_error depend depends
	[ -n "$makedepend" ] && spell_error makedepend makedepends
	[ -n "$pkguser" ] && spell_error pkguser pkgusers
	[ -n "$pkggroup" ] && spell_error pkggroup pkggroups
	[ -n "$subpackage" ] && spell_error subpackage subpackages
232
	[ -n "$checkdepend" ] && spell_error checkdepend checkdepends
Natanael Copa's avatar
Natanael Copa committed
233

234
	check_maintainer || die "Provide a valid RFC822 maintainer address"
235
	check_license || warning "Please use valid SPDX license identifiers found at: https://spdx.org/licenses"
236

237
	check_depends_dev || warning "depends_dev found but no development subpackage found"
238
	check_secfixes_comment || return 1
239

240
	makedepends_has 'g++' && ! options_has toolchain && warning "g++ should not be in makedepends"
241

Max Rees's avatar
Max Rees committed
242
243
	is_function package || die "Missing package() function in APKBUILD"

244
	if ! options_has "!check" && [ -n "$REQUIRE_CHECK" ]; then
Max Rees's avatar
Max Rees committed
245
246
		is_function check \
			|| die "Testsuites (abuild check) are required or need to be explicitly disabled!"
247
248
	fi

249
250
	check_provides || die "provides must not contain $pkgname"

251
252
253
	return 0
}

254
255
256
257
sanitycheck() {
	default_sanitycheck
}

258
259
sumcheck() {
	local algo="$1" sums="$2"
260
	local dummy f endreturnval originalparams origin file
261
262
263

	# get number of checksums
	set -- $sums
264
	local numsums="$(( $# / 2 ))"
265
266
267
268

	set -- $source
	if [ $# -ne $numsums ]; then
		die "Number of ${algo}sums($numsums) does not correspond to number of sources($#)"
269
	fi
270
	fetch || return 1
271
	msg "Checking ${algo}sums..."
Natanael Copa's avatar
Natanael Copa committed
272
	cd "$srcdir" || return 1
Max Rees's avatar
Max Rees committed
273
274
	IFS="
"
275
	endreturnval=0
276
	for src in $sums; do
277
		origin=$1; shift
278
		if ! echo "$src" | ${algo}sum -c; then
279
			endreturnval=1
280
			is_remote $origin || continue
281

Max Rees's avatar
Max Rees committed
282
			local csum="$(printf '%s' "$src" | awk '{ print substr($0, 1, 8) }' )"
283
284
285
			local file="$SRCDEST/$(filename_from_uri $origin)"

			echo "Because the remote file above failed the ${algo}sum check it will be renamed."
286
			echo "Rebuilding will cause it to re-download which in some cases may fix the problem."
287
288
			echo "Renaming: ${file##*/} to ${file##*/}.$csum"
			mv "$file" "$file.$csum"
289
290
291
292
		fi
	done
	unset IFS
	return $endreturnval
Natanael Copa's avatar
Natanael Copa committed
293
294
}

295
296
297
298
299
300
301
302
303
# for compatibility
md5check() {
	warning "'md5check' is deprecated. Use 'verify' instead"
	sumcheck md5 "$md5sums"
}

# verify checksums
verify() {
	local verified=false algo=
304
	for algo in sha512 sha256 sha1 md5; do
305
306
307
308
309
310
311
		local sums=
		eval sums=\"\$${algo}sums\"
		if [ -z "$sums" ] || [ -z "$source" ]; then
			continue
		fi
		sumcheck "$algo" "$sums" || return 1
		verified=true
312
		break
313
314
315
316
317
318
319
	done
	if [ -n "$source" ] && ! $verified; then
		die "Use 'abuild checksum' to generate/update the checksum(s)"
	fi
	return 0
}

Natanael Copa's avatar
Natanael Copa committed
320
321
# verify upstream sources
sourcecheck() {
322
323
324
325
	local uri
	for uri in $source; do
		is_remote $uri || continue
		case "$uri" in
326
327
328
		*::*)
			uri=${uri##*::}
			;;
329
		esac
330
		wget --spider -q "$uri" || return 1
Natanael Copa's avatar
Natanael Copa committed
331
	done
332
	return 0
Natanael Copa's avatar
Natanael Copa committed
333
}
334

Natanael Copa's avatar
Natanael Copa committed
335
336
337
uri_fetch() {
	local uri="$1"
	mkdir -p "$SRCDEST"
338
	msg "Fetching $uri"
339
	$ABUILD_FETCH -d "$SRCDEST" "$uri"
Natanael Copa's avatar
Natanael Copa committed
340
341
}

342
is_remote() {
343
	case "${1#*::}" in
344
		http://*|ftp://*|https://*)
345
346
347
348
349
			return 0;;
	esac
	return 1
}

350
351
352
353
354
355
356
357
358
filename_from_uri() {
	local uri="$1"
	local filename="${uri##*/}"  # $(basename $uri)
	case "$uri" in
	*::*) filename=${uri%%::*};;
	esac
	echo "$filename"
}

359
360
361
362
# try download from file from mirror first
uri_fetch_mirror() {
	local uri="$1"
	if [ -n "$DISTFILES_MIRROR" ]; then
363
		if is_remote "$DISTFILES_MIRROR"; then
364
365
			uri_fetch "$DISTFILES_MIRROR"/$(filename_from_uri $uri)\
				&& return 0
366
		else
367
368
			cp "$DISTFILES_MIRROR"/$(filename_from_uri $uri) \
				"$SRCDEST" && return 0
369
		fi
370
371
372
373
	fi
	uri_fetch "$uri"
}

374
375
376
377
378
379
380
381
382
383
384
385
symlinksrc() {
	local s
	mkdir -p "$srcdir"
	for s in $source; do
		if is_remote "$s"; then
			ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
		else
			ln -sf "$startdir/$s" "$srcdir/"
		fi
	done
}

386
default_fetch() {
Natanael Copa's avatar
Natanael Copa committed
387
388
	local s
	mkdir -p "$srcdir"
389
390
	for s in $source; do
		if is_remote "$s"; then
391
			uri_fetch_mirror "$s" || return 1
392
			ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
393
		else
394
395
			ln -sf "$startdir/$s" "$srcdir/"
		fi
Natanael Copa's avatar
Natanael Copa committed
396
397
398
	done
}

399
400
401
402
fetch() {
	default_fetch
}

Natanael Copa's avatar
Natanael Copa committed
403
404
# verify that all init.d scripts are openrc runscripts
initdcheck() {
405
	local i line
Natanael Copa's avatar
Natanael Copa committed
406
407
	for i in $source; do
		case $i in
408
409
410
411
412
413
414
415
416
417
418
		*.initd) line=$(head -n 1 "$srcdir"/$i);;
		*) continue ;;
		esac

		case "$line" in
		*sbin/openrc-run)
			;;
		*sbin/runscript)
			warning "$i is not an openrc #!/sbin/openrc-run"
			;;
		*)	error "$i is not an openrc #!/sbin/openrc-run"
Natanael Copa's avatar
Natanael Copa committed
419
420
421
			return 1
			;;
		esac
422
	done
Natanael Copa's avatar
Natanael Copa committed
423
424
}

Natanael Copa's avatar
Natanael Copa committed
425
# unpack the sources
426
default_unpack() {
Natanael Copa's avatar
Natanael Copa committed
427
	local u
428
429
	verify || return 1
	initdcheck || return 1
Natanael Copa's avatar
Natanael Copa committed
430
	mkdir -p "$srcdir"
431
	local gunzip="$(command -v pigz || echo gunzip)"
432
	[ $gunzip = "/usr/bin/pigz" ] && gunzip="$gunzip -d"
Natanael Copa's avatar
Natanael Copa committed
433
	for u in $source; do
434
435
436
437
438
439
		local s
		if is_remote "$u"; then
			s="$SRCDEST/$(filename_from_uri $u)"
		else
			s="$startdir/$u"
		fi
Natanael Copa's avatar
Natanael Copa committed
440
		case "$s" in
441
442
443
			*.tar)
				msg "Unpacking $s..."
				tar -C "$srcdir" -xf "$s" || return 1;;
Natanael Copa's avatar
Natanael Copa committed
444
			*.tar.gz|*.tgz)
445
				msg "Unpacking $s..."
446
				$gunzip -c "$s" | tar -C "$srcdir" -f - -x || return 1;;
Natanael Copa's avatar
Natanael Copa committed
447
			*.tar.bz2)
448
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
449
				tar -C "$srcdir" -jxf "$s" || return 1;;
450
451
452
			*.tar.lz)
				msg "Unpacking $s..."
				tar -C "$srcdir" --lzip -xf "$s" || return 1;;
453
454
			*.tar.lzma)
				msg "Unpacking $s..."
A. Wilcox's avatar
A. Wilcox committed
455
				unlzma -T 0 -c "$s" | tar -C "$srcdir" -f - -x  \
456
					|| return 1;;
457
458
			*.tar.xz)
				msg "Unpacking $s..."
A. Wilcox's avatar
A. Wilcox committed
459
				unxz --threads=0 -c "$s" | tar -C "$srcdir" -f - -x || return 1;;
Natanael Copa's avatar
Natanael Copa committed
460
461
			*.zip)
				msg "Unpacking $s..."
462
				unzip -n -q "$s" -d "$srcdir" || return 1;;
Natanael Copa's avatar
Natanael Copa committed
463
464
465
466
		esac
	done
}

467
468
469
470
unpack() {
	default_unpack
}

Natanael Copa's avatar
Natanael Copa committed
471
472
# cleanup source and package dir
clean() {
473
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
474
	rm -rf "$srcdir"
475
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
476
477
478
479
480
481
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
482
		if is_remote "$s"; then
483
484
485
			s=$(filename_from_uri $s)
			msg "Cleaning downloaded $s ..."
			rm -f "$SRCDEST/$s"
486
		fi
Natanael Copa's avatar
Natanael Copa committed
487
488
489
	done
}

490
491
492
493
494
495
496
subpkg_unset() {
	unset subpkgname subpkgsplit subpkgarch
}

subpkg_set() {
	subpkgname=${1%%:*}

497
	local _splitarch="${1#*:}"
498
499
500
501
502
503
504
505
	[ "$_splitarch" = "$1" ] && _splitarch=""

	subpkgsplit=${_splitarch%%:*}
	[ -z "$subpkgsplit" ] && subpkgsplit="${subpkgname##*-}"

	subpkgarch=${_splitarch#*:}
	if [ "$subpkgarch" = "$_splitarch" -o -z "$subpkgarch" ]; then
		case "$subpkgname" in
A. Wilcox's avatar
A. Wilcox committed
506
		*-doc | *-lang | *-lang-* | *-openrc) subpkgarch="noarch" ;;
507
508
509
510
511
		*) subpkgarch="$pkgarch" ;;
		esac
	fi
}

Natanael Copa's avatar
Natanael Copa committed
512
513
cleanpkg() {
	local i
514
	getpkgver || return 1
515
	msg "Cleaning built packages..."
516
517
518
	rm -f "$REPODEST/$repo/src/$pkgname-$pkgver-r$pkgrel.src.tar.gz"
	for i in $allpackages; do
		subpkg_set "$i"
Max Rees's avatar
Max Rees committed
519
520
		[ "$subpkgarch" = "noarch" ] && subpkgarch="$CARCH"
		rm -f "$REPODEST/$repo/$subpkgarch/$subpkgname-$pkgver-r$pkgrel.apk"
Natanael Copa's avatar
Natanael Copa committed
521
	done
522
523
	subpkg_unset

524
	# remove given packages from index
525
	update_abuildrepo_index
Natanael Copa's avatar
Natanael Copa committed
526
527
}

528
529
530
# clean all packages except current
cleanoldpkg() {
	local i j
531
	getpkgver || return 1
532
	msg "Cleaning all packages except $pkgver-r$pkgrel..."
533
534
535
536
	for i in $allpackages; do
		subpkg_set "$i"
		for j in "$REPODEST"/$repo/*/$subpkgname-[0-9]*.apk ; do
			[ "${j##*/}" = "$subpkgname-$pkgver-r$pkgrel.apk" ] \
537
				&& continue
538
			rm -f "$j"
539
540
		done
	done
541
	subpkg_unset
542
	update_abuildrepo_index
543
544
	return 0
}
545
546
547

mkusers() {
	local i
548
549
550
551
552
553
	for i in $pkggroups; do
		if ! getent group $i >/dev/null; then
			msg "Creating group $i"
			$ADDGROUP -S $i || return 1
		fi
	done
554
555
	for i in $pkgusers; do
		if ! getent passwd $i >/dev/null; then
556
			local gopt=
557
			msg "Creating user $i"
558
559
560
			if getent group $i >/dev/null; then
				gopt="-G $i"
			fi
561
			$ADDUSER -S -D -H $gopt $i || return 1
562
563
564
565
		fi
	done
}

Natanael Copa's avatar
Natanael Copa committed
566
567
# helper to update config.sub to a recent version
update_config_sub() {
568
	find . -name config.sub | (local changed=false; while read f; do
569
570
		if ! ./$f armv6-alpine-linux-muslgnueabihf 2>/dev/null; then
			msg "Updating $f"
571
572
573
			cp "$datadir"/${f##*/} "$f" || return 1
			changed=true
		else
574
			msg "No update needed for $f"
575
		fi
576
	done; $changed)
Natanael Copa's avatar
Natanael Copa committed
577
}
578

579
580
# helper to update config.guess to a recent version
update_config_guess() {
581
	find . -name config.guess | (local changed=false; while read f; do
582
		if grep -q aarch64 "$f" && grep -q ppc64le "$f"; then
583
584
585
586
587
588
			msg "No update needed for $f"
		else
			msg "Updating $f"
			cp "$datadir"/${f##*/} "$f" || return 1
			changed=true
		fi
589
	done; $changed)
590
591
}

Natanael Copa's avatar
Natanael Copa committed
592
runpart() {
593
	local part="$1"
594
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
595
	trap "die '$part failed'" EXIT
596
597
598
599
600
601
	if [ -d "$builddir" ]; then
		case "$part" in
			prepare|build|package|check)
				cd "$builddir";;
		esac
	fi
Natanael Copa's avatar
Natanael Copa committed
602
603
	$part
	trap - EXIT
Natanael Copa's avatar
Natanael Copa committed
604
605
606
}

# override those in your build script
607
608
609
610
611
612
613
614
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
}

615
616
617
have_patches() {
	local i
	for i in $source; do
618
		case ${i%::*} in
619
620
621
622
623
624
			*.patch) return 0;;
		esac
	done
	return 1
}

625
626
default_prepare() {
	local i
627
	[ -n "$builddir" -a -d "$builddir" ] && cd "$builddir"
628
629
630
	if ! have_patches; then
		return 0
	fi
631
	[ -d "$builddir" ] || { error "Is \$builddir set correctly?"; return 1; }
632
	for i in $source; do
633
		case ${i%::*} in
634
			*.patch)
635
				msg "${i%::*}"
636
				patch ${patch_args:--p1} -i "$srcdir/${i%::*}" || return 1
637
638
639
640
641
				;;
		esac
	done
}

Natanael Copa's avatar
Natanael Copa committed
642
prepare() {
643
	default_prepare
Natanael Copa's avatar
Natanael Copa committed
644
645
}

Natanael Copa's avatar
Natanael Copa committed
646
build() {
647
	:
Natanael Copa's avatar
Natanael Copa committed
648
649
}

650
651
652
# generate a simple tar.gz package of pkgdir
targz() {
	cd "$pkgdir" || return 1
653
654
	mkdir -p "$REPODEST"/src
	tar -czf "$REPODEST"/src/$pkgname-$pkgver-r$pkgrel.tar.gz *
655
656
}

657
658
659
postcheck() {
	local dir="$1" name="$2" i=
	msg "Running postcheck for $name"
660
	# checking for FHS compat
Natanael Copa's avatar
Natanael Copa committed
661
662
663
664
665
666
667
	if ! options_has "!fhs"; then
		for i in "$dir"/srv/* "$dir"/usr/local/* "$dir"/opt/*; do
			if [ -e "$i" ]; then
				error "Packages must not put anything under /srv, /usr/local or /opt"
				return 1
			fi
		done
668
669
670
671
		if [ -d "$dir"/usr/var ]; then
			error "Found /usr/var, localstatedir is most likely wrong"
			return 1
		fi
Natanael Copa's avatar
Natanael Copa committed
672
	fi
673
674
675
676

	# remove *.la files if libtool is not set
	if ! options_has "libtool"; then
		find "$dir" -name '*.la' -type f -delete
677
	fi
678

679
680
681
682
683
684
	# look for /usr/lib/charset.alias
	if [ -e "$dir"/usr/lib/charset.alias ] \
			&& ! options_has "charset.alias"; then
		error "Found /usr/lib/charset.alias"
		return 1
	fi
685
686
687
688
689
	# look for /etc/init.d and /etc/conf.d
	if [ -e "$dir"/etc/init.d -o -e "$dir"/etc/conf.d ] \
			&& ! is_openrc_pkg "$name"; then
		warning "Found OpenRC directory (/etc/conf.d or /etc/init.d) but name doesn't end with -openrc"
	fi
690
691
	# look for /usr/share/doc
	if [ -e "$dir"/usr/share/doc ] \
692
			&& ! is_doc_pkg "$name"; then
693
694
695
		warning "Found /usr/share/doc but package name doesn't end with -doc"
	fi
	# look for /usr/share/man
696
	if [ -e "$dir"/usr/share/man ]; then
697
		if ! is_doc_pkg "$name"; then
698
699
			warning "Found /usr/share/man but package name doesn't end with -doc"
		fi
700
		# check for uncompressed man pages
701
		i=$(find "$dir"/usr/share/man -name '*.[0-8]' -type f | sed "s|^$dir|\t|")
702
703
704
705
706
707
		if [ -n "$i" ]; then
			error "Found uncompressed man pages:"
			echo "$i"
			return 1
		fi
	fi
708
709
710
711
712
713
	# check directory permissions
	i=$(find "$dir" -type d -perm -777 | sed "s|^$dir|\t|")
	if [ -n "$i" ]; then
		warning "World writeable directories found:"
		echo "$i"
	fi
714
	# check so we dont have any suid root binaries that are not PIE
715
	i=$(find "$dir" -type f -perm /6000 \
716
717
718
719
720
721
722
		| xargs scanelf --nobanner --etype ET_EXEC \
		| sed "s|ET_EXEC $dir|\t|")
	if [ -n "$i" ]; then
		error "Found non-PIE files that has SUID:"
		echo "$i"
		return 1
	fi
723
724
725
726
727
728
729
730
731
732
733
	# test suid bit on executable
	if ! options_has "suid"; then
		i=$(find "$dir" \( -perm -u+s -o -perm -g+s \) -a -type f \
			-a -perm -o+x)
		if [ -n "$i" ]; then
			error "Found executable files with SUID bit set:"
			echo "$i"
			return 1
		fi
	fi

Natanael Copa's avatar
Natanael Copa committed
734
735
736
737
738
739
740
741
742
	# test for textrels
	if ! options_has "textrels"; then
		local res="$(scanelf --recursive --textrel --quiet "$dir")"
		if [ -n "$res" ]; then
			error "Found textrels:"
			echo "$res"
			return 1
		fi
	fi
743
744
745
	return 0
}

746
747
748
749
pre_split() {
	if [ -z "$subpkgname" ]; then
		return 0
	fi
Jonathan Neuschäfer's avatar
Jonathan Neuschäfer committed
750
	# the subpackages should not inherit those from main package
751
752
753
754
	provides=""
	install_if=""
}

755
prepare_subpackages() {
Natanael Copa's avatar
Natanael Copa committed
756
757
	local i
	cd "$startdir"
758
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
759
		# call abuild recursively, setting subpkg{dir,name}
760
761
		( subpkg_set "$i"; msg "Running split function $subpkgsplit..."; \
		  subpkgdir="$pkgbasedir/$subpkgname" subpkgname="$subpkgname" subpkgarch="$subpkgarch" \
762
		  "$abuild_path" $forceroot pre_split $subpkgsplit prepare_package \
763
			&& postcheck "$pkgbasedir/$subpkgname" "$subpkgname" ) || return 1
Natanael Copa's avatar
Natanael Copa committed
764
	done
765
	postcheck "$pkgdir" "$pkgname" || return 1
766
767
	# post check for /usr/share/locale
	if [ -d "$pkgdir"/usr/share/locale ]; then
768
		warning "Found /usr/share/locale"
769
		warning2 "Maybe add \$pkgname-lang to subpackages?"
770
	fi
Natanael Copa's avatar
Natanael Copa committed
771
772
}

773
default_lang() {
774
	pkgdesc="Languages for package $pkgname"
775
	install_if="$pkgname=$pkgver-r$pkgrel lang"
776

777
778
779
780
781
782
783
784
785
786
787
	local dir
	for dir in ${langdir:-/usr/share/locale}; do
		mkdir -p "$subpkgdir"/${dir%/*}
		mv "$pkgdir"/"$dir" "$subpkgdir"/"$dir" || return 1
	done
}

lang() {
	default_lang
}

788
default_lang_subpkg() {
789
790
791
792
	if [ -z "$lang" ]; then
		error "lang is not set"
		return 1
	fi
793
	pkgdesc="$pkgname language pack for $lang"
794
	install_if="$pkgname=$pkgver-r$pkgrel lang-$lang"
795

796
797
798
799
800
	local dir
	for dir in ${langdir:-/usr/share/locale}; do
		mkdir -p "$subpkgdir"/$dir
		mv "$pkgdir"/$dir/$lang* \
		"$subpkgdir"/$dir/ \
801
		|| return 1
802
803
804
805
806
	done
}

lang_subpkg() {
	default_lang_subpkg
807
808
809
}

prepare_language_packs() {
810
	local lang
811
812
813
814
	for lang in $linguas; do
		lang="$lang" \
		subpkgname="$pkgname-lang-$lang" \
		subpkgdir="$pkgbasedir"/$subpkgname \
815
			"$abuild_path" $forceroot lang_subpkg prepare_package || return 1
816
817
818
	done
}

819
820
# echo '-dirty' if git is not clean
git_dirty() {
821
	[ $($ABUILD_GIT status -s "$startdir" | wc -l) -ne 0 ] && echo "-dirty"
822
823
824
825
}

# echo last commit hash id
git_last_commit() {
826
	$ABUILD_GIT log --format=oneline -n 1 "$startdir" | awk '{print $1}'
827
828
}

829
830
831
get_maintainer() {
	if [ -z "$maintainer" ]; then
		maintainer=$(awk -F': ' '/\# *Maintainer/ {print $2}' "$APKBUILD")
832
833
		# remove surrounding whitespace
		maintainer=$(echo "$maintainer" | xargs)
834
835
836
837
838
839
840
841
842
843
844
845
846
	fi
}

check_maintainer() {
	get_maintainer
	if [ -z "$maintainer" ]; then
		warning "No maintainer"
	else
		# try to check for a valid rfc822 address
		case "$maintainer" in
			*[A-Za-z0-9]*\ \<*@*.*\>) ;;
			*) return 1 ;;
		esac
847
848
849
	fi
}

850
851
852
check_license() {
	local ret=0
	local license_list=/usr/share/spdx/license.lst
853
	local exclude="AND OR WITH"
854
855
856
857
	if options_has "!spdx" || ! [ -f "$license_list" ]; then
		return 0
	fi
	local i; for i in $license; do
858
		list_has "$i" $exclude && continue
859
860
861
862
863
864
865
866
		if ! grep -q -w -F "$i" "$license_list"; then
			ret=1
			warning "\"$i\" is not a known license"
		fi
	done
	return $ret
}

867
check_secfixes_comment() {
868
869
870
	local c="$(sed -E -n -e '/^# secfixes:/,/(^[^#]|^$)/p' $APKBUILD | grep '^#')"
	local invalid="$(echo "$c" \
		| grep -v -E '(^# secfixes:|^#  +- [A-Z0-9-]+|^#   [0-9]+.*:$|^#$)')"
871
872
873
874
875
	if [ -z "$invalid" ]; then
		return 0
	fi

	# check if there are tabs
Max Rees's avatar
Max Rees committed
876
	if echo "$invalid" | grep -q "$(printf '\t')"; then
877
		error "secfixes comment must not have tabs:"
Max Rees's avatar
Max Rees committed
878
		echo "$c" | grep "$(printf '\t')" >&2
879
880
881
882
883
884
885
886
		return 1
	fi

	error "secfixes comment is not valid:"
	echo "$invalid" >&2
	return 1
}

887
check_depends_dev() {
Natanael Copa's avatar
Natanael Copa committed
888
889
	if [ -z "$depends_dev" ]; then
		return 0
890
	fi
Natanael Copa's avatar
Natanael Copa committed
891
892
	local i
	for i in $pkgname $subpackages; do
893
894
		case "${i%%:*}" in
		*-dev) return 0 ;;
Natanael Copa's avatar
Natanael Copa committed
895
896
897
		esac
	done
	return 1
898
899
}

900
901
902
903
904
905
906
907
908
909
check_provides() {
	local i
	for i in $provides; do
		if [ "${i%%[<>=]*}" = "$pkgname" ]; then
			return 1
		fi
	done
	return 0
}

910
prepare_metafiles() {
911
	getpkgver || return 1
912
	local name="${subpkgname:-$pkgname}"
913
	[ -z "${name##* *}" ] && die "package name contains spaces"
914
	local dir="${subpkgdir:-$pkgdir}"
915
	local pkg="$name-$pkgver-r$pkgrel.apk"
916
	local pkginfo="$controldir"/.PKGINFO
917
	local sub
918

Natanael Copa's avatar
Natanael Copa committed
919
920
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
921
	mkdir -p "$controldir"
922
	local builddate="$(date -u "+%s")"
923
924
925
926
927
928
929

	# Fix package size on several filesystems
	case "$(df -PT . | awk 'END {print $2}')" in
	btrfs|ecryptfs|zfs)
		sync;;
	esac

930
	local size="$(du -sk | awk '{print $1 * 1024}')"
Natanael Copa's avatar
Natanael Copa committed
931

932
933
934
935
936
	if [ "$arch" != "$apkbuild_arch" ]; then
		local msg="Split function set arch=\"$arch\" for $name, use subpackages=pkg:split:arch format instead"
		[ "$arch" != "noarch" ] && die "$msg"
		warning "$msg"
		subpkgarch="$arch"
937
938
	fi

939
	echo "# Generated by $(basename "$abuild_path") $program_version" >"$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
940
	if [ -n "$FAKEROOTKEY" ]; then
941
		echo "# using $($FAKEROOT -v)" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
942
	fi
943
	echo "# $(date -u)" >> "$pkginfo"
Jakub Jirutka's avatar
Jakub Jirutka committed
944
945
946
947
948
949
950
951
952
953
954
	cat >> "$pkginfo" <<-EOF
		pkgname = $name
		pkgver = $pkgver-r$pkgrel
		pkgdesc = $pkgdesc
		url = $url
		builddate = $builddate
		packager = ${PACKAGER:-"Unknown"}
		size = $size
		arch = ${subpkgarch:-$pkgarch}
		origin = $pkgname
	EOF
955
956
	local i deps
	deps="$depends"
957
	if ! depends_has /bin/sh; then
958
		for i in $install $triggers; do
959
			local s="${i%=*}"
960
			[ "$name" != "${s%.*}" ] && continue
961
			if head -n 1 "$startdir/$s" | grep '^#!/bin/sh' >/dev/null ; then
962
963
				msg "Script found. /bin/sh added as a dependency for $pkg"
				deps="$deps /bin/sh"
964
965
966
				break
			fi
		done
967
	fi
968

969
970
971
	# store last_commit in global var so we only call git once
	if [ -z "$last_commit" ]; then
		last_commit="$(git_last_commit)$(git_dirty)"
972
	fi