abuild.in 24.8 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
}

181
default_fetch() {
Natanael Copa's avatar
Natanael Copa committed
182
183
	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
	done
}

194
195
196
197
fetch() {
	default_fetch
}

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

223
224
225
226
unpack() {
	default_unpack
}

Natanael Copa's avatar
Natanael Copa committed
227
228
# cleanup source and package dir
clean() {
229
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
230
	rm -rf "$srcdir"
231
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
232
233
234
235
236
237
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
238
239
240
241
		if is_remote "$s"; then
			msg "Cleaning downloaded ${s##*/}..."
			rm -f "$SRCDEST/${s##*/}"
		fi
Natanael Copa's avatar
Natanael Copa committed
242
243
244
245
246
	done
}

cleanpkg() {
	local i
247
	getpkgver || return 1
248
	msg "Cleaning built packages..."
249
	for i in $pkgname $subpackages; do
250
251
		local p="${i%:*}-$pkgver-r$pkgrel"
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
252
			"$apkcache"/$p.apk
Natanael Copa's avatar
Natanael Copa committed
253
	done
254
	# remove given packages from index
Natanael Copa's avatar
Natanael Copa committed
255
256
}

257
258
259
# clean all packages except current
cleanoldpkg() {
	local i j
260
	getpkgver || return 1
261
262
263
264
265
266
267
268
269
	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
}
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

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
288
289
runpart() {
	local part=$1
290
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
291
292
293
294
	$part || die "$part failed"
}

# override those in your build script
295
296
297
298
299
300
301
302
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
303
304
305
306
prepare() {
	:
}

Natanael Copa's avatar
Natanael Copa committed
307
build() {
308
	:
Natanael Copa's avatar
Natanael Copa committed
309
310
}

Natanael Copa's avatar
Natanael Copa committed
311
312
313
314
315
316
317
318
319
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
}

320
prepare_subpackages() {
Natanael Copa's avatar
Natanael Copa committed
321
	if [ -z "$subpackages" ]; then
322
323
		return 0
	fi
Natanael Copa's avatar
Natanael Copa committed
324
325
	local i
	cd "$startdir"
326
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
327
328
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
329
		msg "Running split function $func..."
330
		subpkgdir="$pkgbasedir/${i%:*}" subpkgname="${i%:*}" \
331
			$0 $func prepare_package || return 1
Natanael Copa's avatar
Natanael Copa committed
332
333
334
	done
}

335
prepare_metafiles() {
336
	getpkgver || return 1
337
338
	local name=${subpkgname:-$pkgname}
	[ -z "${name##* *}" ] && die "package name contains spaces"
339
	local dir=${subpkgdir:-$pkgdir}
340
	local pkg="$name-$pkgver-r$pkgrel.apk"
341
	local pkginfo="$controldir"/.PKGINFO
342
	local sub
Natanael Copa's avatar
Natanael Copa committed
343
344
345
	
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
346
	mkdir -p "$controldir"
Natanael Copa's avatar
Natanael Copa committed
347
348
349
	local builddate=$(date -u "+%s")
	local size=$(du -sk | awk '{print $1 * 1024}')

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

	local metafiles=".PKGINFO"
Natanael Copa's avatar
Natanael Copa committed
399
	for i in $install ${triggers%%:*}; do
400
401
		script=${i#$name}
		case "$script" in
Natanael Copa's avatar
Natanael Copa committed
402
			.pre-install|.post-install|.pre-upgrade|.post-upgrade|.pre-deinstall|.post-deinstall|.trigger)
403
404
				msg "Adding $script"
				;;
Natanael Copa's avatar
Natanael Copa committed
405
			*) 	error "$script: Invalid install/trigger script"
406
407
408
				return 1
				;;
		esac
Natanael Copa's avatar
Natanael Copa committed
409
		cp "$startdir/$i" "$controldir/$script" || return 1
410
		chmod +x "$controldir/$script"
411
412
		metafiles="$metafiles $script"
	done
413
	echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
414
}
415

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

430
prepare_package() {
431
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
432
	stripbin
433
	prepare_metafiles && prepare_tracedeps
434
435
436
437
438
439
440
441
}

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

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

484
485
create_apks() {
	local file
486
	getpkgver || return 1
487
	for file in "$pkgbasedir"/.control.*/.PKGINFO; do
488
489
490
		local dir="${file%/.PKGINFO}"
		local name=$(pkginfo_val pkgname $file)
		local ver=$(pkginfo_val pkgver $file)
491
		local apk=$name-$ver.apk
492
		local datadir="$pkgbasedir"/$name
493
494

		trace_apk_deps "$name" "$dir" || return 1
495
		msg "Creating $apk..."
496
		(
497
498
		cd "$datadir"
		# data.tar.gz
499
500
501
502
503
504
		set -- *
		if [ "$1" = '*' ]; then
			touch .dummy
			set -- .dummy
		fi
		tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
505
506
507
508
509
510

		# 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
511
		cd "$dir"
512
513
		tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
			| gzip -9 > control.tar.gz
514
		abuild-sign -q control.tar.gz || exit 1
Natanael Copa's avatar
Natanael Copa committed
515

516
517
518
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
519
520
521
	done
}

522
apkcache() {
523
	if ! apk_up2date || [ -n "$force" ]; then
524
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
525
			&& prepare && mkusers && rootpkg || return 1
526
	fi
527

528
	local apk
529
	mkdir -p "$apkcache" || return 1
530
531
532
533
534
535
536
537
538
539
	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
540
	for apk in $(listpkg); do
541
		ln -sf "$PKGDEST"/$apk "$apkcache"/$apk
542
543
	done

544
	msg "Updating the cached abuild repository index..."
545
546
547
548
549
	local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
	local oldindex=
	if [ -f APKINDEX.tar.gz ]; then
		oldindex="--index APKINDEX.tar.gz"
	fi
550
551
552
	apk index $oldindex --output APKINDEX.tar.gz.unsigned \
		--description "$repo $(cd $startdir && git describe)" \
		*.apk || exit 1
553
554
555
	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
556
	chmod 644 APKINDEX.tar.gz
557
558
}

559
# predefined splitfunc doc
560
default_doc() {
561
	depends="$depends_doc"
562
	install="$install_doc"
Natanael Copa's avatar
Natanael Copa committed
563
	triggers="$triggers_doc"
Natanael Copa's avatar
Natanael Copa committed
564
	local i
565
	for i in doc man info html sgml licenses gtk-doc; do
566
567
568
		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
569
570
		fi
	done
571
572
573
	
	rm -f "$subpkgdir/usr/share/info/dir"

574
575
576
#	# compress info and man pages
#	find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
#		-o -name '*.[1-9]' \) -exec gzip {} \;
577
578
579
580

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

Natanael Copa's avatar
Natanael Copa committed
581
#	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
582
583
584
	return 0
}

585
586
587
588
doc() {
	default_doc
}

589
# predefined splitfunc mod
590
default_mod() {
591
	depends="$kernel $depends_mod"
592
	install="$install_mod"
Natanael Copa's avatar
Natanael Copa committed
593
	for i in firmware modules; do
594
595
596
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
597
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
598
599
600
601
		fi
	done
}

602
603
604
605
mod() {
	default_mod
}

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

632
633
634
635
dev() {
	default_dev
}

636
637
638
639
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

Natanael Copa's avatar
Natanael Copa committed
640
641
# build and package in fakeroot
rootpkg() {
642
643
644
645
	local do_build=build
	cd "$startdir"
	if is_function package; then
		build || return 1
646
		do_build=package
647
	fi
Natanael Copa's avatar
Natanael Copa committed
648
	cd "$startdir"
649
650
651
652
	[ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
	$FAKEROOT "$abuild_path" $do_build \
		prepare_subpackages \
		prepare_package \
653
		create_apks
Natanael Copa's avatar
Natanael Copa committed
654
655
656
}

srcpkg() {
657
	getpkgver || return 1
658
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
659
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
660
661
662
663
664
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
665
	msg "Creating source package $p.src.tar.gz..."
666
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
667
668
}

669
# check if package is up to date
670
apk_up2date() {
671
	getpkgver || return 1
672
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
673
	local i s
Natanael Copa's avatar
Natanael Copa committed
674
	cd "$startdir"
675
676
677
678
679
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

680
	for i in $source APKBUILD; do
681
682
683
684
685
686
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
687
688
689
690
691
692
693
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

694
695
cache_up2date() {
	local i apk
696
	getpkgver || return 1
697
698
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
699
		[ "$apkcache"/APKINDEX.tar.gz -nt "$apkcache"/$apk ] || return 1
700
701
702
703
704
705
706
707
	done
	return 0
}

up2date() {
	apk_up2date && cache_up2date
}

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

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

	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() {
784
785
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
786
	[ -n "$nodeps" ] && return 0
787
	msg "Analyzing dependencies..."
788
789
790
791
	deps="$BUILD_BASE $makedepends"

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

795
	installed_deps=$(apk info -e $deps)
796
	# find which deps are missing
797
	for i in $deps; do
798
		if [ "${i#\!}" != "$i" ]; then
799
			list_has ${i#\!} $installed_deps \
800
				&& die "Conflicting package ${i#\!} is installed."
801
		elif ! deplist_has $i $installed_deps; then
802
803
804
805
806
807
808
			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

809
810
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
811

812
	uninstall_after=".makedepends-$pkgname $uninstall_after"
813
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
814
		$SUDO apk add --repository "$apkcache" \
815
816
			--virtual .makedepends-$pkgname $deps \
			&& return 0
817
	fi
818
819
	
	[ -z "$recursive" ] && return 1
820
821
822

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
823
		local m=$(apk search --repository "$apkcache" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
824
		if [ -z "$m" ]; then
825
826
827
			missing="$missing $i"
		fi
	done
828
829
	
	for i in $(deptrace $missing); do
830
831
832
833
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
		msg "Entering $dir"
834
		cd "$dir" && $0 -k -r apkcache || return 1
835
	done
836
	$SUDO apk add -u --repository "$apkcache" \
837
		--virtual .makedepends-$pkgname $deps
838
839
}

840
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
841
842
checksum() {
	local s files
843
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
844
	fetch
845
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
846
847
848
849
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
850
851
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
852
853
}

854
stripbin() {
855
	local bin
856
	options_has "!strip" && return 0
857
858
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
859
860
861
	scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
		| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
		| xargs -r strip
862
863
}

864
865
866
# simply list target apks
listpkg() {
	local i 
867
	getpkgver || return 1
868
869
870
871
872
	for i in $pkgname $subpackages; do
		echo "${i%:*}-$pkgver-r$pkgrel.apk"
	done
}

Natanael Copa's avatar
Natanael Copa committed
873
874
875
876
877
878
879
880
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
881
882
883
884
885
886
887
888
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

889
890
891
892
893
894
895
896
897
898
899
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

900
901
902
903
904
905
906
907
908
909
910
911
912
# 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
}

913
914
915
916
options_has() {
	list_has "$1" $options
}

917
depends_has() {
918
	deplist_has "$1" $depends
919
920
}

Natanael Copa's avatar
Natanael Copa committed
921
makedepends_has() {
922
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
923
924
}

Natanael Copa's avatar
Natanael Copa committed
925
926
927
928
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
929
930
931
932
install_has() {
	list_has "$1" $install
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
933
934
# install package after build
post_add() {
935
	getpkgver || return 1
Natanael Copa's avatar
abuild:    
Natanael Copa committed
936
937
938
939
940
941
942
943
944
945
946
947
	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
948
	$SUDO apk add -u "$pkgf" || die "Failed to install $1"
Natanael Copa's avatar
abuild:    
Natanael Copa committed
949
950
}

951
installdeps() {
952
	local deps i
953
	sudo apk add --repository "$apkcache" --virtual .makedepends-$pkgname \
954
		$makedepends
955
956
957
}

uninstalldeps (){
958
	sudo apk del .makedepends-$pkgname
959
}
960
961
962
963
964
965
966
967
968

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

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

APKBUILD="${APKBUILD:-./APKBUILD}"
1012
1013
unset force
unset recursive
1014
while getopts "dfFhi:kinp:P:qrRs:u" opt; do
Natanael Copa's avatar
Natanael Copa committed
1015
	case $opt in
1016
		'd') nodeps=1;;
Natanael Copa's avatar
Natanael Copa committed
1017
		'f') force=1;;
1018
		'F') forceroot=1;;
1019
1020
		'h') usage;;
		'i') install_after="$install_after $OPTARG";;
1021
		'k') keep=1;;
1022
		'n') die "Use newapkbuild to create new aports";;
1023
		'p') PKGDEST=$OPTARG;;
1024
		'P') REPODEST=$OPTARG;;
Natanael Copa's avatar
Natanael Copa committed
1025
		'q') quiet=1;;
1026
1027
		'r') install_deps=1;;
		'R') recursive=1;;
1028
		's') SRCDEST=$OPTARG;;
1029
1030
		'u') upgrade=1
		     recursive=1;;
Natanael Copa's avatar
Natanael Copa committed
1031
1032
1033
1034
	esac
done
shift $(( $OPTIND - 1 ))

1035
1036
1037
1038
1039
1040
1041
# check so we are not root
if [ "$(whoami)" = "root" ] && [ -z "$FAKEROOTKEY" ]; then
	[ -z "$forceroot" ] && die "Do not run abuild as root"
	SUDO=
	FAKEROOT=
fi

1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
# 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"

1059
1060
1061
1062
1063
# If REPODEST is set then it will override the PKGDEST
if [ -n "$REPODEST" ]; then
	PKGDEST="$REPODEST/$repo"
fi

1064
# If we are handling a sub package then reset subpackages and install
1065
if [ -n "$subpkgname" ]; then
1066
	origsubpackages="$subpackages"
1067
	subpackages=
1068
	install=