abuild.in 25.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"
89
	if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
Natanael Copa's avatar
Natanael Copa committed
90
91
92
		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
}

uri_fetch() {
	local uri="$1"
152
	local d="${uri##*/}"	# $(basename $uri)
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
	# we need GNU wget for this
	case "$uri" in
		https://*) opts="--no-check-certificate";;
	esac
	
Natanael Copa's avatar
Natanael Copa committed
162
	mkdir -p "$SRCDEST"
163
164
165
	if [ -f "$SRCDEST/$d.part" ]; then
		msg "Partial download found. Trying to resume"
		opts="$opts -c"
Natanael Copa's avatar
Natanael Copa committed
166
	fi
Linux User's avatar
Linux User committed
167
	msg "Fetching $uri"
168
169
	wget $opts -O "$SRCDEST/$d.part" "$uri" \
		&& mv "$SRCDEST/$d.part" "$SRCDEST/$d"
Natanael Copa's avatar
Natanael Copa committed
170
171
}

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

180
181
182
183
184
185
186
187
188
189
# try download from file from mirror first
uri_fetch_mirror() {
	local uri="$1"
	local d="${uri##*/}"	# $(basename $uri)
	if [ -n "$DISTFILES_MIRROR" ]; then
		uri_fetch "$DISTFILES_MIRROR"/$d && return 0
	fi
	uri_fetch "$uri"
}

190
default_fetch() {
Natanael Copa's avatar
Natanael Copa committed
191
192
	local s
	mkdir -p "$srcdir"
193
194
	for s in $source; do
		if is_remote "$s"; then
195
			uri_fetch_mirror "$s" || return 1
196
197
198
199
			ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
		else		
			ln -sf "$startdir/$s" "$srcdir/"
		fi
Natanael Copa's avatar
Natanael Copa committed
200
201
202
	done
}

203
204
205
206
fetch() {
	default_fetch
}

Natanael Copa's avatar
Natanael Copa committed
207
# unpack the sources
208
default_unpack() {
Natanael Copa's avatar
Natanael Copa committed
209
	local u
210
	md5check || return 1
Natanael Copa's avatar
Natanael Copa committed
211
212
213
214
	mkdir -p "$srcdir"
	for u in $source; do
		local s="$SRCDEST/${u##*/}"	# $(basename $s)
		case "$s" in
Natanael Copa's avatar
Natanael Copa committed
215
			*.tar.gz|*.tgz)
216
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
217
218
				tar -C "$srcdir" -zxf "$s" || return 1;;
			*.tar.bz2)
219
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
220
				tar -C "$srcdir" -jxf "$s" || return 1;;
221
222
223
224
			*.tar.lzma)
				msg "Unpacking $s..."
				unlzma -c "$s" | tar -C "$srcdir" -x  \
					|| return 1;;
Natanael Copa's avatar
Natanael Copa committed
225
226
227
			*.zip)
				msg "Unpacking $s..."
				unzip "$s" -d "$srcdir" || return 1;;
Natanael Copa's avatar
Natanael Copa committed
228
229
230
231
		esac
	done
}

232
233
234
235
unpack() {
	default_unpack
}

Natanael Copa's avatar
Natanael Copa committed
236
237
# cleanup source and package dir
clean() {
238
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
239
	rm -rf "$srcdir"
240
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
241
242
243
244
245
246
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
247
248
249
250
		if is_remote "$s"; then
			msg "Cleaning downloaded ${s##*/}..."
			rm -f "$SRCDEST/${s##*/}"
		fi
Natanael Copa's avatar
Natanael Copa committed
251
252
253
254
255
	done
}

cleanpkg() {
	local i
256
	getpkgver || return 1
257
	msg "Cleaning built packages..."
258
	for i in $pkgname $subpackages; do
259
260
		local p="${i%:*}-$pkgver-r$pkgrel"
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
261
			"$apkcache"/$p.apk
Natanael Copa's avatar
Natanael Copa committed
262
	done
263
	# remove given packages from index
Natanael Copa's avatar
Natanael Copa committed
264
265
}

266
267
268
# clean all packages except current
cleanoldpkg() {
	local i j
269
	getpkgver || return 1
270
271
272
273
274
275
276
277
278
	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
}
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

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
297
298
runpart() {
	local part=$1
299
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
300
301
302
303
	$part || die "$part failed"
}

# override those in your build script
304
305
306
307
308
309
310
311
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
312
313
314
315
prepare() {
	:
}

Natanael Copa's avatar
Natanael Copa committed
316
build() {
317
	:
Natanael Copa's avatar
Natanael Copa committed
318
319
}

Natanael Copa's avatar
Natanael Copa committed
320
321
322
323
324
325
326
327
328
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
}

329
prepare_subpackages() {
Natanael Copa's avatar
Natanael Copa committed
330
	if [ -z "$subpackages" ]; then
331
332
		return 0
	fi
Natanael Copa's avatar
Natanael Copa committed
333
334
	local i
	cd "$startdir"
335
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
336
337
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
338
		msg "Running split function $func..."
339
		subpkgdir="$pkgbasedir/${i%:*}" subpkgname="${i%:*}" \
340
			$0 $func prepare_package || return 1
Natanael Copa's avatar
Natanael Copa committed
341
342
343
	done
}

344
prepare_metafiles() {
345
	getpkgver || return 1
346
347
	local name=${subpkgname:-$pkgname}
	[ -z "${name##* *}" ] && die "package name contains spaces"
348
	local dir=${subpkgdir:-$pkgdir}
349
	local pkg="$name-$pkgver-r$pkgrel.apk"
350
	local pkginfo="$controldir"/.PKGINFO
351
	local sub
Natanael Copa's avatar
Natanael Copa committed
352
353
354
	
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
355
	mkdir -p "$controldir"
Natanael Copa's avatar
Natanael Copa committed
356
357
358
	local builddate=$(date -u "+%s")
	local size=$(du -sk | awk '{print $1 * 1024}')

359
	echo "# Generated by $(basename $0) $abuild_ver" >"$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
360
	if [ -n "$FAKEROOTKEY" ]; then
361
		echo "# using $($FAKEROOT -v)" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
362
	fi
363
364
	echo "# $(date -u)" >> "$pkginfo"
	cat >> "$pkginfo" <<EOF
365
pkgname = $name
366
pkgver = $pkgver-r$pkgrel
Natanael Copa's avatar
Natanael Copa committed
367
368
369
370
371
372
pkgdesc = $pkgdesc
url = $url
builddate = $builddate
packager = ${PACKAGER:-"Unknown"}
size = $size
EOF
373
374
	local i deps
	deps="$depends"
375
	if [ "$pkgname" != "busybox" ] && ! depends_has busbox; then
Natanael Copa's avatar
Natanael Copa committed
376
377
		for i in $install ${triggers%%:*}; do
			if head -n 1 "$startdir/$i" | grep '^#!/bin/sh' >/dev/null ; then
378
379
380
381
382
				msg "Script found. busybox added as a dependency for $pkg"
				deps="$deps busybox"
				break
			fi
		done
383
384
	fi
	
Natanael Copa's avatar
Natanael Copa committed
385
	for i in $license; do
386
		echo "license = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
387
388
	done
	for i in $replaces; do
389
		echo "replaces = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
390
	done
391
	for i in $deps; do
392
		echo "depend = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
393
394
	done
	for i in $conflicts; do
395
		echo "conflict = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
396
397
	done
	for i in $provides; do
398
		echo "provides = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
399
400
	done
	for i in $backup; do
401
		echo "backup = $i" >> "$pkginfo"
Natanael Copa's avatar
Natanael Copa committed
402
	done
Natanael Copa's avatar
Natanael Copa committed
403
404
405
	if [ -n "$triggers" ]; then
		echo "triggers = ${triggers#*:}" >> "$pkginfo"
	fi
Natanael Copa's avatar
Natanael Copa committed
406
407

	local metafiles=".PKGINFO"
Natanael Copa's avatar
Natanael Copa committed
408
	for i in $install ${triggers%%:*}; do
409
410
		script=${i#$name}
		case "$script" in
Natanael Copa's avatar
Natanael Copa committed
411
			.pre-install|.post-install|.pre-upgrade|.post-upgrade|.pre-deinstall|.post-deinstall|.trigger)
412
413
				msg "Adding $script"
				;;
Natanael Copa's avatar
Natanael Copa committed
414
			*) 	error "$script: Invalid install/trigger script"
415
416
417
				return 1
				;;
		esac
Natanael Copa's avatar
Natanael Copa committed
418
		cp "$startdir/$i" "$controldir/$script" || return 1
419
		chmod +x "$controldir/$script"
420
421
		metafiles="$metafiles $script"
	done
422
	echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
423
}
424

425
426
427
prepare_tracedeps() {
	local dir=${subpkgdir:-$pkgdir}
	options_has "!tracedeps" && return 0
428
429
	find -name '*.so' -o -name '*.so.[0-9]*' | sed 's:.*/::' \
		>"$controldir"/.provides-so
430
	scanelf -Rn "$dir" | awk -F "\ " '$1 == "ET_DYN" || $1 == "ET_EXEC" {print $2}'  \
431
432
433
		| sed 's:,:\n:g' | sort | uniq \
	| while read i; do
		# only add files that are not self provided
434
435
		grep "^$i$" "$controldir"/.provides-so >/dev/null \
			|| echo $i >> "$controldir"/.needs-so
436
	done
Natanael Copa's avatar
Natanael Copa committed
437
438
}

439
prepare_package() {
440
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
441
	stripbin
442
	prepare_metafiles && prepare_tracedeps
443
444
445
446
447
448
449
450
}

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

451
452
453
trace_apk_deps() {
	local name="$1"
	local dir="$2"
454
455
	local i j found autodeps=
	msg "Tracing dependencies for $name..."
456
457
458
459
460
461
	# 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
462
	for i in $(cat "$dir"/.needs-so 2>/dev/null); do
463
		found=
464
		# first check if its provide by same apkbuild
465
		for j in "$dir"/../.control.*/.provides-so; do
466
			grep -w "$i" "$j" >/dev/null || continue
467
			found=${j%/.provides-so}
468
			found=${found##*/.control.}
469
			break
470
471
472
473
474
475
476
477
478
		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
479
		if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
480
481
482
			warning "You can remove '$found' from depends"
			continue
		fi
483
484
		list_has "$found" $autodeps || autodeps="$autodeps $found"
		msg "Added '$found' as dependency as it has $i"
485
486
487
488
489
490
491
492
	done
	[ -z "$autodeps" ] && return 0
	echo "# automatically detected:" >> "$dir"/.PKGINFO
	for i in $autodeps; do
		echo "depend = $i" >> "$dir"/.PKGINFO
	done
}

493
494
create_apks() {
	local file
495
	getpkgver || return 1
496
	for file in "$pkgbasedir"/.control.*/.PKGINFO; do
497
498
499
		local dir="${file%/.PKGINFO}"
		local name=$(pkginfo_val pkgname $file)
		local ver=$(pkginfo_val pkgver $file)
500
		local apk=$name-$ver.apk
501
		local datadir="$pkgbasedir"/$name
502
503

		trace_apk_deps "$name" "$dir" || return 1
504
		msg "Creating $apk..."
505
		(
506
507
		cd "$datadir"
		# data.tar.gz
508
509
510
511
512
513
		set -- *
		if [ "$1" = '*' ]; then
			touch .dummy
			set -- .dummy
		fi
		tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
514
515
516
517
518
519

		# 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
520
		cd "$dir"
521
522
		tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
			| gzip -9 > control.tar.gz
523
		abuild-sign -q control.tar.gz || exit 1
Natanael Copa's avatar
Natanael Copa committed
524

525
526
527
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
528
529
530
	done
}

531
apkcache() {
532
	if ! apk_up2date || [ -n "$force" ]; then
533
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
534
			&& prepare && mkusers && rootpkg || return 1
535
	fi
536

537
	local apk
538
	mkdir -p "$apkcache" || return 1
539
540
541
542
543
544
545
546
547
548
	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
549
	for apk in $(listpkg); do
550
		ln -sf "$PKGDEST"/$apk "$apkcache"/$apk
551
552
	done

553
	msg "Updating the cached abuild repository index..."
554
555
556
557
558
	local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
	local oldindex=
	if [ -f APKINDEX.tar.gz ]; then
		oldindex="--index APKINDEX.tar.gz"
	fi
559
560
561
	apk index $oldindex --output APKINDEX.tar.gz.unsigned \
		--description "$repo $(cd $startdir && git describe)" \
		*.apk || exit 1
562
563
564
	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
565
	chmod 644 APKINDEX.tar.gz
566
567
}

568
# predefined splitfunc doc
569
default_doc() {
570
	depends="$depends_doc"
571
	install="$install_doc"
Natanael Copa's avatar
Natanael Copa committed
572
	triggers="$triggers_doc"
Natanael Copa's avatar
Natanael Copa committed
573
	local i
574
	for i in doc man info html sgml licenses gtk-doc; do
575
576
577
		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
578
579
		fi
	done
580
581
582
	
	rm -f "$subpkgdir/usr/share/info/dir"

583
584
585
#	# compress info and man pages
#	find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
#		-o -name '*.[1-9]' \) -exec gzip {} \;
586
587
588
589

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

Natanael Copa's avatar
Natanael Copa committed
590
#	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
591
592
593
	return 0
}

594
595
596
597
doc() {
	default_doc
}

598
# predefined splitfunc mod
599
default_mod() {
600
	depends="$kernel $depends_mod"
601
	install="$install_mod"
Natanael Copa's avatar
Natanael Copa committed
602
	for i in firmware modules; do
603
604
605
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
606
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
607
608
609
610
		fi
	done
}

611
612
613
614
mod() {
	default_mod
}

615
# predefined splitfunc dev
616
default_dev() {
617
	local i
618
	depends="$pkgname $depends_dev"
619
	install="$install_dev"
Natanael Copa's avatar
Natanael Copa committed
620
	triggers="$triggers_dev"
621
622
623
624
	for i in $origsubpackages; do
		[ "${i%:*}" = "$subpkgname" ] || depends="$depends ${i%:*}"
	done
		
625
	cd "$pkgdir" || return 0
626
627
628
629
630
	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
631
632
		if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
			d="$subpkgdir/${i%/*}"	# dirname $i
Natanael Copa's avatar
Natanael Copa committed
633
			mkdir -p "$d"
634
			mv "$pkgdir/$i" "$d"
635
			rmdir "$pkgdir/${i%/*}" 2>/dev/null
Natanael Copa's avatar
Natanael Copa committed
636
637
		fi
	done
Natanael Copa's avatar
Natanael Copa committed
638
	return 0
Natanael Copa's avatar
Natanael Copa committed
639
640
}

641
642
643
644
dev() {
	default_dev
}

645
646
647
648
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

Natanael Copa's avatar
Natanael Copa committed
649
650
# build and package in fakeroot
rootpkg() {
651
652
653
654
	local do_build=build
	cd "$startdir"
	if is_function package; then
		build || return 1
655
		do_build=package
656
	fi
Natanael Copa's avatar
Natanael Copa committed
657
	cd "$startdir"
658
659
660
661
	[ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
	$FAKEROOT "$abuild_path" $do_build \
		prepare_subpackages \
		prepare_package \
662
		create_apks
Natanael Copa's avatar
Natanael Copa committed
663
664
665
}

srcpkg() {
666
	getpkgver || return 1
667
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
668
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
669
670
671
672
673
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
674
	msg "Creating source package $p.src.tar.gz..."
675
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
676
677
}

678
# check if package is up to date
679
apk_up2date() {
680
	getpkgver || return 1
681
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
682
	local i s
Natanael Copa's avatar
Natanael Copa committed
683
	cd "$startdir"
684
685
686
687
688
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

689
	for i in $source APKBUILD; do
690
691
692
693
694
695
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
696
697
698
699
700
701
702
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

703
704
cache_up2date() {
	local i apk
705
	getpkgver || return 1
706
707
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
708
		[ "$apkcache"/APKINDEX.tar.gz -nt "$apkcache"/$apk ] || return 1
709
710
711
712
713
714
715
716
	done
	return 0
}

up2date() {
	apk_up2date && cache_up2date
}

717
718
719
720
721
722
723
# 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
	(
724
725
	aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
	for i in $aportsdir/*/APKBUILD; do
726
727
728
729
		pkgname=
		subpackages=
		depends=
		makedepends=
730
		. $i
731
		dir=${i%/APKBUILD}
732
		deps=
733
		# filter out conflicts from deps and version info
734
735
736
737
		for j in $depends $makedepends; do
			case "$j" in
				!*) continue;;
			esac
738
			deps="$deps ${j%[<>=]*}"
739
		done
740
		for j in $pkgname $subpackages; do
741
			echo "o ${j%%:*} $dir"
742
			set -- $deps
743
744
745
746
747
748
749
			echo -n "d ${j%%:*} $1"
			shift
			while [ $# -gt 0 ]; do
				echo -n ",$1"
				shift
			done
			echo
750
751
		done
	done
752
	)
753
754
}

755
deptrace() {
756
757
758
759
760
	local deps= i=
	# strip versions from deps
	for i in "$@"; do
		deps="$deps ${i%[<>=]*}"
	done
761
	[ -z "$deps" ] && return 0
762
763
764
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
Natanael Copa's avatar
abuild:    
Natanael Copa committed
765
			apk info -q | sort |  sed 's/^/i /'
766
		fi
767
	) | awk -v pkgs="$deps" '
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792

	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() {
793
794
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
795
	[ -n "$nodeps" ] && return 0
796
	msg "Analyzing dependencies..."
797
798
799
800
	deps="$BUILD_BASE $makedepends"

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

804
	installed_deps=$(apk info -e $deps)
805
	# find which deps are missing
806
	for i in $deps; do
807
		if [ "${i#\!}" != "$i" ]; then
808
			list_has ${i#\!} $installed_deps \
809
				&& die "Conflicting package ${i#\!} is installed."
810
		elif ! deplist_has $i $installed_deps; then
811
812
813
814
815
816
817
			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

818
819
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
820

821
	uninstall_after=".makedepends-$pkgname $uninstall_after"
822
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
823
824
		# make a --simluate run first to detect missing deps
		# apk-tools --virtual is no goot at reporting those.
825
		$SUDO apk add --repository "$apkcache" \
826
827
828
829
			--wait 30 \
			--simulate --quiet $deps || return 1
		$SUDO apk add --repository "$apkcache" \
			--wait 30 \
830
831
			--virtual .makedepends-$pkgname $deps \
			&& return 0
832
	fi
833
834
	
	[ -z "$recursive" ] && return 1
835
836
837

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
838
		local m=$(apk search --repository "$apkcache" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
839
		if [ -z "$m" ]; then
840
841
842
			missing="$missing $i"
		fi
	done
843
844
	
	for i in $(deptrace $missing); do
845
846
847
848
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
		msg "Entering $dir"
849
		cd "$dir" && $0 -k -r apkcache || return 1
850
	done
851
	$SUDO apk add -u --repository "$apkcache" \
852
		--wait 30 \
853
		--virtual .makedepends-$pkgname $deps
854
855
}

856
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
857
858
checksum() {
	local s files
859
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
860
	fetch
861
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
862
863
864
865
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
866
867
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
868
869
}

870
stripbin() {
871
	local bin
872
	options_has "!strip" && return 0
873
874
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
875
876
877
	scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
		| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
		| xargs -r strip
878
879
}

880
881
882
# simply list target apks
listpkg() {
	local i 
883
	getpkgver || return 1
884
885
886
887
888
	for i in $pkgname $subpackages; do
		echo "${i%:*}-$pkgver-r$pkgrel.apk"
	done
}

Natanael Copa's avatar
Natanael Copa committed
889
890
891
892
893
894
895
896
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
897
898
899
900
901
902
903
904
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

905
906
907
908
909
910
911
912
913
914
915
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

916
917
918
919
920
921
922
923
924
925
926
927
928
# 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
}

929
930
931
932
options_has() {
	list_has "$1" $options
}

933
depends_has() {
934
	deplist_has "$1" $depends
935
936
}

Natanael Copa's avatar
Natanael Copa committed
937
makedepends_has() {
938
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
939
940
}

Natanael Copa's avatar
Natanael Copa committed
941
942
943
944
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
945
946
947
948
install_has() {
	list_has "$1" $install
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
949
950
# install package after build
post_add() {
951
	getpkgver || return 1
Natanael Copa's avatar
abuild:    
Natanael Copa committed
952
953
954
955
956
957
958
959
960
961
962
963
	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
964
	$SUDO apk add --wait 30 -u "$pkgf" || die "Failed to install $1"
Natanael Copa's avatar
abuild:    
Natanael Copa committed
965
966
}

967
installdeps() {
968
	local deps i
969
970
	sudo apk add --wait 30 --repository "$apkcache" \
		--virtual .makedepends-$pkgname \
971
		$makedepends
972
973
974
}

uninstalldeps (){
975
	sudo apk del .makedepends-$pkgname
976
}
977
978
979
980
981
982
983
984
985

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

Natanael Copa's avatar
Natanael Copa committed
986
usage() {
987
988
	echo "$program $abuild_ver"
	echo "usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]"
989
	echo "              [-s SRCDEST] [cmd] ..."
990
	echo "       $program [-c] -n PKGNAME[-PKGVER]"
Natanael Copa's avatar
Natanael Copa committed
991
	echo "Options:"
992
	echo " -d  Disable dependency checking"
Natanael Copa's avatar
Natanael Copa committed
993
	echo " -f  Force specified cmd, even if they are already done"
994
	echo " -F  Force run as root"
995
996
	echo " -h  Show this help"
	echo " -i  Install PKG after successul build"
997
	echo " -k  Keep built packages, even if APKBUILD or sources are newer"
998
	echo " -p  Set package destination directory"
999
	echo " -P  Set PKGDEST to REPODEST/<repo>, where repo is the parents dir name" 
Natanael Copa's avatar
Natanael Copa committed
1000
	echo " -q  Quiet"
1001
1002
	echo " -r  Install missing dependencies from system repository (using sudo)"
	echo " -R  Recursively build and install missing dependencies (using sudo)"
1003
	echo " -s  Set source package destination directory"
1004
	echo " -u  Recursively build and upgrade all dependencies (using sudo)"
Natanael Copa's avatar
Natanael Copa committed
1005
1006
	echo ""
	echo "Commands:"
1007
	echo "  checksum    Generate checksum to be included in APKBUILD"
1008
1009
1010
1011
1012
	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"
1013
	echo "  listpkg     List target packages"
1014
1015
1016
	echo "  package     Create package in \$PKGDEST"
	echo "  rootpkg     Run '$0 build package' as fakeroot"
	echo "  clean       Remove temp build and install dirs"
1017
	echo "  cleanoldpkg Remove binary packages except current version"
1018
1019
1020
1021
	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"
1022
1023
	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
1024
1025
1026
1027
1028
	echo ""
	exit 0
}

APKBUILD="${APKBUILD:-./APKBUILD}"
<