abuild.in 24.2 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
22
SUDO=${SUDO:-"sudo"}

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

27

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

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

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

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

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

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

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

123
124
125
	# 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
126
127

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

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

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

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

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

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

Natanael Copa's avatar
Natanael Copa committed
180
181
182
fetch() {
	local s
	mkdir -p "$srcdir"
183
184
185
186
187
188
189
	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
190
191
192
193
194
195
	done
}

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

# cleanup source and package dir
clean() {
220
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
221
	rm -rf "$srcdir"
222
	rm -rf "$pkgbasedir"
Natanael Copa's avatar
Natanael Copa committed
223
224
225
226
227
228
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
229
230
231
232
		if is_remote "$s"; then
			msg "Cleaning downloaded ${s##*/}..."
			rm -f "$SRCDEST/${s##*/}"
		fi
Natanael Copa's avatar
Natanael Copa committed
233
234
235
236
237
	done
}

cleanpkg() {
	local i
238
	msg "Cleaning built packages..."
239
	for i in $pkgname $subpackages; do
240
241
		local p="${i%:*}-$pkgver-r$pkgrel"
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
242
			"$apkcache"/$p.apk
Natanael Copa's avatar
Natanael Copa committed
243
	done
244
	# remove given packages from index
Natanael Copa's avatar
Natanael Copa committed
245
246
}

247
248
249
250
251
252
253
254
255
256
257
258
# 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
}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276

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
277
278
runpart() {
	local part=$1
279
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
280
281
282
283
	$part || die "$part failed"
}

# override those in your build script
Natanael Copa's avatar
Natanael Copa committed
284
285
286
287
prepare() {
	:
}

Natanael Copa's avatar
Natanael Copa committed
288
build() {
289
	:
Natanael Copa's avatar
Natanael Copa committed
290
291
}

Natanael Copa's avatar
Natanael Copa committed
292
293
294
295
296
297
298
299
300
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
}

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

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

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

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

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

410
prepare_package() {
411
	msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
412
	stripbin
413
	prepare_metafiles
414
	prepare_tracedeps
415
416
417
418
419
420
421
422
}

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

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

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

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

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

496
497
498
		# create the final apk
		cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
	)
499
500
501
	done
}

502
apkcache() {
503
	if ! apk_up2date || [ -n "$force" ]; then
504
		sanitycheck && builddeps && clean && fetch && unpack \
Natanael Copa's avatar
Natanael Copa committed
505
			&& prepare && mkusers && rootpkg || return 1
506
	fi
507

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

524
	msg "Updating the cached abuild repository index..."
525
526
527
528
529
	local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
	local oldindex=
	if [ -f APKINDEX.tar.gz ]; then
		oldindex="--index APKINDEX.tar.gz"
	fi
530
531
532
	apk index $oldindex --output APKINDEX.tar.gz.unsigned \
		--description "$repo $(cd $startdir && git describe)" \
		*.apk || exit 1
533
534
535
	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
536
	chmod 644 APKINDEX.tar.gz
537
538
}

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

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

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

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

565
566
567
568
doc() {
	default_doc
}

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

582
583
584
585
mod() {
	default_mod
}

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

612
613
614
615
dev() {
	default_dev
}

616
617
618
619
is_function() {
	type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
}

Natanael Copa's avatar
Natanael Copa committed
620
621
# build and package in fakeroot
rootpkg() {
622
623
624
625
626
	local do_build=build
	cd "$startdir"
	if is_function package; then
		msg "Building without fakeroot"
		build || return 1
627
		do_build=package
628
	fi
Natanael Copa's avatar
Natanael Copa committed
629
	cd "$startdir"
630
	msg "Entering fakeroot..."
631
632
	fakeroot "$abuild_path" $do_build prepare_subpackages prepare_package \
		create_apks
Natanael Copa's avatar
Natanael Copa committed
633
634
635
}

srcpkg() {
636
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
637
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
638
639
640
641
642
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
643
	msg "Creating source package $p.src.tar.gz..."
644
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
645
646
}

647
# check if package is up to date
648
apk_up2date() {
649
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
650
	local i s
Natanael Copa's avatar
Natanael Copa committed
651
	cd "$startdir"
652
653
654
655
656
	for i in $pkgname $subpackages; do
		[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
	done
	[ -n "$keep" ] && return 0

657
	for i in $source APKBUILD; do
658
659
660
661
662
663
		local s
		if is_remote "$i"; then
			s="$SRCDEST/${i##*/}"	# $(basename $i)
		else
			s="$startdir/${i##*/}"
		fi
664
665
666
667
668
669
670
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

671
672
673
674
cache_up2date() {
	local i apk
	for i in $pkgname $subpackages; do
		apk="${i%:*}-$pkgver-r$pkgrel.apk"
675
		[ "$apkcache"/APKINDEX.tar.gz -nt "$apkcache"/$apk ] || return 1
676
677
678
679
680
681
682
683
	done
	return 0
}

up2date() {
	apk_up2date && cache_up2date
}

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

722
deptrace() {
723
724
725
726
727
	local deps= i=
	# strip versions from deps
	for i in "$@"; do
		deps="$deps ${i%[<>=]*}"
	done
728
	[ -z "$deps" ] && return 0
729
730
731
	( 	depparse_aports 
		if [ -z "$upgrade" ]; then
			# list installed pkgs and prefix with 'i '
Natanael Copa's avatar
abuild:    
Natanael Copa committed
732
			apk info -q | sort |  sed 's/^/i /'
733
		fi
734
	) | awk -v pkgs="$deps" '
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759

	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() {
760
761
	local deps= alldeps= pkg= i= dir= ver= missing= installed_deps=
	local filtered_deps=
762
	[ -n "$nodeps" ] && return 0
763
	msg "Analyzing dependencies..."
764
765
766
767
	deps="$BUILD_BASE $makedepends"

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

771
	installed_deps=$(apk info -e $deps)
772
	# find which deps are missing
773
	for i in $deps; do
774
		if [ "${i#\!}" != "$i" ]; then
775
			list_has ${i#\!} $installed_deps \
776
				&& die "Conflicting package ${i#\!} is installed."
777
		elif ! deplist_has $i $installed_deps; then
778
779
780
781
782
783
784
			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

785
786
	[ -z "$missing" ] && [ -z "$install_deps" ] && [ -z "$recursive" ] \
		&& return 0
787

788
	uninstall_after=".makedepends-$pkgname $uninstall_after"
789
	if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
790
		$SUDO apk add --repository "$apkcache" \
791
792
			--virtual .makedepends-$pkgname $deps \
			&& return 0
793
	fi
794
795
	
	[ -z "$recursive" ] && return 1
796
797
798

	# find dependencies that are installed but missing in repo.
	for i in $deps; do
799
		local m=$(apk search --repository "$apkcache" ${i%[<>=]*})
Natanael Copa's avatar
Natanael Copa committed
800
		if [ -z "$m" ]; then
801
802
803
			missing="$missing $i"
		fi
	done
804
805
	
	for i in $(deptrace $missing); do
806
807
808
809
		# i = pkg:dir
		local dir=${i#*:}
		local pkg=${i%:*}
		msg "Entering $dir"
810
		cd "$dir" && $0 -k -r apkcache || return 1
811
	done
812
	$SUDO apk add -u --repository "$apkcache" \
813
		--virtual .makedepends-$pkgname $deps
814
815
}

816
# replace the md5sums in the APKBUILD
Natanael Copa's avatar
Natanael Copa committed
817
818
checksum() {
	local s files
819
	[ -z "$source" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
820
	fetch
821
	msg "Updating the md5sums in APKBUILD..."
Natanael Copa's avatar
Natanael Copa committed
822
823
824
825
	for s in $source; do
		files="$files ${s##*/}"
	done
	md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
826
827
	sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
	echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
Natanael Copa's avatar
Natanael Copa committed
828
829
}

830
stripbin() {
831
	local bin
832
	options_has "!strip" && return 0
833
834
	cd "${subpkgdir:-$pkgdir}" || return 1
	msg "Stripping binaries"
835
	find . -type f 2>/dev/null | while read bin; do
836
837
838
839
840
841
842
843
844
845
846
		local opt=
		case "$(file -biz "$bin")" in
			*/x-sharedlib*|*/x-archive*)
				strip --strip-debug "$bin";;
			*/x-executable*)
				strip "$bin";;
		esac
	done
	return 0
}

847
848
849
850
851
852
853
854
# 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
855
856
857
858
859
860
861
862
source_has() {
	local i
	for i in $source; do
		[ "$1" = "${i##*/}" ] && return 0
	done
	return 1
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
863
864
865
866
867
868
869
870
subpackages_has() {
	local i
	for i in $subpackages; do
		[ "$1" = "${i%:*}" ] && return 0
	done
	return 1
}

871
872
873
874
875
876
877
878
879
880
881
list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" = "$i" ] && return 0
		[ "$needle" = "!$i" ] && return 1
	done
	return 1
}

882
883
884
885
886
887
888
889
890
891
892
893
894
# 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
}

895
896
897
898
options_has() {
	list_has "$1" $options
}

899
depends_has() {
900
	deplist_has "$1" $depends
901
902
}

Natanael Copa's avatar
Natanael Copa committed
903
makedepends_has() {
904
	deplist_has "$1" $makedepends
Natanael Copa's avatar
Natanael Copa committed
905
906
}

Natanael Copa's avatar
Natanael Copa committed
907
908
909
910
md5sums_has() {
	list_has "$1" $md5sums
}

Natanael Copa's avatar
Natanael Copa committed
911
912
913
914
install_has() {
	list_has "$1" $install
}

Natanael Copa's avatar
abuild:    
Natanael Copa committed
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# 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
929
	$SUDO apk add -u "$pkgf" || die "Failed to install $1"
Natanael Copa's avatar
abuild:    
Natanael Copa committed
930
931
}

932
installdeps() {
933
	local deps i
934
	sudo apk add --repository "$apkcache" --virtual .makedepends-$pkgname \
935
		$makedepends
936
937
938
}

uninstalldeps (){
939
	sudo apk del .makedepends-$pkgname
940
}
941
942
943
944
945
946
947
948
949

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

Natanael Copa's avatar
Natanael Copa committed
950
usage() {
951
952
	echo "$program $abuild_ver"
	echo "usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]"
953
	echo "              [-s SRCDEST] [cmd] ..."
954
	echo "       $program [-c] -n PKGNAME[-PKGVER]"
Natanael Copa's avatar
Natanael Copa committed
955
	echo "Options:"
956
	echo " -d  Disable dependency checking"
Natanael Copa's avatar
Natanael Copa committed
957
	echo " -f  Force specified cmd, even if they are already done"
958
959
	echo " -h  Show this help"
	echo " -i  Install PKG after successul build"
960
	echo " -k  Keep built packages, even if APKBUILD or sources are newer"
961
	echo " -p  Set package destination directory"
962
	echo " -P  Set PKGDEST to REPODEST/<repo>, where repo is the parents dir name" 
Natanael Copa's avatar
Natanael Copa committed
963
	echo " -q  Quiet"
964
965
	echo " -r  Install missing dependencies from system repository (using sudo)"
	echo " -R  Recursively build and install missing dependencies (using sudo)"
966
	echo " -s  Set source package destination directory"
967
	echo " -u  Recursively build and upgrade all dependencies (using sudo)"
Natanael Copa's avatar
Natanael Copa committed
968
969
	echo ""
	echo "Commands:"
970
	echo "  checksum    Generate checksum to be included in APKBUILD"
971
972
973
974
975
	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"
976
	echo "  listpkg     List target packages"
977
978
979
	echo "  package     Create package in \$PKGDEST"
	echo "  rootpkg     Run '$0 build package' as fakeroot"
	echo "  clean       Remove temp build and install dirs"
980
	echo "  cleanoldpkg Remove binary packages except current version"
981
982
983
984
	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"
985
986
	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
987
988
989
990
991
	echo ""
	exit 0
}

APKBUILD="${APKBUILD:-./APKBUILD}"
992
993
unset force
unset recursive
994
while getopts "dfhi:kinp:P:qrRs:u" opt; do
Natanael Copa's avatar
Natanael Copa committed
995
	case $opt in
996
		'd') nodeps=1;;
Natanael Copa's avatar
Natanael Copa committed
997
		'f') force=1;;
998
999
		'h') usage;;
		'i') install_after="$install_after $OPTARG";;
1000
		'k') keep=1;;
1001
		'n') die "Use newapkbuild to create new aports";;
1002
		'p') PKGDEST=$OPTARG;;
1003
		'P') REPODEST=$OPTARG;;
Natanael Copa's avatar
Natanael Copa committed
1004
		'q') quiet=1;;
1005
1006
		'r') install_deps=1;;
		'R') recursive=1;;
1007
		's') SRCDEST=$OPTARG;;
1008
1009
		'u') upgrade=1
		     recursive=1;;
Natanael Copa's avatar
Natanael Copa committed
1010
1011
1012
1013
	esac
done
shift $(( $OPTIND - 1 ))

1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
# 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"

1031
1032
1033
1034
1035
# If REPODEST is set then it will override the PKGDEST
if [ -n "$REPODEST" ]; then
	PKGDEST="$REPODEST/$repo"
fi

1036
# If we are handling a sub package then reset subpackages and install
1037
if [ -n "$subpkgname" ]; then
1038
	origsubpackages="$subpackages"
1039
	subpackages=
1040
	install=
1041
fi
1042
pkgdir="$pkgbasedir/$pkgname"
1043
controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
Natanael Copa's avatar
Natanael Copa committed
1044
1045

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

if [ -z "$1" ]; then
1049
	set all
Natanael Copa's avatar
Natanael Copa committed
1050
1051
1052
1053
1054
1055
fi

while [ $# -gt 0 ]; do
	runpart $1
	shift
done
1056
1057

for i in $install_after; do
Natanael Copa's avatar
abuild:    
Natanael Copa committed
1058
	post_add $i
1059
1060
done

Linux User's avatar
Linux User committed
1061
cleanup
Natanael Copa's avatar
Natanael Copa committed
1062