abuild 11.1 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
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 196 197
	for i in $pkgname $subpackages; do
		local p="$i-$pkgver-$pkgrel"
		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"
}

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() {
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
228 229
		local func=$(get_split_func $i)
		# call abuild recursively, setting subpkg{dir,name}
230
		msg "Running split function $func..."
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

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

318
	[ -d "$subpkgdir/usr/share/man" ] && depends="man"
Natanael Copa's avatar
Natanael Copa committed
319 320 321
	return 0
}

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

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

# build and package in fakeroot
rootpkg() {
Natanael Copa's avatar
Natanael Copa committed
350
	cd "$startdir"
351
	msg "Entering fakeroot..."
Natanael Copa's avatar
Natanael Copa committed
352 353 354 355
	fakeroot $0 build subpkg package
}

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

367 368
# check if package is up to date
up2date() {
369
	local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
370
	local i s
Natanael Copa's avatar
Natanael Copa committed
371
	cd "$startdir"
372 373 374 375 376 377 378 379 380 381
	[ -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
}

382 383 384
# note: this must run in a subshell
find_aport() {
	local i
385
	msg "Searching for $1 in aports tree..."
386 387
	cd ../..
	for i in */*/APKBUILD; do
388
		pkgrel=
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
		. $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
405
		[ -z "$upgrade" ] && apk_info -e $dep && continue
406
		[ -z "$recursive" ] && die "Missing dependency $dep. Use -r to build recursively"
407 408 409 410 411 412
		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
413
		# recursively build deps
414
		msg "Entering ${pkg%/*}"
415
		cd ${pkg%/*} 
416 417
		$0 -r ${upgrade:+-u} || return 1
		sudo apk_add ${upgrade:+-u} $pkg
418 419 420
	done
}

Natanael Copa's avatar
Natanael Copa committed
421 422 423 424 425 426 427
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"
428 429
	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
430 431
	echo ""
	echo "Commands:"
432 433 434 435 436 437 438 439 440 441 442 443 444
	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
445 446 447 448 449 450
	echo ""
	exit 0
}

checksum() {
	local s files
451
	fetch
Natanael Copa's avatar
Natanael Copa committed
452 453 454
	for s in $source; do
		files="$files ${s##*/}"
	done
455 456
	md5sums="$(cd "$SRCDEST" && md5sum $files)" || die "md5sum failed"
	echo "md5sums=\"$md5sums\""
Natanael Copa's avatar
Natanael Copa committed
457 458 459 460
}

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

461
while getopts "hfqru" opt; do
Natanael Copa's avatar
Natanael Copa committed
462 463 464 465
	case $opt in
		'h') usage;;
		'f') force=1;;
		'q') quiet=1;;
466
		'r') recursive=1;;
467 468
		'u') upgrade=1
		     recursive=1;;
Natanael Copa's avatar
Natanael Copa committed
469 470 471 472 473 474 475 476
	esac
done
shift $(( $OPTIND - 1 ))

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

477
# If we are handling a sub package then reset subpackages
478 479 480
if [ -n "$subpkgname" ]; then
	subpackages=
fi
Natanael Copa's avatar
Natanael Copa committed
481 482

trap 'die "Aborted by user"' INT
Linux User's avatar
Linux User committed
483
set_xterm_title "abuild: $pkgname"
Natanael Copa's avatar
Natanael Copa committed
484 485 486


if [ -z "$1" ]; then
Natanael Copa's avatar
Natanael Copa committed
487
	if up2date && [ -z "$force" ]; then
Natanael Copa's avatar
Natanael Copa committed
488
		msg "Package is up to date"
489 490 491
	else
		set $default_cmds
	fi
Natanael Copa's avatar
Natanael Copa committed
492 493 494 495 496 497
fi

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