abuild.in 24.9 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
15
16

startdir="$PWD"
srcdir=${srcdir:-"$startdir/src"}
17
pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
Natanael Copa's avatar
Natanael Copa committed
18
pkgrel=0
Natanael Copa's avatar
Natanael Copa committed
19
20
repo=${startdir%/*}
repo=${repo##*/}
Natanael Copa's avatar
Natanael Copa committed
21
22
23
24

# defaults
SRCDEST=${SRCDEST:-$startdir}
PKGDEST=${PKGDEST:-$startdir}
25
BUILD_BASE="build-base"
Natanael Copa's avatar
Natanael Copa committed
26

27
28
SUDO=${SUDO:-"sudo"}

29
default_cmds="sanitycheck builddeps clean fetch unpack mkusers rootpkg apkcache"
Natanael Copa's avatar
Natanael Copa committed
30

Natanael Copa's avatar
Natanael Copa committed
31
# read config
Natanael Copa's avatar
Natanael Copa committed
32
ABUILD_CONF=${ABUILD_CONF:-"$sysconfdir/abuild.conf"}
Natanael Copa's avatar
Natanael Copa committed
33
34
[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"

Natanael Copa's avatar
Natanael Copa committed
35
# source functions
36
37
datadir=/usr/share/abuild

Natanael Copa's avatar
Natanael Copa committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#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
70
71

	
Linux User's avatar
Linux User committed
72
73
set_xterm_title() {
	if [ "$TERM" = xterm ]; then
74
		 printf "\033]0;$1\007" >&2
Linux User's avatar
Linux User committed
75
76
77
78
79
	fi
} 

cleanup() {
	set_xterm_title ""
80
	if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
81
		$SUDO apk del $uninstall_after
82
	fi
Linux User's avatar
Linux User committed
83
84
}

Natanael Copa's avatar
Natanael Copa committed
85
die() {
Linux User's avatar
Linux User committed
86
	error "$@"
Linux User's avatar
Linux User committed
87
	cleanup
Natanael Copa's avatar
Natanael Copa committed
88
89
90
	exit 1
}

91
92
# check if apkbuild is basicly sane
sanitycheck() {
Natanael Copa's avatar
Natanael Copa committed
93
	local i
94
	msg "Checking sanity of $APKBUILD..."
95
96
97
	[ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
	[ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
	[ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
98
99
	apk version --check -q "$pkgver" ||\
		die "$pkgver is not a valid version"
100
101
102
103
104
	[ -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
105
106
107
108
109
110
111
	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"

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

125
126
	if [ -n "$md5sums" ]; then
		for i in $(echo "$md5sums" | awk '{ print $2 }'); do
Natanael Copa's avatar
Natanael Copa committed
127
			source_has $i || die "$i exists in md5sums but is missing in source"
128
129
		done
	fi
130

131
132
133
	# 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
134
135

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

	makedepends_has 'g++' && warning "g++ should not be in makedepends"
138
139
140
141
	return 0
}

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

uri_fetch() {
	local uri="$1"
	local d="${s##*/}"	# $(basename $s)
160
161
162
163
	local opts
	[ -n "$quiet" ] && opts="-q"
	[ -f "$SRCDEST/$d" ] && return 0

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

180
181
is_remote() {
	case "$1" in
Natanael Copa's avatar
Natanael Copa committed
182
		http://*|ftp://*|https://*)
183
184
185
186
187
			return 0;;
	esac
	return 1
}

Natanael Copa's avatar
Natanael Copa committed
188
189
190
fetch() {
	local s
	mkdir -p "$srcdir"
191
192
193
194
195
196
197
	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
198
199
200
201
202
203
	done
}

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

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

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

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

255
256
257
258
259
260
261
262
263
264
265
266
# clean all packages except current
cleanoldpkg() {
	local i j
	msg "Cleaning all packages except $pkgver-r$pkgrel..."
	for i in $pkgname $subpackages; do
		for j in "$PKGDEST"/${i%:*}-[0-9]*.apk; do
			[ "$j" != "$PKGDEST/${i%:*}-$pkgver-r$pkgrel.apk" ] \
				&& rm -f "$j"
		done
	done
	return 0
}
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

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

# override those in your build script
build() {
	die "No build() function found in $APKBUILD"
}

Natanael Copa's avatar
Natanael Copa committed
296
297
298
299
300
301
302
303
304
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
}

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

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

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

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

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

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

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

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

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

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

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

500
501
502
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
503
504
505
	done
}

506
apkcache() {
507
	if ! apk_up2date || [ -n "$force" ]; then
508
509
		sanitycheck && builddeps && clean && fetch && unpack \
			&& mkusers && rootpkg || return 1
510
	fi
511

512
	local apk
513
	mkdir -p "$apkcache" || return 1
514
515
516
517
518
519
520
521
522
523
	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
524
	for apk in $(listpkg); do
525
		ln -sf "$PKGDEST"/$apk "$apkcache"/$apk
526
527
	done

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

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

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

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

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

567
568
569
570
doc() {
	default_doc
}

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

584
585
586
587
mod() {
	default_mod
}

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

614
615
616
617
dev() {
	default_dev
}

Natanael Copa's avatar
Natanael Copa committed
618
619
# build and package in fakeroot
rootpkg() {
Natanael Copa's avatar
Natanael Copa committed
620
	cd "$startdir"
621
	msg "Entering fakeroot..."
622
	fakeroot $0 build prepare_subpackages prepare_package create_apks
Natanael Copa's avatar
Natanael Copa committed
623
624
625
}

srcpkg() {
626
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
627
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
628
629
630
631
632
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
633
	msg "Creating source package $p.src.tar.gz..."
634
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
635
636
}

637
# check if package is up to date
638
apk_up2date() {
639
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
640
	local i s
Natanael Copa's avatar
Natanael Copa committed
641
	cd "$startdir"
642
643
644
645
646
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

647
	for i in $source APKBUILD; do
648
649
650
651
652
653
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
654
655
656
657
658
659
660
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

661
662
663
664
cache_up2date() {
	local i apk
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
665
		[ "$apkcache"/APKINDEX.tar.gz -nt "$apkcache"/$apk ] || return 1
666
667
668
669
670
671
672
673
	done
	return 0
}

up2date() {
	apk_up2date && cache_up2date
}

674
675
676
677
678
679
680
681
682
683
684
685
686
# 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=
687
		. $i
688
		dir=${i%/APKBUILD}
689
		deps=
690
		# filter out conflicts from deps and version info
691
692
693
694
		for j in $depends $makedepends; do
			case "$j" in
				!*) continue;;
			esac
695
			deps="$deps ${j%[<>=]*}"
696
		done
697
		for j in $pkgname $subpackages; do
698
			echo "o ${j%%:*} $dir"
699
			set -- $deps
700
701
702
703
704
705
706
			echo -n "d ${j%%:*} $1"
			shift
			while [ $# -gt 0 ]; do
				echo -n ",$1"
				shift
			done
			echo
707
708
		done
	done
709
	)
710
711
}

712
deptrace() {
713
	local deps="$@"
714
	[ -z "$deps" ] && return 0
715
716
717
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
Natanael Copa's avatar
abuild:    
Natanael Copa committed
718
			apk info -q | sort |  sed 's/^/i /'
719
		fi
720
	) | awk -v pkgs="$deps" '
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

	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() {
746
747
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
748
	[ -n "$nodeps" ] && return 0
749
	msg "Analyzing dependencies..."
750
751
752
753
	deps="$BUILD_BASE $makedepends"

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

757
	installed_deps=$(apk info -e $deps)
758
	# find which deps are missing
759
	for i in $deps; do
760
		if [ "${i#\!}" != "$i" ]; then
761
			list_has ${i#\!} $installed_deps \
762
				&& die "Conflicting package ${i#\!} is installed."
763
		elif ! deplist_has $i $installed_deps; then
764
765
766
767
768
769
770
			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

771
772
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
773

774
	uninstall_after=".makedepends-$pkgname $uninstall_after"
775
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
776
		$SUDO apk add --repository "$apkcache" \
777
778
			--virtual .makedepends-$pkgname $deps \
			&& return 0
779
	fi
780
781
	
	[ -z "$recursive" ] && return 1
782
783
784

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
785
		local m=$(apk search --repository "$apkcache" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
786
		if [ -z "$m" ]; then
787
788
789
			missing="$missing $i"
		fi
	done
790
791
	
	for i in $(deptrace $missing); do
792
793
794
795
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
		msg "Entering $dir"
796
		cd "$dir" && $0 -k -r apkcache || return 1
797
	done
798
	$SUDO apk add -u --repository "$apkcache" \
799
		--virtual .makedepends-$pkgname $deps
800
801
}

802
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
803
804
checksum() {
	local s files
805
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
806
	fetch
807
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
808
809
810
811
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
812
813
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
814
815
}

816
stripbin() {
817
	local bin
818
	options_has "!strip" && return 0
819
820
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
821
	find . -type f 2>/dev/null | while read bin; do
822
823
824
825
826
827
828
829
830
831
832
		local opt=
		case "$(file -biz "$bin")" in
			*/x-sharedlib*|*/x-archive*)
				strip --strip-debug "$bin";;
			*/x-executable*)
				strip "$bin";;
		esac
	done
	return 0
}

833
834
835
836
837
838
839
840
# simply list target apks
listpkg() {
	local i 
	for i in $pkgname $subpackages; do
		echo "${i%:*}-$pkgver-r$pkgrel.apk"
	done
}

Natanael Copa's avatar
Natanael Copa committed
841
842
843
844
845
846
847
848
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
849
850
851
852
853
854
855
856
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

857
858
859
860
861
862
863
864
865
866
867
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

868
869
870
871
872
873
874
875
876
877
878
879
880
# 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
}

881
882
883
884
options_has() {
	list_has "$1" $options
}

885
depends_has() {
886
	deplist_has "$1" $depends
887
888
}

Natanael Copa's avatar
Natanael Copa committed
889
makedepends_has() {
890
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
891
892
}

Natanael Copa's avatar
Natanael Copa committed
893
894
895
896
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
897
898
899
900
install_has() {
	list_has "$1" $install
}

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

918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
# create new aport from templates
newaport() {
	local pn=${newname%-[0-9]*}
	local pv
	if [ "$pn" != "$newname" ]; then
		pv=${newname#$pn-}
	fi
	if [ -e "$pn"/APKBUILD ]; then
		error "$pn/APKBUILD already exist"
		return 1
	fi
	mkdir -p "$pn"
	cd "$pn"
	sed 	-e '1,/^\#*$/d' \
		-e "s/^\(# Contributor: \).*/\1$PACKAGER/" \
		-e "s/^\(# Maintainer: \).*/\1$PACKAGER/" \
		-e "s/^pkgname=.*/pkgname=$pn/" \
		-e "s/^pkgver=.*/pkgver=$pv/" \
		"$datadir"/sample.APKBUILD > APKBUILD || return 1
	#-e '1,/^\#$/d' \
	if [ -n "$cpinitd" ]; then
		cp "$datadir"/sample.initd $pn.initd
		cp "$datadir"/sample.confd $pn.confd
941
942
943
		cp "$datadir"/sample.pre-install $pn.pre-install
		cp "$datadir"/sample.post-install $pn.post-install
		sed -i -e "s/^install=.*/install=\"\$pkgname.pre-install \$pkgname.post-install\"/" \
944
945
946
947
948
			-e "s/^source=\"\(.*\)\"/source=\"\1\n\t$pn.initd\n\t$pn.confd\n\t\$install\n\t\"/" \
			APKBUILD
		
	fi
}
949
950

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

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

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

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

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

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

1041
# source the buildfile
1042
1043
1044
1045
if [ -z "$newname" ]; then
	[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
	. "$APKBUILD"
fi
1046

1047
# If we are handling a sub package then reset subpackages and install
1048
if [ -n "$subpkgname" ]; then
1049
	origsubpackages="$subpackages"
1050
	subpackages=
1051
	install=
1052
fi
1053
pkgdir="$pkgbasedir/$pkgname"
1054
controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
Natanael Copa's avatar
Natanael Copa committed
1055
1056

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

1059
1060
1061
if [ -z "$1" ] && [ -n "$newname" ]; then
	set "newaport"
fi
Natanael Copa's avatar
Natanael Copa committed
1062
1063

if [ -z "$1" ]; then
1064
	set all
Natanael Copa's avatar
Natanael Copa committed
1065
1066
1067
1068
1069
1070
fi

while [ $# -gt 0 ]; do
	runpart $1
	shift
done
1071
1072

for i in $install_after; do
Natanael Copa's avatar
abuild:    
Natanael Copa committed
1073
	post_add $i
1074
1075
done

Linux User's avatar
Linux User committed
1076
cleanup
Natanael Copa's avatar
Natanael Copa committed
1077