abuild 11.3 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1
2
3
4
5
6
7
8
9
10
#!/bin/sh

# script to build apk packages (light version og makepkg)
# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
#
# Distributed under GPL-2
#
# Depends on: busybox utilities, fakeroot, 
#

Natanael Copa's avatar
v0.7    
Natanael Copa committed
11
myver=0.7
Natanael Copa's avatar
Natanael Copa committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# read config
MAKEAPK_CONF=${MAKEAPK_CONF:-/etc/abuild.conf}
[ -f "$MAKEAPK_CONF" ] && . "$MAKEAPK_CONF"

startdir="$PWD"
srcdir=${srcdir:-"$startdir/src"}
pkgdir=${pkgdir:-"$startdir/pkg"}
pkgrel=0

# defaults
SRCDEST=${SRCDEST:-$startdir}
PKGDEST=${PKGDEST:-$startdir}

26
default_cmds="sanitycheck builddeps clean fetch md5check unpack rootpkg"
Natanael Copa's avatar
Natanael Copa committed
27

Linux User's avatar
Linux User committed
28
29
30
31
32
33
34
35
36
37
38
#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	
	

Natanael Copa's avatar
Natanael Copa committed
39
# functions
Natanael Copa's avatar
Natanael Copa committed
40
msg() {
Linux User's avatar
Linux User committed
41
42
43
44
	local prompt="$GREEN>>>${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}(fakeroot)${NORMAL} }"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	[ -z "$quiet" ] && printf "${prompt} ${fake}${name}: $@\n" >&2
Natanael Copa's avatar
Natanael Copa committed
45
46
47
}

warning() {
Linux User's avatar
Linux User committed
48
49
50
51
52
53
54
55
56
57
58
	local prompt="${YELLOW}>>> WARNING: ${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}(fakeroot)${NORMAL} }"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	printf "${prompt} ${fake}${name}: $@\n" >&2
}

error() {
	local prompt="${RED}>>> ERROR: ${NORMAL}"
	local fake="${FAKEROOTKEY:+${BLUE}(fakeroot)${NORMAL} }"
	local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
	printf "${prompt} ${fake}${name}: $@\n" >&2
Natanael Copa's avatar
Natanael Copa committed
59
60
}

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

cleanup() {
	set_xterm_title ""
}

Natanael Copa's avatar
Natanael Copa committed
71
die() {
Linux User's avatar
Linux User committed
72
	error "$@"
Linux User's avatar
Linux User committed
73
	cleanup
Natanael Copa's avatar
Natanael Copa committed
74
75
76
	exit 1
}

77
78
# check if apkbuild is basicly sane
sanitycheck() {
79
	msg "Checking sanity of $APKBUILD..."
80
81
82
	[ -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
83
	[  "${pkgver##[0-9]}" == "$pkgver" ] && \
84
85
86
87
88
89
		die "pkgver does not start with a digit"
	[ -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"

90
91
92
93
	if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
		die "Number of md5sums does not correspond to number of sources"
	fi

94
95
96
97
98
99
100
	# common spelling errors
	[ -n "$depend" ] && die "APKBUILD contains 'depend'. It should be depends"
	[ -n "$makedepend" ] && die "APKBUILD contains 'makedepend'. It should be makedepends"
	return 0
}

md5check() {
101
102
103
	if [ -z "$source" ]; then
		return 0
	fi
104
105
106
	if [ -z "$md5sums" ]; then
		die "Use 'abuild checksum >>$APKBUILD' to generate a checksum"
	fi
107
108
109
110

	if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
		die "Number of md5sums does not correspond to number of sources"
	fi
111
	msg "Checking md5sums..."
112
	cd "$srcdir" && echo "$md5sums" | md5sum -c 
Natanael Copa's avatar
Natanael Copa committed
113
114
115
116
117
}

uri_fetch() {
	local uri="$1"
	local d="${s##*/}"	# $(basename $s)
118
119
120
121
	local opts
	[ -n "$quiet" ] && opts="-q"
	[ -f "$SRCDEST/$d" ] && return 0

Natanael Copa's avatar
Natanael Copa committed
122
	mkdir -p "$SRCDEST"
123
124
125
	if [ -f "$SRCDEST/$d.part" ]; then
		msg "Partial download found. Trying to resume"
		opts="$opts -c"
Natanael Copa's avatar
Natanael Copa committed
126
	fi
Linux User's avatar
Linux User committed
127
	msg "Fetching $uri"
128
129
	wget $opts -O "$SRCDEST/$d.part" "$uri" \
		&& mv "$SRCDEST/$d.part" "$SRCDEST/$d"
Natanael Copa's avatar
Natanael Copa committed
130
131
132
133
134
135
136
137
138
}

fetch() {
	local s
	mkdir -p "$srcdir"
	for s in $source; do 
		case "$s" in
			http://*|ftp://*)
				uri_fetch "$s" || return 1
139
140
141
				ln -sf "$SRCDEST/${s##*/}" "$srcdir"/
				;;
			*)
Linux User's avatar
Linux User committed
142
				ln -sf "$startdir/$s" "$srcdir/"
Natanael Copa's avatar
Natanael Copa committed
143
144
145
146
147
148
149
150
151
152
153
154
				;;
		esac
	done
}

# unpack the sources
unpack() {
	local u
	mkdir -p "$srcdir"
	for u in $source; do
		local s="$SRCDEST/${u##*/}"	# $(basename $s)
		case "$s" in
Natanael Copa's avatar
Natanael Copa committed
155
			*.tar.gz|*.tgz)
156
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
157
158
				tar -C "$srcdir" -zxf "$s" || return 1;;
			*.tar.bz2)
159
				msg "Unpacking $s..."
Natanael Copa's avatar
Natanael Copa committed
160
				tar -C "$srcdir" -jxf "$s" || return 1;;
161
162
163
164
			*.tar.lzma)
				msg "Unpacking $s..."
				unlzma -c "$s" | tar -C "$srcdir" -x  \
					|| return 1;;
Natanael Copa's avatar
Natanael Copa committed
165
166
167
168
169
170
		esac
	done
}

# cleanup source and package dir
clean() {
171
	msg "Cleaning temporary build dirs..."
Natanael Copa's avatar
Natanael Copa committed
172
173
174
	rm -rf "$srcdir"
	rm -rf "$pkgdir"
	local i
Natanael Copa's avatar
Natanael Copa committed
175
176
	for i in $subpackages; do
		rm -rf "$pkgdir-$(get_split_func $i)"
Natanael Copa's avatar
Natanael Copa committed
177
178
179
180
181
182
183
184
	done
}

# cleanup fetched sources
cleancache() {
	local s
	for s in $source; do
		case "$s" in
185
186
187
			http://*|ftp://*)
				msg "Cleaning downloaded ${s##*/}..."
				rm -f "$SRCDEST/${s##*/}";;
Natanael Copa's avatar
Natanael Copa committed
188
189
190
191
192
193
		esac
	done
}

cleanpkg() {
	local i
194
	msg "Cleaning built packages..."
195
	for i in $pkgname $subpackages; do
196
		local p="$i-$pkgver-r$pkgrel"
197
		rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz"
Natanael Copa's avatar
Natanael Copa committed
198
199
200
201
202
	done
}

runpart() {
	local part=$1
203
	[ -n "$DEBUG" ] && msg "$part"
Natanael Copa's avatar
Natanael Copa committed
204
205
206
207
208
209
210
211
	$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
212
213
214
215
216
217
218
219
220
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
}

Natanael Copa's avatar
Natanael Copa committed
221
subpkg() {
Natanael Copa's avatar
Natanael Copa committed
222
	if [ -z "$subpackages" ]; then
223
224
		return 0
	fi
Natanael Copa's avatar
Natanael Copa committed
225
226
	local i
	cd "$startdir"
227
	for i in $subpackages; do
Natanael Copa's avatar
Natanael Copa committed
228
229
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
230
		msg "Running split function $func..."
Natanael Copa's avatar
Natanael Copa committed
231
232
		subpkgdir="$startdir/pkg-$func" subpkgname="$i" \
			$0 $func package || return 1
Natanael Copa's avatar
Natanael Copa committed
233
234
235
236
	done
}

package_apk() {
237
238
	local name=${subpkgname:-$pkgname}
	[ -z "${name##* *}" ] && die "package name contains spaces"
239
	local dir=${subpkgdir:-$pkgdir}
240
	local pkg="$name-$pkgver-r$pkgrel.apk"
241
	local sub
Natanael Copa's avatar
Natanael Copa committed
242
243
244
	
	[ ! -d "$dir" ] && die "Missing $dir"
	cd "$dir"
245
	msg "Creating ${subpkgname:+sub}package $pkg..."
Natanael Copa's avatar
Natanael Copa committed
246
247
248
249
250
251
252
253
254
	local builddate=$(date -u "+%s")
	local size=$(du -sk | awk '{print $1 * 1024}')

	echo "# Generated by $(basename $0) $myver" >.PKGINFO
	if [ -n "$FAKEROOTKEY" ]; then
		echo "# using $(fakeroot -v)" >> .PKGINFO
	fi
	echo "# $(date -u)" >> .PKGINFO
	cat >> .PKGINFO <<EOF
255
pkgname = $name
256
pkgver = $pkgver-r$pkgrel
Natanael Copa's avatar
Natanael Copa committed
257
258
259
260
261
262
pkgdesc = $pkgdesc
url = $url
builddate = $builddate
packager = ${PACKAGER:-"Unknown"}
size = $size
EOF
Natanael Copa's avatar
Natanael Copa committed
263
	local i
Natanael Copa's avatar
Natanael Copa committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

	for i in $license; do
		echo "license = $i" >>.PKGINFO
	done
	for i in $replaces; do
		echo "replaces = $i" >>.PKGINFO
	done
	for i in $depends; do
		echo "depend = $i" >>.PKGINFO
	done
	for i in $conflicts; do
		echo "conflict = $i" >>.PKGINFO
	done
	for i in $provides; do
		echo "provides = $i" >>.PKGINFO
	done
	for i in $backup; do
		echo "backup = $i" >>.PKGINFO
	done

	local metafiles=".PKGINFO"
Natanael Copa's avatar
Natanael Copa committed
285
286
287
	if [ -n "$install" ]; then
		cp "$srcdir/$install" "$dir/.INSTALL" || return 1
		chmod +x "$dir/.INSTALL"
Natanael Copa's avatar
Natanael Copa committed
288
		metafiles="$metafiles .INSTALL"
Natanael Copa's avatar
Natanael Copa committed
289
	fi
Natanael Copa's avatar
Natanael Copa committed
290
291
292
293
294
295
296
297

#	for i in pre-install post-install pre-deinstall post-deinstall; do
#		[ -f ../$i ] && cp ../$i "$db"/
#	done
	
	set *
	[ "$1" = '*' ] && set --
	( cd "$dir" && tar -zcf "$PKGDEST/$pkg" $metafiles $@ )
Natanael Copa's avatar
Natanael Copa committed
298
299
300
301
302
303
}

package() {
	package_apk
}

304
# predefined splitfunc doc
Natanael Copa's avatar
Natanael Copa committed
305
306
307
308
doc() {
	depends=""
	local i
	for i in doc man info html sgml; do
309
310
311
		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
312
313
		fi
	done
314
315
316
317
318
319
	
	rm -f "$subpkgdir/usr/share/info/dir"

	# compress info and man pages
	find "$subpkgdir/usr/share" \( -name '*.info' -o name '*.info-[1-9]' \
		-o -name '*.[1-9]' \) -exec gzip {} \;
320
321
322
323

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

324
	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
325
326
327
	return 0
}

328
# predefined splitfunc mod
Natanael Copa's avatar
Natanael Copa committed
329
330
331
mod() {
	depends="$kernel"
	for i in firmware modules; do
332
333
334
		if [ -d "$pkgdir/lib/$i" ]; then
			rm -rf "$subpkgdir/lib"
			mkdir -p "$subpkgdir/lib"
335
			mv "$pkgdir/lib/$i" "$subpkgdir/lib"
Natanael Copa's avatar
Natanael Copa committed
336
337
338
339
		fi
	done
}

340
# predefined splitfunc dev
Natanael Copa's avatar
Natanael Copa committed
341
dev() {
342
343
	depends="$pkgname"
	for i in $(cd "$pkgdir" && find usr/lib -name '*.a' -o \
Natanael Copa's avatar
Natanael Copa committed
344
345
			-name '*.la' -o -name '*.o' 2>/dev/null) \
			usr/include usr/lib/pkgconfig usr/share/aclocal; do
346
347
		if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
			d="$subpkgdir/${i%/*}"	# dirname $i
Natanael Copa's avatar
Natanael Copa committed
348
			mkdir -p "$d"
349
			mv "$pkgdir/$i" "$d"
Natanael Copa's avatar
Natanael Copa committed
350
351
352
353
354
355
		fi
	done
}

# build and package in fakeroot
rootpkg() {
Natanael Copa's avatar
Natanael Copa committed
356
	cd "$startdir"
357
	msg "Entering fakeroot..."
Natanael Copa's avatar
Natanael Copa committed
358
359
360
361
	fakeroot $0 build subpkg package
}

srcpkg() {
362
	local p="$pkgname-$pkgver-$pkgrel"
Natanael Copa's avatar
Natanael Copa committed
363
	local prefix="${startdir##*/}"
Natanael Copa's avatar
Natanael Copa committed
364
365
366
367
368
	local i files="$prefix/APKBUILD"
	for i in $source; do
		files="$files $prefix/${i##*/}"
	done
	mkdir -p "$PKGDEST"
369
	msg "Creating source package $p.src.tar.gz..."
370
	(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files) 
Natanael Copa's avatar
Natanael Copa committed
371
372
}

373
374
# check if package is up to date
up2date() {
375
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
376
	local i s
Natanael Copa's avatar
Natanael Copa committed
377
	cd "$startdir"
378
379
380
381
382
383
384
385
386
387
	[ -f "$pkg" ] || return 1
	for i in $source APKBUILD; do
		local s="$SRCDEST/${i##*/}"	# $(basename $i)
		if [ "$s" -nt "$pkg" ]; then
			return 1
		fi
	done
	return 0
}

388
389
390
# note: this must run in a subshell
find_aport() {
	local i
391
	msg "Searching for $1 in aports tree..."
392
393
	cd ../..
	for i in */*/APKBUILD; do
394
		pkgrel=
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
		. $i
		local j
		for j in $pkgname $subpackages; do
			if [ "${j%%:*}" = "$1" ]; then
				echo "$PWD/${i%/APKBUILD}/$1-$pkgver-r$pkgrel.apk"
				return 0
			fi
		done
	done
	return 1
}

# recursively build and install dependencies
builddeps() {
	local dep pkg
	for dep in $depends $makedepends; do
411
		[ -z "$upgrade" ] && apk_info -e $dep && continue
412
		[ -z "$recursive" ] && die "Missing dependency $dep. Use -r to build recursively"
413
414
415
416
417
418
		pkg=$(find_aport $dep) 
		if [ -z "$pkg" ]; then
			# try install from system repo as fallback
			apk_add ${upgrade:+-u} $dep && continue
			die "Failed to find dependency $dep"
		fi
419
		# recursively build deps
420
		msg "Entering ${pkg%/*}"
421
		cd ${pkg%/*} 
422
423
		$0 -r ${upgrade:+-u} || return 1
		sudo apk_add ${upgrade:+-u} $pkg
424
425
426
	done
}

Natanael Copa's avatar
Natanael Copa committed
427
428
429
430
431
432
433
usage() {
	echo "$(basename $0) $myver"
	echo "usage: $0 [options] [cmd] ..."
	echo "Options:"
	echo " -h  Show this help"
	echo " -f  Force specified cmd, even if they are already done"
	echo " -q  Quiet"
434
435
	echo " -r  Recursively build and install missing dependencies (using sudo)"
	echo " -u  Recursively build and upgrade dependencies (using sudo)"
Natanael Copa's avatar
Natanael Copa committed
436
437
	echo ""
	echo "Commands:"
438
439
440
441
442
443
444
445
446
447
448
449
450
	echo "  checksum    Generate checksum to be included in $APKBUILD"
	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"
	echo "  package     Create package in \$PKGDEST"
	echo "  rootpkg     Run '$0 build package' as fakeroot"
	echo "  clean       Remove temp build and install dirs"
	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"
Natanael Copa's avatar
Natanael Copa committed
451
452
453
454
455
456
	echo ""
	exit 0
}

checksum() {
	local s files
457
	fetch
Natanael Copa's avatar
Natanael Copa committed
458
459
460
	for s in $source; do
		files="$files ${s##*/}"
	done
461
462
	md5sums="$(cd "$SRCDEST" && md5sum $files)" || die "md5sum failed"
	echo "md5sums=\"$md5sums\""
Natanael Copa's avatar
Natanael Copa committed
463
464
465
466
}

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

467
while getopts "hfqru" opt; do
Natanael Copa's avatar
Natanael Copa committed
468
469
470
471
	case $opt in
		'h') usage;;
		'f') force=1;;
		'q') quiet=1;;
472
		'r') recursive=1;;
473
474
		'u') upgrade=1
		     recursive=1;;
Natanael Copa's avatar
Natanael Copa committed
475
476
477
478
479
480
481
482
	esac
done
shift $(( $OPTIND - 1 ))

# source the buildfile
[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
. "$APKBUILD"

Natanael Copa's avatar
Natanael Copa committed
483
# If we are handling a sub package then reset subpackages
484
485
486
if [ -n "$subpkgname" ]; then
	subpackages=
fi
Natanael Copa's avatar
Natanael Copa committed
487
488

trap 'die "Aborted by user"' INT
Linux User's avatar
Linux User committed
489
set_xterm_title "abuild: $pkgname"
Natanael Copa's avatar
Natanael Copa committed
490
491
492


if [ -z "$1" ]; then
Natanael Copa's avatar
Natanael Copa committed
493
	if up2date && [ -z "$force" ]; then
Natanael Copa's avatar
Natanael Copa committed
494
		msg "Package is up to date"
495
496
497
	else
		set $default_cmds
	fi
Natanael Copa's avatar
Natanael Copa committed
498
499
500
501
502
503
fi

while [ $# -gt 0 ]; do
	runpart $1
	shift
done
Linux User's avatar
Linux User committed
504
cleanup
Natanael Copa's avatar
Natanael Copa committed
505