mirror of
https://gitlab.alpinelinux.org/alpine/abuild.git
synced 2024-12-23 15:33:28 +00:00
646 lines
14 KiB
Bash
Executable File
646 lines
14 KiB
Bash
Executable File
#!/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,
|
|
#
|
|
|
|
abuild_ver=1.6
|
|
|
|
startdir="$PWD"
|
|
srcdir=${srcdir:-"$startdir/src"}
|
|
pkgdir=${pkgdir:-"$startdir/pkg"}
|
|
pkgrel=0
|
|
repo=${startdir%/*}
|
|
repo=${repo##*/}
|
|
|
|
# defaults
|
|
SRCDEST=${SRCDEST:-$startdir}
|
|
PKGDEST=${PKGDEST:-$startdir}
|
|
BUILD_BASE="binutils gcc make patch uclibc-dev"
|
|
|
|
default_cmds="sanitycheck builddeps clean fetch unpack rootpkg"
|
|
|
|
# read config
|
|
ABUILD_CONF=${ABUILD_CONF:-"/etc/abuild.conf"}
|
|
[ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF"
|
|
|
|
# If REPODEST is set then it will override the PKGDEST
|
|
if [ -n "$REPODEST" ]; then
|
|
PKGDEST="$REPODEST/$repo"
|
|
fi
|
|
|
|
# source functions
|
|
# if abuild was not run from PATH, then look for func lib at same location
|
|
if [ -z "$FUNCLIB" ]; then
|
|
FUNCLIB="${0##/*}/functions.sh"
|
|
[ -f "$FUNCLIB" ] || FUNCLIB=/usr/share/abuild/functions.sh
|
|
fi
|
|
|
|
if ! [ -f "$FUNCLIB" ]; then
|
|
echo "$FUNCLIB: not found" >&2
|
|
exit 1
|
|
fi
|
|
. "$FUNCLIB"
|
|
|
|
set_xterm_title() {
|
|
if [ "$TERM" = xterm ]; then
|
|
printf "\033]0;$1\007" >&2
|
|
fi
|
|
}
|
|
|
|
cleanup() {
|
|
set_xterm_title ""
|
|
if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
|
|
sudo apk del $uninstall_after
|
|
fi
|
|
}
|
|
|
|
die() {
|
|
error "$@"
|
|
cleanup
|
|
exit 1
|
|
}
|
|
|
|
# check if apkbuild is basicly sane
|
|
sanitycheck() {
|
|
msg "Checking sanity of $APKBUILD..."
|
|
[ -z "$pkgname" ] && die "Missing pkgname in APKBUILD"
|
|
[ -z "${pkgname##* *}" ] && die "pkgname contains spaces"
|
|
[ -z "$pkgver" ] && die "Missing pkgver in APKBUILD"
|
|
[ "${pkgver##[0-9]}" == "$pkgver" ] && \
|
|
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"
|
|
|
|
if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
|
|
die "Number of md5sums does not correspond to number of sources"
|
|
fi
|
|
|
|
# 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() {
|
|
if [ -z "$source" ]; then
|
|
return 0
|
|
fi
|
|
if [ -z "$md5sums" ]; then
|
|
die "Use 'abuild checksum' to generate/update the checksum(s)"
|
|
fi
|
|
|
|
if [ "$(echo $source | wc -l)" -ne "$(echo $md5sums | wc -l)" ]; then
|
|
die "Number of md5sums does not correspond to number of sources"
|
|
fi
|
|
fetch || return 1
|
|
msg "Checking md5sums..."
|
|
cd "$srcdir" && echo "$md5sums" | md5sum -c
|
|
}
|
|
|
|
uri_fetch() {
|
|
local uri="$1"
|
|
local d="${s##*/}" # $(basename $s)
|
|
local opts
|
|
[ -n "$quiet" ] && opts="-q"
|
|
[ -f "$SRCDEST/$d" ] && return 0
|
|
|
|
mkdir -p "$SRCDEST"
|
|
if [ -f "$SRCDEST/$d.part" ]; then
|
|
msg "Partial download found. Trying to resume"
|
|
opts="$opts -c"
|
|
fi
|
|
msg "Fetching $uri"
|
|
wget $opts -O "$SRCDEST/$d.part" "$uri" \
|
|
&& mv "$SRCDEST/$d.part" "$SRCDEST/$d"
|
|
}
|
|
|
|
is_remote() {
|
|
case "$1" in
|
|
http://*|ftp://*)
|
|
return 0;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
fetch() {
|
|
local s
|
|
mkdir -p "$srcdir"
|
|
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
|
|
done
|
|
}
|
|
|
|
# unpack the sources
|
|
unpack() {
|
|
local u
|
|
md5check || return 1
|
|
mkdir -p "$srcdir"
|
|
for u in $source; do
|
|
local s="$SRCDEST/${u##*/}" # $(basename $s)
|
|
case "$s" in
|
|
*.tar.gz|*.tgz)
|
|
msg "Unpacking $s..."
|
|
tar -C "$srcdir" -zxf "$s" || return 1;;
|
|
*.tar.bz2)
|
|
msg "Unpacking $s..."
|
|
tar -C "$srcdir" -jxf "$s" || return 1;;
|
|
*.tar.lzma)
|
|
msg "Unpacking $s..."
|
|
unlzma -c "$s" | tar -C "$srcdir" -x \
|
|
|| return 1;;
|
|
*.zip)
|
|
msg "Unpacking $s..."
|
|
unzip "$s" -d "$srcdir" || return 1;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# cleanup source and package dir
|
|
clean() {
|
|
msg "Cleaning temporary build dirs..."
|
|
rm -rf "$srcdir"
|
|
rm -rf "$pkgdir"
|
|
local i
|
|
for i in $subpackages; do
|
|
rm -rf "$pkgdir-$(get_split_func $i)"
|
|
done
|
|
}
|
|
|
|
# cleanup fetched sources
|
|
cleancache() {
|
|
local s
|
|
for s in $source; do
|
|
if is_remote "$s"; then
|
|
msg "Cleaning downloaded ${s##*/}..."
|
|
rm -f "$SRCDEST/${s##*/}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
cleanpkg() {
|
|
local i
|
|
msg "Cleaning built packages..."
|
|
for i in $pkgname $subpackages; do
|
|
local p="$i-$pkgver-r$pkgrel"
|
|
rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz"
|
|
done
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
runpart() {
|
|
local part=$1
|
|
[ -n "$DEBUG" ] && msg "$part"
|
|
$part || die "$part failed"
|
|
}
|
|
|
|
# override those in your build script
|
|
build() {
|
|
die "No build() function found in $APKBUILD"
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
subpkg() {
|
|
if [ -z "$subpackages" ]; then
|
|
return 0
|
|
fi
|
|
local i
|
|
cd "$startdir"
|
|
for i in $subpackages; do
|
|
local func=$(get_split_func $i)
|
|
# call abuild recursively, setting subpkg{dir,name}
|
|
msg "Running split function $func..."
|
|
subpkgdir="$startdir/pkg-$func" subpkgname="${i%:*}" \
|
|
$0 $func package || return 1
|
|
done
|
|
}
|
|
|
|
package_apk() {
|
|
local name=${subpkgname:-$pkgname}
|
|
[ -z "${name##* *}" ] && die "package name contains spaces"
|
|
local dir=${subpkgdir:-$pkgdir}
|
|
local pkg="$name-$pkgver-r$pkgrel.apk"
|
|
local sub
|
|
|
|
[ ! -d "$dir" ] && die "Missing $dir"
|
|
cd "$dir"
|
|
msg "Creating ${subpkgname:+sub}package $pkg..."
|
|
local builddate=$(date -u "+%s")
|
|
local size=$(du -sk | awk '{print $1 * 1024}')
|
|
|
|
echo "# Generated by $(basename $0) $abuild_ver" >.PKGINFO
|
|
if [ -n "$FAKEROOTKEY" ]; then
|
|
echo "# using $(fakeroot -v)" >> .PKGINFO
|
|
fi
|
|
echo "# $(date -u)" >> .PKGINFO
|
|
cat >> .PKGINFO <<EOF
|
|
pkgname = $name
|
|
pkgver = $pkgver-r$pkgrel
|
|
pkgdesc = $pkgdesc
|
|
url = $url
|
|
builddate = $builddate
|
|
packager = ${PACKAGER:-"Unknown"}
|
|
size = $size
|
|
EOF
|
|
local i
|
|
|
|
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"
|
|
if [ -n "$install" ]; then
|
|
cp "$srcdir/$install" "$dir/.INSTALL" || return 1
|
|
chmod +x "$dir/.INSTALL"
|
|
metafiles="$metafiles .INSTALL"
|
|
fi
|
|
|
|
# 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 $@ )
|
|
}
|
|
|
|
package() {
|
|
stripbin
|
|
package_apk
|
|
}
|
|
|
|
# predefined splitfunc doc
|
|
doc() {
|
|
depends="$depends_doc"
|
|
local i
|
|
for i in doc man info html sgml; do
|
|
if [ -d "$pkgdir/usr/share/$i" ]; then
|
|
mkdir -p "$subpkgdir/usr/share"
|
|
mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
|
|
fi
|
|
done
|
|
|
|
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 {} \;
|
|
|
|
# remove if empty, ignore error (not empty)
|
|
rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null
|
|
|
|
# [ -d "$subpkgdir/usr/share/man" ] && depends="man"
|
|
return 0
|
|
}
|
|
|
|
# predefined splitfunc mod
|
|
mod() {
|
|
depends="$kernel $depends_mod"
|
|
for i in firmware modules; do
|
|
if [ -d "$pkgdir/lib/$i" ]; then
|
|
rm -rf "$subpkgdir/lib"
|
|
mkdir -p "$subpkgdir/lib"
|
|
mv "$pkgdir/lib/$i" "$subpkgdir/lib"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# predefined splitfunc dev
|
|
dev() {
|
|
depends="$pkgname $depends_dev"
|
|
cd "$pkgdir" || return 0
|
|
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
|
|
if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
|
|
d="$subpkgdir/${i%/*}" # dirname $i
|
|
mkdir -p "$d"
|
|
mv "$pkgdir/$i" "$d"
|
|
rmdir "$pkgdir/${i%/*}" 2>/dev/null
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# build and package in fakeroot
|
|
rootpkg() {
|
|
cd "$startdir"
|
|
msg "Entering fakeroot..."
|
|
fakeroot $0 build subpkg package
|
|
}
|
|
|
|
srcpkg() {
|
|
local p="$pkgname-$pkgver-$pkgrel"
|
|
local prefix="${startdir##*/}"
|
|
local i files="$prefix/APKBUILD"
|
|
for i in $source; do
|
|
files="$files $prefix/${i##*/}"
|
|
done
|
|
mkdir -p "$PKGDEST"
|
|
msg "Creating source package $p.src.tar.gz..."
|
|
(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files)
|
|
}
|
|
|
|
# check if package is up to date
|
|
up2date() {
|
|
local pkg="$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk"
|
|
local i s
|
|
cd "$startdir"
|
|
for i in $pkgname $subpackages; do
|
|
[ -f "$PKGDEST/$pkgname-$pkgver-r$pkgrel.apk" ] || return 1
|
|
done
|
|
[ -n "$keep" ] && return 0
|
|
|
|
for i in $source APKBUILD; do
|
|
local s
|
|
if is_remote "$i"; then
|
|
s="$SRCDEST/${i##*/}" # $(basename $i)
|
|
else
|
|
s="$startdir/${i##*/}"
|
|
fi
|
|
if [ "$s" -nt "$pkg" ]; then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# 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=
|
|
. $i
|
|
dir=${i%/APKBUILD}
|
|
for j in $pkgname $subpackages; do
|
|
echo "o ${j%%:*} $dir"
|
|
set -- $depends $makedepends
|
|
echo -n "d ${j%%:*} $1"
|
|
shift
|
|
while [ $# -gt 0 ]; do
|
|
echo -n ",$1"
|
|
shift
|
|
done
|
|
echo
|
|
done
|
|
done
|
|
)
|
|
}
|
|
|
|
deptrace() {
|
|
( depparse_aports
|
|
if [ -z "$upgrade" ]; then
|
|
# list installed pkgs and prefix with 'i '
|
|
apk info -q | sort | sed 's/^/i /'
|
|
fi
|
|
) | awk -v pkgs="$BUILD_BASE $depends $makedepends" '
|
|
|
|
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() {
|
|
local deps alldeps pkg i dir ver
|
|
msg "Building dependencies..."
|
|
deps="$BUILD_BASE $depends $makedepends"
|
|
if [ -z "$recursive" ]; then
|
|
for i in $deps; do
|
|
apk info -e $i || die "Missing dependency $i. Use -r to build recursively"
|
|
done
|
|
return 0
|
|
fi
|
|
|
|
for i in $(deptrace); do
|
|
# i = pkg:dir
|
|
local dir=${i#*:}
|
|
local pkg=${i%:*}
|
|
msg "Entering $dir"
|
|
cd "$dir" || return 1
|
|
$0 -i $pkg || return 1
|
|
uninstall_after="$pkg $uninstall_after"
|
|
done
|
|
}
|
|
|
|
# replace the md5sums in the APKBUILD
|
|
checksum() {
|
|
local s files
|
|
fetch
|
|
msg "Updating the md5sums in APKBUILD..."
|
|
for s in $source; do
|
|
files="$files ${s##*/}"
|
|
done
|
|
md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
|
|
sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
|
|
echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
|
|
}
|
|
|
|
stripbin() {
|
|
local bin
|
|
cd "${subpkgdir:-$pkgdir}" || return 1
|
|
msg "Stripping binaries"
|
|
find . -type f 2>/dev/null | while read bin; do
|
|
local opt=
|
|
case "$(file -biz "$bin")" in
|
|
*/x-sharedlib*|*/x-archive*)
|
|
strip --strip-debug "$bin";;
|
|
*/x-executable*)
|
|
strip "$bin";;
|
|
esac
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# simply list target apks
|
|
listpkg() {
|
|
local i
|
|
for i in $pkgname $subpackages; do
|
|
echo "${i%:*}-$pkgver-r$pkgrel.apk"
|
|
done
|
|
}
|
|
|
|
subpackages_has() {
|
|
local i
|
|
for i in $subpackages; do
|
|
[ "$1" = "${i%:*}" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# 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
|
|
sudo apk add -u "$pkgf" || die "Failed to install $1"
|
|
}
|
|
|
|
usage() {
|
|
echo "$(basename $0) $abuild_ver"
|
|
echo "usage: $0 [options] [-i PKG] [-p PKGDEST] [-s SRCDEST] [cmd] ..."
|
|
echo "Options:"
|
|
echo " -f Force specified cmd, even if they are already done"
|
|
echo " -h Show this help"
|
|
echo " -i Install PKG after successul build"
|
|
echo " -k Keep built packages, even if APKBUILD or sources are newer"
|
|
echo " -p Set package destination directory"
|
|
echo " -q Quiet"
|
|
echo " -r Recursively build and install missing dependencies (using sudo)"
|
|
echo " -s Set source package destination directory"
|
|
echo " -u Recursively build and upgrade dependencies (using sudo)"
|
|
echo ""
|
|
echo "Commands:"
|
|
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 " listpkg List target packages"
|
|
echo " package Create package in \$PKGDEST"
|
|
echo " rootpkg Run '$0 build package' as fakeroot"
|
|
echo " clean Remove temp build and install dirs"
|
|
echo " cleanoldpkg Remove binary packages except current version"
|
|
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"
|
|
echo ""
|
|
exit 0
|
|
}
|
|
|
|
APKBUILD="${APKBUILD:-./APKBUILD}"
|
|
unset force
|
|
unset recursive
|
|
while getopts "fhi:kip:qrs:u" opt; do
|
|
case $opt in
|
|
'f') force=1;;
|
|
'h') usage;;
|
|
'i') install_after="$install_after $OPTARG";;
|
|
'k') keep=1;;
|
|
'p') PKGDEST=$OPTARG;;
|
|
'q') quiet=1;;
|
|
'r') recursive=1;;
|
|
's') SRCDEST=$OPTARG;;
|
|
'u') upgrade=1
|
|
recursive=1;;
|
|
esac
|
|
done
|
|
shift $(( $OPTIND - 1 ))
|
|
|
|
# source the buildfile
|
|
[ -f "$APKBUILD" ] || die "Could not find $APKBUILD (PWD=$PWD)"
|
|
. "$APKBUILD"
|
|
|
|
# If we are handling a sub package then reset subpackages
|
|
if [ -n "$subpkgname" ]; then
|
|
subpackages=
|
|
fi
|
|
|
|
trap 'die "Aborted by user"' INT
|
|
set_xterm_title "abuild: $pkgname"
|
|
|
|
|
|
if [ -z "$1" ]; then
|
|
if up2date && [ -z "$force" ]; then
|
|
msg "Package is up to date"
|
|
else
|
|
set $default_cmds
|
|
fi
|
|
fi
|
|
|
|
while [ $# -gt 0 ]; do
|
|
runpart $1
|
|
shift
|
|
done
|
|
|
|
for i in $install_after; do
|
|
post_add $i
|
|
done
|
|
|
|
cleanup
|
|
|