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

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

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

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

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

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

29

Natanael Copa's avatar
Natanael Copa committed
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
61
#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
62
63

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

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

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

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

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

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

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

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

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

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

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

Natanael Copa's avatar
Natanael Copa committed
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
182
183
184
185
186
187
188
189
190
# 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"
}

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

204
205
206
207
fetch() {
	default_fetch
}

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

233
234
235
236
unpack() {
	default_unpack
}

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

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

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

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

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

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

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

321
322
323
324
325
326
# generate a simple tar.gz package of pkgdir
targz() {
	cd "$pkgdir" || return 1
	tar -czf "$PKGDEST"/$pkgname-$pkgver-r$pkgrel.tar.gz *
}

Natanael Copa's avatar
Natanael Copa committed
327
328
329
330
331
332
333
334
335
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
}

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

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

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

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

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

446
prepare_package() {
447
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
448
	stripbin
449
	prepare_metafiles && prepare_tracedeps
450
451
452
453
454
455
456
457
}

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

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

500
501
create_apks() {
	local file
502
	getpkgver || return 1
503
	for file in "$pkgbasedir"/.control.*/.PKGINFO; do
504
505
506
		local dir="${file%/.PKGINFO}"
		local name=$(pkginfo_val pkgname $file)
		local ver=$(pkginfo_val pkgver $file)
507
		local apk=$name-$ver.apk
508
		local datadir="$pkgbasedir"/$name
509
510

		trace_apk_deps "$name" "$dir" || return 1
511
		msg "Creating $apk..."
512
		(
513
514
		cd "$datadir"
		# data.tar.gz
515
516
517
518
519
520
		set -- *
		if [ "$1" = '*' ]; then
			touch .dummy
			set -- .dummy
		fi
		tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
521
522
523
524
525
526

		# 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
527
		cd "$dir"
528
529
		tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
			| gzip -9 > control.tar.gz
530
		abuild-sign -q control.tar.gz || exit 1
Natanael Copa's avatar
Natanael Copa committed
531

532
533
534
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
535
536
537
	done
}

538
update_abuildrepo() {
539
	if ! apk_up2date || [ -n "$force" ]; then
540
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
541
			&& prepare && mkusers && rootpkg || return 1
542
	fi
543

544
	local apk
545
546
	mkdir -p "$abuildrepo" || return 1
	cd "$abuildrepo"
547
548
549
550
551
552
553
554
555

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

	# create links for this package
556
	for apk in $(listpkg); do
557
		ln -sf "$PKGDEST"/$apk "$abuildrepo"/$apk
558
559
	done

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

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

590
591
592
#	# compress info and man pages
#	find "$subpkgdir/usr/share" \( -name '*.info' -o -name '*.info-[1-9]' \
#		-o -name '*.[1-9]' \) -exec gzip {} \;
593
594
595
596

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

Natanael Copa's avatar
Natanael Copa committed
597
#	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
598
599
600
	return 0
}

601
602
603
604
doc() {
	default_doc
}

605
# predefined splitfunc mod
606
default_mod() {
607
	depends="$kernel $depends_mod"
608
	install="$install_mod"
Natanael Copa's avatar
Natanael Copa committed
609
	for i in firmware modules; do
610
611
612
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
613
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
614
615
616
617
		fi
	done
}

618
619
620
621
mod() {
	default_mod
}

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

648
649
650
651
dev() {
	default_dev
}

652
653
654
655
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

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

srcpkg() {
673
	getpkgver || return 1
674
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
675
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
676
677
678
679
680
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
681
	msg "Creating source package $p.src.tar.gz..."
682
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
683
684
}

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

696
	for i in $source APKBUILD; do
697
698
699
700
701
702
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
703
704
705
706
707
708
709
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

710
abuildindex_up2date() {
711
	local i apk
712
	getpkgver || return 1
713
714
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
715
		[ "$abuildrepo"/APKINDEX.tar.gz -nt "$abuildrepo"/$apk ] || return 1
716
717
718
719
720
	done
	return 0
}

up2date() {
721
722
723
724
725
726
727
	apk_up2date && abuildindex_up2date
}

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

730
731
732
733
734
735
736
# 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
	(
737
738
	aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
	for i in $aportsdir/*/APKBUILD; do
739
740
741
742
		pkgname=
		subpackages=
		depends=
		makedepends=
743
		. $i
744
		dir=${i%/APKBUILD}
745
		deps=
746
		# filter out conflicts from deps and version info
747
748
749
750
		for j in $depends $makedepends; do
			case "$j" in
				!*) continue;;
			esac
751
			deps="$deps ${j%[<>=]*}"
752
		done
753
		for j in $pkgname $subpackages; do
754
			echo "o ${j%%:*} $dir"
755
			set -- $deps
756
757
758
759
760
761
762
			echo -n "d ${j%%:*} $1"
			shift
			while [ $# -gt 0 ]; do
				echo -n ",$1"
				shift
			done
			echo
763
764
		done
	done
765
	)
766
767
}

768
deptrace() {
769
770
771
772
773
	local deps= i=
	# strip versions from deps
	for i in "$@"; do
		deps="$deps ${i%[<>=]*}"
	done
774
	[ -z "$deps" ] && return 0
775
776
777
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
778
			$APK info -q | sort |  sed 's/^/i /'
779
		fi
780
	) | awk -v pkgs="$deps" '
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805

	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() {
806
807
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
808
	[ -n "$nodeps" ] && return 0
809
	msg "Analyzing dependencies..."
810
811
812
813
	deps="$BUILD_BASE $makedepends"

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

817
	installed_deps=$($APK info -e $deps)
818
	# find which deps are missing
819
	for i in $deps; do
820
		if [ "${i#\!}" != "$i" ]; then
821
			list_has ${i#\!} $installed_deps \
822
				&& die "Conflicting package ${i#\!} is installed."
823
		elif ! deplist_has $i $installed_deps; then
824
825
826
827
828
829
830
			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

831
832
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
833

834
	uninstall_after=".makedepends-$pkgname $uninstall_after"
835
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
836
837
		# make a --simluate run first to detect missing deps
		# apk-tools --virtual is no goot at reporting those.
838
		$SUDO $APK add --repository "$abuildrepo" \
839
840
			--wait 30 \
			--simulate --quiet $deps || return 1
841
		$SUDO $APK add --repository "$abuildrepo" \
842
			--wait 30 \
843
844
			--virtual .makedepends-$pkgname $deps \
			&& return 0
845
	fi
846
847
	
	[ -z "$recursive" ] && return 1
848
849
850

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
851
		local m=$($APK search --repository "$abuildrepo" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
852
		if [ -z "$m" ]; then
853
854
855
			missing="$missing $i"
		fi
	done
856
857
	
	for i in $(deptrace $missing); do
858
859
860
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
Natanael Copa's avatar
Natanael Copa committed
861
862
		if [ -d "$dir" ]; then
			msg "Entering $dir"
863
			cd "$dir" && $0 -k -r abuildindex || return 1
Natanael Copa's avatar
Natanael Copa committed
864
		fi
865
	done
866
	$SUDO $APK add -u --repository "$abuildrepo" \
867
		--wait 30 \
868
		--virtual .makedepends-$pkgname $deps
869
870
}

871
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
872
873
checksum() {
	local s files
874
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
875
	fetch
876
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
877
878
879
880
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
881
882
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
883
884
}

885
stripbin() {
886
	local bin
887
	options_has "!strip" && return 0
888
889
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
890
891
892
	scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
		| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
		| xargs -r strip
893
894
}

895
896
897
# simply list target apks
listpkg() {
	local i 
898
	getpkgver || return 1
899
900
901
902
903
	for i in $pkgname $subpackages; do
		echo "${i%:*}-$pkgver-r$pkgrel.apk"
	done
}

Natanael Copa's avatar
Natanael Copa committed
904
905
906
907
908
909
910
911
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
912
913
914
915
916
917
918
919
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

920
921
922
923
924
925
926
927
928
929
930
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

931
932
933
934
935
936
937
938
939
940
941
942
943
# 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
}

944
945
946
947
options_has() {
	list_has "$1" $options
}

948
depends_has() {
949
	deplist_has "$1" $depends
950
951
}

Natanael Copa's avatar
Natanael Copa committed
952
makedepends_has() {
953
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
954
955
}

Natanael Copa's avatar
Natanael Copa committed
956
957
958
959
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
960
961
962
963
install_has() {
	list_has "$1" $install
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
964
965
# install package after build
post_add() {
966
	getpkgver || return 1
Natanael Copa's avatar
abuild:    
Natanael Copa committed
967
968
969
970
971
972
	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
973
	deps=$($APK index "$pkgf" 2>/dev/null | awk -F: '$1=="D" { print $2 }')
Natanael Copa's avatar
abuild:    
Natanael Copa committed
974
975
976
977
978
	for i in $deps; do
		if subpackages_has $i || [ "$i" = "$pkgname" ]; then
			post_add $i || return 1
		fi
	done
979
	$SUDO $APK add --wait 30 -u "$pkgf" || die "Failed to install $1"
Natanael Copa's avatar
abuild:    
Natanael Copa committed
980
981
}

982
installdeps() {
983
	local deps i
984
	sudo $APK add --wait 30 --repository "$abuildrepo" \
985
		--virtual .makedepends-$pkgname \
986
		$makedepends
987
988
989
}

uninstalldeps (){
990
	sudo $APK del .makedepends-$pkgname
991
}
992
993
994
995
996

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

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

APKBUILD="${APKBUILD:-./APKBUILD}"
1044
1045
unset force
unset recursive