mirror of
https://gitlab.alpinelinux.org/alpine/abuild.git
synced 2025-01-11 17:29:52 +00:00
ea8ab0c920
depends_dev are dependencies of the of the developement subpackage it does not need to be set when there is no developement subpackage
2212 lines
54 KiB
Bash
2212 lines
54 KiB
Bash
#!/bin/sh
|
|
|
|
# abuild - build apk packages (light version of makepkg)
|
|
# Copyright (c) 2008-2015 Natanael Copa <ncopa@alpinelinux.org>
|
|
#
|
|
# Distributed under GPL-2
|
|
#
|
|
|
|
program_version=@VERSION@
|
|
sysconfdir=@sysconfdir@
|
|
abuildrepo_base=@abuildrepo@
|
|
datadir=@datadir@
|
|
|
|
abuild_path=$(readlink -f $0)
|
|
|
|
if ! [ -f "$datadir/functions.sh" ]; then
|
|
echo "$datadir/functions.sh: not found" >&2
|
|
exit 1
|
|
fi
|
|
. "$datadir/functions.sh"
|
|
|
|
# defaults
|
|
BUILD_BASE="build-base"
|
|
|
|
: ${FAKEROOT:="fakeroot"}
|
|
: ${SUDO_APK:="abuild-apk"}
|
|
: ${APK:="apk"}
|
|
: ${ADDUSER:="abuild-adduser"}
|
|
: ${ADDGROUP:="abuild-addgroup"}
|
|
|
|
apk_opt_wait="--wait 30"
|
|
|
|
# run optional log command for remote logging
|
|
logcmd() {
|
|
${ABUILD_LOG_CMD:-true} "$@"
|
|
return 0
|
|
}
|
|
|
|
# we override the default msg, warning and error as we want the pkgname
|
|
msg() {
|
|
[ -n "$quiet" ] && return 0
|
|
local prompt="$GREEN>>>${NORMAL}"
|
|
local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
|
|
local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
|
|
printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
|
|
}
|
|
|
|
warning() {
|
|
local prompt="${YELLOW}>>> WARNING:${NORMAL}"
|
|
local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
|
|
local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
|
|
printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
|
|
}
|
|
|
|
error() {
|
|
local prompt="${RED}>>> ERROR:${NORMAL}"
|
|
local fake="${FAKEROOTKEY:+${BLUE}*${NORMAL}}"
|
|
local name="${STRONG}${subpkgname:-$pkgname}${NORMAL}"
|
|
printf "${prompt} ${name}${fake}: %s\n" "$1" >&2
|
|
logcmd "ERROR: $pkgname: $1"
|
|
}
|
|
|
|
cross_compiling() {
|
|
test "$CBUILD" != "$CHOST" -a -n "$CBUILDROOT"
|
|
}
|
|
|
|
cleanup() {
|
|
local i=
|
|
set_xterm_title ""
|
|
if [ -n "$CLEANUP_FILES" ]; then
|
|
rm -f $CLEANUP_FILES
|
|
fi
|
|
for i; do
|
|
case $i in
|
|
pkgdir) msg "Cleaning up pkgdir"; rm -rf "$pkgbasedir";;
|
|
srcdir) msg "Cleaning up srcdir"; rm -rf "$srcdir";;
|
|
deps)
|
|
if [ -z "$install_after" ] && [ -n "$uninstall_after" ]; then
|
|
msg "Uninstalling dependencies..."
|
|
$SUDO_APK del --quiet $apk_opt_wait $uninstall_after
|
|
if cross_compiling; then
|
|
$SUDO_APK del --root "$CBUILDROOT" \
|
|
--quiet $apk_opt_wait \
|
|
$uninstall_after
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
die() {
|
|
error "$@"
|
|
cleanup $ERROR_CLEANUP
|
|
exit 1
|
|
}
|
|
|
|
spell_error() {
|
|
die "APKBUILD contains '$1'. It should be '$2'"
|
|
}
|
|
|
|
# check if apkbuild is basicly sane
|
|
default_sanitycheck() {
|
|
local i= j= suggestion=
|
|
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"
|
|
if [ "$pkgver" != "volatile" ] && [ -z "$nodeps" ]; then
|
|
$APK version --check --quiet "$pkgver" ||\
|
|
die "$pkgver is not a valid version"
|
|
fi
|
|
[ -z "$pkgrel" ] && die "Missing pkgrel in APKBUILD"
|
|
[ -z "$pkgdesc" ] && die "Missing pkgdesc in APKBUILD"
|
|
[ -z "$url" ] && die "Missing url in APKBUILD"
|
|
[ -z "$license" ] && die "Missing license in APKBULID"
|
|
if [ $(echo "$pkgdesc" | wc -c) -gt 128 ]; then
|
|
die "pkgdesc is too long"
|
|
fi
|
|
is_function package || warning "Missing package() function in APKBUILD"
|
|
|
|
if [ -n "$replaces_priority" ] \
|
|
&& ! echo $replaces_priority | egrep -q '^[0-9]+$'; then
|
|
die "replaces_priority must be a number"
|
|
fi
|
|
# check so no package names starts with -
|
|
for i in $pkgname $subpackages; do
|
|
case $i in
|
|
-*) die "${i%:*} is not a valid package name";;
|
|
esac
|
|
done
|
|
|
|
# check if CARCH, CBUILD, CHOST and CTARGET is set
|
|
[ -z "$CHOST" ] && die "Please set CHOST in /etc/abuild.conf"
|
|
|
|
if [ -z "$CARCH" ]; then
|
|
die "Please fix CHOST, or set CARCH in abuild.conf"
|
|
fi
|
|
|
|
for i in $install; do
|
|
local n=${i%.*}
|
|
local suff=${i##*.}
|
|
case "$suff" in
|
|
pre-install|post-install|pre-upgrade|post-upgrade|pre-deinstall|post-deinstall);;
|
|
*) die "$i: unknown install script suffix"
|
|
esac
|
|
if ! subpackages_has "$n" && [ "$n" != "$pkgname" ]; then
|
|
die "$i: install script does not match pkgname or any subpackage"
|
|
fi
|
|
[ -e "$startdir/$i" ] || die "install script $i is missing"
|
|
for j in chown chmod chgrp; do
|
|
if grep -q $j "$startdir"/$i; then
|
|
warning "$i: found $j"
|
|
warning2 "Permissions should be fixed in APKBUILD package()"
|
|
fi
|
|
done
|
|
done
|
|
|
|
for i in $triggers; do
|
|
local f=${i%=*}
|
|
local p=${f%.trigger}
|
|
[ "$f" = "$i" ] && die "$f: triggers must contain '='"
|
|
[ "$p" = "$f" ] && die "$f: triggers scripts must have .trigger suffix"
|
|
if ! subpackages_has "$p" && [ "$p" != "$pkgname" ]; then
|
|
die "$p: trigger script does not match pkgname or any subpackage"
|
|
fi
|
|
|
|
[ -e "$startdir"/$f ] || die "trigger script $f is missing"
|
|
done
|
|
if [ -n "$source" ]; then
|
|
for i in $source; do
|
|
if install_has "$i"; then
|
|
warning "You should not have \$install in source"
|
|
continue
|
|
fi
|
|
case "$i" in
|
|
*::*) i=${i%%::*};;
|
|
https://*) makedepends_has wget && warning "wget no longer need to be in makedepends when source has https://" ;;
|
|
esac
|
|
list_has ${i##*/} $md5sums $sha256sums $sha512sums \
|
|
|| die "${i##*/} is missing in checksums"
|
|
|
|
# verify that our source does not have git tag version
|
|
# name as tarball (typicallly github)
|
|
if is_remote "$i" && [ "${i#*::}" = "$i" ]; then
|
|
case ${i##*/} in
|
|
v$pkgver.tar.*|$pkgver.tar.*)
|
|
die "source ${i##*/} needs to be renamed to avoid possible collisions"
|
|
;;
|
|
esac
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# verify that things listed in checksum also is listed in source
|
|
local algo=
|
|
for algo in md5 sha256 sha512; do
|
|
eval set -- \$${algo}sums
|
|
while [ $# -gt 1 ]; do
|
|
local file="$2"
|
|
shift 2
|
|
source_has $file || die "$file exists in ${algo}sums but is missing in source"
|
|
done
|
|
done
|
|
|
|
# common spelling errors
|
|
[ -n "$depend" ] && spell_error depend depends
|
|
[ -n "$makedepend" ] && spell_error makedepend makedepends
|
|
[ -n "$pkguser" ] && spell_error pkguser pkgusers
|
|
[ -n "$pkggroup" ] && spell_error pkggroup pkggroups
|
|
[ -n "$subpackage" ] && spell_error subpackage subpackages
|
|
|
|
check_maintainer || die "Provide a valid RFC822 maintainer address"
|
|
|
|
check_depends_dev || warning "depends_dev found but no development subpackage found"
|
|
|
|
makedepends_has 'g++' && warning "g++ should not be in makedepends"
|
|
return 0
|
|
}
|
|
|
|
sanitycheck() {
|
|
default_sanitycheck
|
|
}
|
|
|
|
sumcheck() {
|
|
local algo="$1" sums="$2"
|
|
local dummy f endreturnval originalparams origin file
|
|
|
|
# get number of checksums
|
|
set -- $sums
|
|
local numsums=$(( $# / 2 ))
|
|
|
|
set -- $source
|
|
if [ $# -ne $numsums ]; then
|
|
die "Number of ${algo}sums($numsums) does not correspond to number of sources($#)"
|
|
fi
|
|
fetch || return 1
|
|
msg "Checking ${algo}sums..."
|
|
cd "$srcdir" || return 1
|
|
IFS=$'\n'
|
|
endreturnval=0
|
|
for src in $sums; do
|
|
origin=$1; shift
|
|
echo "$src" | ${algo}sum -c
|
|
if [ $? -ne 0 ]; then
|
|
endreturnval=1
|
|
is_remote $origin || continue
|
|
echo "Because the remote file above failed the ${algo}sum check it will be deleted."
|
|
echo "Rebuilding will cause it to re-download which in some cases may fix the problem."
|
|
file=`echo "$src" | sed 's/.*[ \t\n]\(.*\)/\1/'`
|
|
echo "Deleting: $file"
|
|
rm $file
|
|
fi
|
|
done
|
|
unset IFS
|
|
return $endreturnval
|
|
}
|
|
|
|
# for compatibility
|
|
md5check() {
|
|
warning "'md5check' is deprecated. Use 'verify' instead"
|
|
sumcheck md5 "$md5sums"
|
|
}
|
|
|
|
# verify checksums
|
|
verify() {
|
|
local verified=false algo=
|
|
for algo in sha512 sha256 sha1 md5; do
|
|
local sums=
|
|
eval sums=\"\$${algo}sums\"
|
|
if [ -z "$sums" ] || [ -z "$source" ]; then
|
|
continue
|
|
fi
|
|
sumcheck "$algo" "$sums" || return 1
|
|
verified=true
|
|
break
|
|
done
|
|
if [ -n "$source" ] && ! $verified; then
|
|
die "Use 'abuild checksum' to generate/update the checksum(s)"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# verify upstream sources
|
|
sourcecheck() {
|
|
local uri
|
|
for uri in $source; do
|
|
is_remote $uri || continue
|
|
case "$uri" in
|
|
saveas-*://*)
|
|
uri=${uri#saveas-}
|
|
uri=${uri%/*}
|
|
;;
|
|
*::*)
|
|
uri=${uri##*::}
|
|
;;
|
|
esac
|
|
wget -q -s "$uri" || return 1
|
|
done
|
|
return 0
|
|
}
|
|
|
|
uri_fetch() {
|
|
local uri="$1"
|
|
[ -n "$quiet" ] && opts="-s"
|
|
|
|
mkdir -p "$SRCDEST"
|
|
abuild-fetch -d "$SRCDEST" "$uri"
|
|
}
|
|
|
|
is_remote() {
|
|
case "${1#*::}" in
|
|
http://*|ftp://*|https://*|saveas-*://*)
|
|
return 0;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
filename_from_uri() {
|
|
local uri="$1"
|
|
local filename="${uri##*/}" # $(basename $uri)
|
|
case "$uri" in
|
|
*::*) filename=${uri%%::*};;
|
|
esac
|
|
echo "$filename"
|
|
}
|
|
|
|
# try download from file from mirror first
|
|
uri_fetch_mirror() {
|
|
local uri="$1"
|
|
if [ -n "$DISTFILES_MIRROR" ]; then
|
|
if is_remote "$DISTFILES_MIRROR"; then
|
|
uri_fetch "$DISTFILES_MIRROR"/$(filename_from_uri $uri)\
|
|
&& return 0
|
|
else
|
|
cp "$DISTFILES_MIRROR"/$(filename_from_uri $uri) \
|
|
"$SRCDEST" && return 0
|
|
fi
|
|
fi
|
|
uri_fetch "$uri"
|
|
}
|
|
|
|
default_fetch() {
|
|
local s
|
|
mkdir -p "$srcdir"
|
|
for s in $source; do
|
|
if is_remote "$s"; then
|
|
uri_fetch_mirror "$s" || return 1
|
|
ln -sf "$SRCDEST/$(filename_from_uri $s)" "$srcdir"/
|
|
else
|
|
ln -sf "$startdir/$s" "$srcdir/"
|
|
fi
|
|
done
|
|
}
|
|
|
|
fetch() {
|
|
default_fetch
|
|
}
|
|
|
|
# verify that all init.d scripts are openrc runscripts
|
|
initdcheck() {
|
|
local i line
|
|
for i in $source; do
|
|
case $i in
|
|
*.initd) line=$(head -n 1 "$srcdir"/$i);;
|
|
*) continue ;;
|
|
esac
|
|
|
|
case "$line" in
|
|
*sbin/openrc-run)
|
|
;;
|
|
*sbin/runscript)
|
|
warning "$i is not an openrc #!/sbin/openrc-run"
|
|
;;
|
|
*) error "$i is not an openrc #!/sbin/openrc-run"
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# unpack the sources
|
|
default_unpack() {
|
|
local u
|
|
if [ -z "$force" ]; then
|
|
verify || return 1
|
|
initdcheck || return 1
|
|
fi
|
|
mkdir -p "$srcdir"
|
|
for u in $source; do
|
|
local s="$SRCDEST/$(filename_from_uri $u)"
|
|
case "$s" in
|
|
*.tar)
|
|
msg "Unpacking $s..."
|
|
tar -C "$srcdir" -xf "$s" || return 1;;
|
|
*.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;;
|
|
*.tar.xz)
|
|
msg "Unpacking $s..."
|
|
unxz -c "$s" | tar -C "$srcdir" -x || return 1;;
|
|
*.zip)
|
|
msg "Unpacking $s..."
|
|
unzip "$s" -d "$srcdir" || return 1;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
unpack() {
|
|
default_unpack
|
|
}
|
|
|
|
# cleanup source and package dir
|
|
clean() {
|
|
msg "Cleaning temporary build dirs..."
|
|
rm -rf "$srcdir"
|
|
rm -rf "$pkgbasedir"
|
|
}
|
|
|
|
# cleanup fetched sources
|
|
cleancache() {
|
|
local s
|
|
for s in $source; do
|
|
if is_remote "$s"; then
|
|
s=$(filename_from_uri $s)
|
|
msg "Cleaning downloaded $s ..."
|
|
rm -f "$SRCDEST/$s"
|
|
fi
|
|
done
|
|
}
|
|
|
|
listpkgnames() {
|
|
local i
|
|
for i in $pkgname $subpackages; do
|
|
echo ${i%:*}
|
|
done
|
|
for i in $linguas; do
|
|
echo $pkgname-lang-$i
|
|
done
|
|
}
|
|
|
|
cleanpkg() {
|
|
local i
|
|
getpkgver || return 1
|
|
msg "Cleaning built packages..."
|
|
for i in $(listpkgnames); do
|
|
local p="${i%:*}-$pkgver-r$pkgrel"
|
|
rm -f "$PKGDEST/$p.apk" "$PKGDEST/$p.src.tar.gz" \
|
|
"$abuildrepo"/$p.apk "$abuildrepo"/*/$p.apk
|
|
done
|
|
# remove given packages from index
|
|
update_abuildrepo_index
|
|
}
|
|
|
|
# clean all packages except current
|
|
cleanoldpkg() {
|
|
local i j
|
|
getpkgver || return 1
|
|
msg "Cleaning all packages except $pkgver-r$pkgrel..."
|
|
for i in $(listpkgnames); do
|
|
local pn=${i%:*}
|
|
for j in "$PKGDEST"/$pn-[0-9]*.apk ; do
|
|
[ "$j" = "$PKGDEST/$pn-$pkgver-r$pkgrel.apk" ] \
|
|
&& continue
|
|
rm -f "$j" "$abuildrepo"/*/${j##*/}
|
|
done
|
|
done
|
|
update_abuildrepo_index
|
|
return 0
|
|
}
|
|
|
|
mkusers() {
|
|
local i
|
|
for i in $pkggroups; do
|
|
if ! getent group $i >/dev/null; then
|
|
msg "Creating group $i"
|
|
$ADDGROUP -S $i || return 1
|
|
fi
|
|
done
|
|
for i in $pkgusers; do
|
|
if ! getent passwd $i >/dev/null; then
|
|
local gopt=
|
|
msg "Creating user $i"
|
|
if getent group $i >/dev/null; then
|
|
gopt="-G $i"
|
|
fi
|
|
$ADDUSER -S -D -H $gopt $i || return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
# helper to update config.sub to a recent version
|
|
update_config_sub() {
|
|
local changed=false
|
|
find . -name config.sub | while read f; do
|
|
if ! ./$f armv6-alpine-linux-muslgnueabihf 2>/dev/null; then
|
|
msg "Updating $f"
|
|
cp "$datadir"/${f##*/} "$f" || return 1
|
|
changed=true
|
|
else
|
|
msg "No update needed for $f"
|
|
fi
|
|
# pipe subshell will return status of last command
|
|
$changed
|
|
done
|
|
return $?
|
|
}
|
|
|
|
runpart() {
|
|
local part=$1
|
|
[ -n "$DEBUG" ] && msg "$part"
|
|
$part || die "$part failed"
|
|
}
|
|
|
|
# override those in your build script
|
|
getpkgver() {
|
|
# this func is supposed to be overridden by volatile packages
|
|
if [ "$pkgver" = "volatile" ]; then
|
|
error "Please provide a getpkgver() function in your APKBUILD"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
prepare() {
|
|
:
|
|
}
|
|
|
|
build() {
|
|
:
|
|
}
|
|
|
|
# generate a simple tar.gz package of pkgdir
|
|
targz() {
|
|
cd "$pkgdir" || return 1
|
|
mkdir -p "$PKGDEST"
|
|
tar -czf "$PKGDEST"/$pkgname-$pkgver-r$pkgrel.tar.gz *
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
postcheck() {
|
|
local dir="$1" name="$2" i=
|
|
msg "Running postcheck for $name"
|
|
# checking for FHS compat
|
|
if ! options_has "!fhs"; then
|
|
for i in "$dir"/srv/* "$dir"/usr/local/* "$dir"/opt/*; do
|
|
if [ -e "$i" ]; then
|
|
error "Packages must not put anything under /srv, /usr/local or /opt"
|
|
return 1
|
|
fi
|
|
done
|
|
if [ -d "$dir"/usr/var ]; then
|
|
error "Found /usr/var, localstatedir is most likely wrong"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# remove *.la files if libtool is not set
|
|
if ! options_has "libtool"; then
|
|
find "$dir" -name '*.la' -type f -delete
|
|
fi
|
|
|
|
# look for /usr/lib/charset.alias
|
|
if [ -e "$dir"/usr/lib/charset.alias ] \
|
|
&& ! options_has "charset.alias"; then
|
|
error "Found /usr/lib/charset.alias"
|
|
return 1
|
|
fi
|
|
# look for /usr/share/doc
|
|
if [ -e "$dir"/usr/share/doc ] \
|
|
&& ! is_doc_pkg "$name"; then
|
|
warning "Found /usr/share/doc but package name doesn't end with -doc"
|
|
fi
|
|
# look for /usr/share/man
|
|
if [ -e "$dir"/usr/share/man ]; then
|
|
if ! is_doc_pkg "$name"; then
|
|
warning "Found /usr/share/man but package name doesn't end with -doc"
|
|
fi
|
|
# check for uncompressed man pages
|
|
i=$(find "$dir"/usr/share/man -name '*.[0-9]' -type f | sed "s|^$dir|\t|")
|
|
if [ -n "$i" ]; then
|
|
error "Found uncompressed man pages:"
|
|
echo "$i"
|
|
return 1
|
|
fi
|
|
fi
|
|
# check directory permissions
|
|
i=$(find "$dir" -type d -perm -777 | sed "s|^$dir|\t|")
|
|
if [ -n "$i" ]; then
|
|
warning "World writeable directories found:"
|
|
echo "$i"
|
|
fi
|
|
# check so we dont have any suid root binaries that are not PIE
|
|
i=$(find "$dir" -type f -perm +6000 \
|
|
| xargs scanelf --nobanner --etype ET_EXEC \
|
|
| sed "s|ET_EXEC $dir|\t|")
|
|
if [ -n "$i" ]; then
|
|
error "Found non-PIE files that has SUID:"
|
|
echo "$i"
|
|
return 1
|
|
fi
|
|
# test suid bit on executable
|
|
if ! options_has "suid"; then
|
|
i=$(find "$dir" \( -perm -u+s -o -perm -g+s \) -a -type f \
|
|
-a -perm -o+x)
|
|
if [ -n "$i" ]; then
|
|
error "Found executable files with SUID bit set:"
|
|
echo "$i"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# test for textrels
|
|
if ! options_has "textrels"; then
|
|
local res="$(scanelf --recursive --textrel --quiet "$dir")"
|
|
if [ -n "$res" ]; then
|
|
error "Found textrels:"
|
|
echo "$res"
|
|
return 1
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
pre_split() {
|
|
if [ -z "$subpkgname" ]; then
|
|
return 0
|
|
fi
|
|
# the subpackages should not inherit those form main package
|
|
provides=""
|
|
install_if=""
|
|
apkbuild_arch="$arch"
|
|
}
|
|
|
|
prepare_subpackages() {
|
|
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..."
|
|
local dir="$pkgbasedir/${i%:*}" name="${i%:*}"
|
|
( subpkgdir="$dir" subpkgname="$name" \
|
|
$0 pre_split $func prepare_package \
|
|
&& postcheck "$dir" "$name" ) || return 1
|
|
done
|
|
postcheck "$pkgdir" "$pkgname" || return 1
|
|
# post check for /usr/share/locale
|
|
if [ -d "$pkgdir"/usr/share/locale ]; then
|
|
warning "Found /usr/share/locale"
|
|
warning2 "Maybe add \$pkgname-lang to subpackages?"
|
|
fi
|
|
}
|
|
|
|
default_lang() {
|
|
pkgdesc="Languages for package $pkgname"
|
|
install_if="$pkgname=$pkgver-r$pkgrel lang"
|
|
arch="noarch"
|
|
local dir
|
|
for dir in ${langdir:-/usr/share/locale}; do
|
|
mkdir -p "$subpkgdir"/${dir%/*}
|
|
mv "$pkgdir"/"$dir" "$subpkgdir"/"$dir" || return 1
|
|
done
|
|
}
|
|
|
|
lang() {
|
|
default_lang
|
|
}
|
|
|
|
default_lang_subpkg() {
|
|
if [ -z "$lang" ]; then
|
|
error "lang is not set"
|
|
return 1
|
|
fi
|
|
pkgdesc="$pkgname language pack for $lang"
|
|
arch="noarch"
|
|
install_if="$pkgname=$pkgver-r$pkgrel lang-$lang"
|
|
local dir
|
|
for dir in ${langdir:-/usr/share/locale}; do
|
|
mkdir -p "$subpkgdir"/$dir
|
|
mv "$pkgdir"/$dir/$lang* \
|
|
"$subpkgdir"/$dir/ \
|
|
|| return 1
|
|
done
|
|
}
|
|
|
|
lang_subpkg() {
|
|
default_lang_subpkg
|
|
}
|
|
|
|
prepare_language_packs() {
|
|
for lang in $linguas; do
|
|
lang="$lang" \
|
|
subpkgname="$pkgname-lang-$lang" \
|
|
subpkgdir="$pkgbasedir"/$subpkgname \
|
|
$0 lang_subpkg prepare_package || return 1
|
|
done
|
|
}
|
|
|
|
# echo '-dirty' if git is not clean
|
|
git_dirty() {
|
|
if [ $(git status -s "$startdir" | wc -l) -ne 0 ]; then
|
|
echo "-dirty"
|
|
fi
|
|
}
|
|
|
|
# echo last commit hash id
|
|
git_last_commit() {
|
|
git log --format=oneline -n 1 "$startdir" | awk '{print $1}'
|
|
}
|
|
|
|
get_maintainer() {
|
|
if [ -z "$maintainer" ]; then
|
|
maintainer=$(awk -F': ' '/\# *Maintainer/ {print $2}' "$APKBUILD")
|
|
# remove surrounding whitespace
|
|
maintainer=$(echo "$maintainer" | xargs)
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
check_maintainer() {
|
|
get_maintainer
|
|
if [ -z "$maintainer" ]; then
|
|
warning "No maintainer"
|
|
else
|
|
# try to check for a valid rfc822 address
|
|
case "$maintainer" in
|
|
*[A-Za-z0-9]*\ \<*@*.*\>) ;;
|
|
*) return 1 ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
check_depends_dev() {
|
|
if [ -n "$depends_dev" ]; then
|
|
local pkgname
|
|
for i in $pkgname $subpackages; do
|
|
case "$pkgname" in
|
|
*-dev) return 0 ;;
|
|
esac
|
|
done
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
prepare_metafiles() {
|
|
getpkgver || return 1
|
|
local name=${subpkgname:-$pkgname}
|
|
[ -z "${name##* *}" ] && die "package name contains spaces"
|
|
local dir=${subpkgdir:-$pkgdir}
|
|
local pkg="$name-$pkgver-r$pkgrel.apk"
|
|
local pkginfo="$controldir"/.PKGINFO
|
|
local sub
|
|
|
|
[ ! -d "$dir" ] && die "Missing $dir"
|
|
cd "$dir"
|
|
mkdir -p "$controldir"
|
|
local builddate=$(date -u "+%s")
|
|
local size=$(du -sk | awk '{print $1 * 1024}')
|
|
local parch="$CARCH"
|
|
|
|
# we need to wait with setting noarch til our build infra can handle it
|
|
# if [ "$arch" = "noarch" ]; then
|
|
# parch="noarch"
|
|
# fi
|
|
|
|
# save arch incase subpackages set it different than main pkg
|
|
if [ "${apkbuild_arch:-$arch}" != "$arch" ]; then
|
|
echo "$arch" > "$controldir"/.arch
|
|
fi
|
|
|
|
echo "# Generated by $(basename $0) $program_version" >"$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
|
|
arch = $parch
|
|
origin = $pkgname
|
|
EOF
|
|
local i deps
|
|
deps="$depends"
|
|
if [ "$pkgname" != "busybox" ] && ! depends_has busybox; then
|
|
for i in $install $triggers; do
|
|
local s=${i%=*}
|
|
[ "$name" != "${s%.*}" ] && continue
|
|
if head -n 1 "$startdir/$s" | grep '^#!/bin/sh' >/dev/null ; then
|
|
msg "Script found. busybox added as a dependency for $pkg"
|
|
deps="$deps busybox"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# store last_commit in global var so we only call git once
|
|
if [ -z "$last_commit" ]; then
|
|
last_commit="$(git_last_commit)$(git_dirty)"
|
|
fi
|
|
echo "commit = $last_commit" >> "$pkginfo"
|
|
|
|
get_maintainer
|
|
if [ -n "$maintainer" ]; then
|
|
echo "maintainer = $maintainer" >> "$pkginfo"
|
|
fi
|
|
|
|
if [ -n "$replaces_priority" ]; then
|
|
echo "replaces_priority = $replaces_priority" >> "$pkginfo"
|
|
fi
|
|
|
|
echo "license = $license" >> "$pkginfo"
|
|
for i in $replaces; do
|
|
echo "replaces = $i" >> "$pkginfo"
|
|
done
|
|
for i in $deps; do
|
|
echo "depend = $i" >> "$pkginfo"
|
|
done
|
|
for i in $provides; do
|
|
echo "provides = $i" >> "$pkginfo"
|
|
done
|
|
for i in $triggers; do
|
|
local f=${i%=*}
|
|
local dirs=${i#*=}
|
|
[ "${f%.trigger}" != "$name" ] && continue
|
|
echo "triggers = ${dirs//:/ }" >> "$pkginfo"
|
|
done
|
|
if [ -n "$install_if" ]; then
|
|
echo "install_if = $(echo $install_if)" >> "$pkginfo"
|
|
fi
|
|
|
|
local metafiles=".PKGINFO"
|
|
for i in $install $triggers; do
|
|
local f=${i%=*}
|
|
local n=${f%.*}
|
|
if [ "$n" != "$name" ]; then
|
|
continue
|
|
fi
|
|
script=${f#$name}
|
|
msg "Adding $script"
|
|
cp "$startdir/$f" "$controldir/$script" || return 1
|
|
chmod +x "$controldir/$script"
|
|
metafiles="$metafiles $script"
|
|
done
|
|
echo $metafiles | tr ' ' '\n' > "$controldir"/.metafiles
|
|
}
|
|
|
|
prepare_trace_rpaths() {
|
|
local dir=${subpkgdir:-$pkgdir}
|
|
local etype= soname= file= sover=
|
|
[ "$arch" = "noarch" ] && return 0
|
|
options_has "!tracedeps" && return 0
|
|
# lets tell all the places we should look for .so files - all rpaths
|
|
scanelf --quiet --recursive --rpath "$dir" \
|
|
| sed -e 's/[[:space:]].*//' -e 's/:/\n/' | sort -u \
|
|
>"$controldir"/.rpaths
|
|
if grep -q -x '/usr/lib' "$controldir"/.rpaths; then
|
|
warning "Redundant /usr/lib in rpath found"
|
|
fi
|
|
if grep '^/home/' "$controldir"/.rpaths; then
|
|
error "Has /home/... in rpath"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# search for broken symlinks so we later can pull in proper depends
|
|
prepare_symlinks() {
|
|
local dir="${subpkgdir:-$pkgdir}"
|
|
options_has "!tracedeps" && return 0
|
|
cd "$dir" || return 1
|
|
find -type l | while read symlink; do
|
|
if ! [ -e "$symlink" ]; then
|
|
echo "$symlink $(readlink $symlink)" \
|
|
>> "$controldir"/.symlinks
|
|
fi
|
|
done
|
|
}
|
|
|
|
prepare_pkgconfig_provides() {
|
|
local dir="${subpkgdir:-$pkgdir}"
|
|
options_has "!tracedeps" && return 0
|
|
cd "$dir" || return 1
|
|
for i in usr/lib/pkgconfig/*.pc; do
|
|
if ! [ -e "$i" ]; then
|
|
continue
|
|
fi
|
|
local f=${i##*/}
|
|
local v=$(PKG_CONFIG_PATH="$dir"/usr/lib/pkgconfig pkg-config \
|
|
--modversion ${f%.pc})
|
|
echo "${f%.pc}=${v:-0}" >> "$controldir"/.provides-pc
|
|
done
|
|
}
|
|
|
|
# check if dir has arch specific binaries
|
|
dir_has_arch_binaries() {
|
|
local dir="$1"
|
|
# if scanelf returns something, then we have binaries
|
|
[ -n "$(scanelf -R "$dir" | head -n 1)" ] && return 0
|
|
|
|
# look for static *.a
|
|
[ -n "$(find "$dir" -type f -name '*.a' | head -n 1)" ] && return 0
|
|
|
|
return 1
|
|
}
|
|
|
|
# returns true if this is the -dev package
|
|
is_dev_pkg() {
|
|
test "${subpkgname%-dev}" != "$subpkgname"
|
|
}
|
|
|
|
# returns true if this is the -doc package
|
|
is_doc_pkg() {
|
|
test "${1%-doc}" != "$1"
|
|
}
|
|
|
|
# check that noarch is set if needed
|
|
archcheck() {
|
|
options_has "!archcheck" && return 0
|
|
if dir_has_arch_binaries "${subpkgdir:-$pkgdir}"; then
|
|
[ "$arch" != "noarch" ] && return 0
|
|
error "Arch specific binaries found so arch must not be set to \"noarch\""
|
|
return 1
|
|
elif [ "$arch" != "noarch" ] && ! is_dev_pkg; then
|
|
# we dont want -dev package go to noarch
|
|
warning "No arch specific binaries found so arch should probably be set to \"noarch\""
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
prepare_package() {
|
|
msg "Preparing ${subpkgname:+sub}package ${subpkgname:-$pkgname}..."
|
|
stripbin
|
|
prepare_metafiles \
|
|
&& prepare_trace_rpaths \
|
|
&& prepare_symlinks \
|
|
&& prepare_pkgconfig_provides \
|
|
|| return 1
|
|
archcheck
|
|
}
|
|
|
|
pkginfo_val() {
|
|
local key="$1"
|
|
local file="$2"
|
|
awk -F ' = ' "\$1 == \"$key\" {print \$2}" "$file"
|
|
}
|
|
|
|
# find real path to so files
|
|
real_so_path() {
|
|
local so="$1"
|
|
shift
|
|
while [ $# -gt 0 ]; do
|
|
[ -e "$1"/$so ] && realpath "$1/$so" && return 0
|
|
shift
|
|
done
|
|
error "$so: path not found"
|
|
return 1
|
|
}
|
|
|
|
# search rpaths and /usr/lib /lib for given so files
|
|
find_so_files() {
|
|
local rpaths=$(cat "$1")
|
|
shift
|
|
while [ $# -gt 0 ]; do
|
|
real_so_path "$1" /usr/lib /lib $rpaths || return 1
|
|
shift
|
|
done
|
|
return 0
|
|
}
|
|
|
|
subpkg_provides_prefixed_so() {
|
|
[ -n "$sonameprefix" ] && grep -q -w "^$sonameprefix$1" \
|
|
"$pkgbasedir"/.control.*/.provides-so 2>/dev/null
|
|
}
|
|
|
|
subpkg_provides_so() {
|
|
grep -q -w "^$1" "$pkgbasedir"/.control.*/.provides-so 2>/dev/null
|
|
}
|
|
|
|
subpkg_provides_pc() {
|
|
grep -q -w "^${1%%[<>=]*}" "$pkgbasedir"/.control.*/.provides-pc \
|
|
2>/dev/null
|
|
}
|
|
|
|
trace_apk_deps() {
|
|
local name="$1"
|
|
local dir="$2"
|
|
local i= found= autodeps= deppkgs= missing=
|
|
msg "Tracing dependencies..."
|
|
# add pkgconfig if usr/lib/pkgconfig is found
|
|
if [ -d "$pkgbasedir"/$name/usr/lib/pkgconfig ] \
|
|
&& ! grep -q '^depend = pkgconfig' "$dir"/.PKGINFO; then
|
|
autodeps="$autodeps pkgconfig"
|
|
fi
|
|
|
|
# special case for libpthread: we need depend on libgcc
|
|
if [ "$CLIBC" = "uclibc" ] && [ -f "$dir"/.needs-so ] \
|
|
&& grep -q -w '^libpthread.so.*' "$dir"/.needs-so \
|
|
&& ! grep -q -w "^depend = libgcc" "$dir"/.PKGINFO; then
|
|
autodeps="$autodeps libgcc"
|
|
msg " added libgcc (due to libpthread)"
|
|
fi
|
|
|
|
[ -f "$dir"/.needs-so ] && for i in $(cat "$dir"/.needs-so); do
|
|
# first check if its provided by same apkbuild
|
|
grep -q -w "^$sonameprefix$i" "$dir"/.provides-so 2>/dev/null && continue
|
|
|
|
if subpkg_provides_prefixed_so "$i"; then
|
|
autodeps="$autodeps so:$sonameprefix$i"
|
|
elif subpkg_provides_so "$i" || cross_compiling \
|
|
|| $APK info --quiet --installed "so:$i"; then
|
|
autodeps="$autodeps so:$i"
|
|
else
|
|
missing="$missing $i"
|
|
fi
|
|
done
|
|
|
|
# find all packages that holds the so files
|
|
if [ -f "$dir"/.rpaths ]; then
|
|
local so_files=$(find_so_files "$dir"/.rpaths $missing) \
|
|
|| return 1
|
|
deppkgs=$($APK info --quiet --who-owns $so_files) || return 1
|
|
fi
|
|
|
|
for found in $deppkgs; do
|
|
if grep -w "^depend = ${found}$" "$dir"/.PKGINFO >/dev/null ; then
|
|
warning "You can remove '$found' from depends"
|
|
continue
|
|
fi
|
|
autodeps="$autodeps $found"
|
|
done
|
|
|
|
# symlink targets
|
|
for i in $(sort -u "$dir"/.symlinks-needs 2>/dev/null); do
|
|
autodeps="$autodeps $i"
|
|
done
|
|
|
|
# pkg-config depends
|
|
for i in $(sort -u "$dir"/.needs-pc 2>/dev/null); do
|
|
if subpkg_provides_pc "$i" || cross_compiling \
|
|
|| $APK info --quiet --installed "pc:$i"; then
|
|
local provider=$(apk search --quiet "pc:$i")
|
|
if list_has "$provider" $depends_dev; then
|
|
warning "$provider should be removed from depends_dev"
|
|
fi
|
|
autodeps="$autodeps pc:$i"
|
|
else
|
|
warning "Could not find any provider for pc:$i"
|
|
local pcfile=/usr/lib/pkgconfig/"${i%%[<>=]*}".pc
|
|
if [ -e "$pcfile" ]; then
|
|
local owner=$($APK info --quiet --who-owns $pcfile)
|
|
warning "${owner:-package providing $pcfile} needs to be rebuilt"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "# automatically detected:" >> "$dir"/.PKGINFO
|
|
if [ -f "$dir"/.provides-so ]; then
|
|
sed 's/^\(.*\) \([0-9].*\)/provides = so:\1=\2/' "$dir"/.provides-so \
|
|
>> "$dir"/.PKGINFO
|
|
fi
|
|
if [ -f "$dir"/.provides-pc ]; then
|
|
sed 's/^/provides = pc:/' "$dir"/.provides-pc | sort -u \
|
|
>> "$dir"/.PKGINFO
|
|
fi
|
|
[ -z "$autodeps" ] && return 0
|
|
for i in $autodeps; do
|
|
echo "depend = $i"
|
|
done | sort -u >> "$dir"/.PKGINFO
|
|
# display all depends
|
|
sed -n '/^depend =/s/depend = /\t/p' "$dir"/.PKGINFO >&2
|
|
}
|
|
|
|
find_scanelf_paths() {
|
|
local datadir="$1"
|
|
local paths="$datadir/lib:$datadir/usr/lib" i= rpaths=
|
|
if [ -n "$ldpath" ]; then
|
|
paths="$paths:$(echo "${datadir}${ldpath}" | sed "s|:|:$datadir|g")"
|
|
fi
|
|
# search in all rpaths
|
|
for rpaths in "$pkgbasedir"/.control.*/.rpaths; do
|
|
[ -f "$rpaths" ] || continue
|
|
while read i; do
|
|
local dir="${datadir}${i}"
|
|
IFS=:
|
|
if [ -d "$dir" ] && ! list_has "$dir" $paths; then
|
|
paths="$paths:${dir}"
|
|
fi
|
|
unset IFS
|
|
done < "$rpaths"
|
|
done
|
|
echo "$paths"
|
|
}
|
|
|
|
scan_shared_objects() {
|
|
local name="$1" controldir="$2" datadir="$3"
|
|
local opt= i=
|
|
|
|
if [ "$arch" = "noarch" ] && ! [ -e "$controldir"/.arch ]; then
|
|
return 0
|
|
fi
|
|
|
|
# allow spaces in paths
|
|
IFS=:
|
|
set -- $(find_scanelf_paths "$datadir")
|
|
unset IFS
|
|
|
|
# sanity check, verify that each path is prefixed with datadir
|
|
for i; do
|
|
if [ "${i#$datadir}" = "$i" ]; then
|
|
error "Internal error in scanelf paths"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
if options_has "ldpath-recursive"; then
|
|
opt="--recursive"
|
|
fi
|
|
msg "Scanning shared objects"
|
|
# lets tell all the .so files this package provides in .provides-so
|
|
scanelf --nobanner --soname $opt "$@" | while read etype soname file; do
|
|
# if soname field is missing, soname will be the filepath
|
|
sover=0
|
|
if [ -z "$file" ]; then
|
|
file="$soname"
|
|
soname=${soname##*/}
|
|
fi
|
|
|
|
# we only want shared libs
|
|
case $soname in
|
|
*.so|*.so.[0-9]*|*.c32);;
|
|
*) continue;;
|
|
esac
|
|
|
|
case "$file" in
|
|
*.so.[0-9]*) sover=${file##*.so.};;
|
|
*.so)
|
|
# filter out sonames with version when file does not
|
|
# have version
|
|
case "$soname" in
|
|
*.so.[0-9]*)
|
|
if options_has "sover-namecheck"; then
|
|
continue
|
|
fi
|
|
esac
|
|
;;
|
|
esac
|
|
list_has "$soname" $somask && continue
|
|
echo "$sonameprefix$soname $sover"
|
|
# use awk to filter out dupes that has sover = 0
|
|
done | awk '{ if (so[$1] == 0) so[$1] = $2; }
|
|
END { for (i in so) print(i " " so[i]); }' \
|
|
| sort -u > "$controldir"/.provides-so
|
|
|
|
# verify that we dont have any duplicates
|
|
local dupes="$(cut -d' ' -f1 "$controldir"/.provides-so | uniq -d)"
|
|
if [ -n "$dupes" ]; then
|
|
die "provides multiple versions of same shared object: $dupes"
|
|
fi
|
|
|
|
# now find the so dependencies
|
|
scanelf --nobanner --recursive --needed "$datadir" | tr ' ' ':' \
|
|
| awk -F ":" '$2 != "" && ($1 == "ET_DYN" || $1 == "ET_EXEC") {print $2}' \
|
|
| sed 's:,:\n:g' | sort -u \
|
|
| while read soname; do
|
|
# only add files that are not self provided
|
|
grep -q -w "^$sonameprefix$soname" "$controldir"/.provides-so \
|
|
|| list_has "$soname" $somask \
|
|
|| echo $soname
|
|
done > "$controldir"/.needs-so
|
|
}
|
|
|
|
# normalize a path string
|
|
normalize_path() {
|
|
local oifs="$IFS" pathstr= i=
|
|
IFS='/'
|
|
set -- $1
|
|
for i; do
|
|
case "$i" in
|
|
"."|"") continue;;
|
|
"..") pathstr="${pathstr%%/${pathstr##*/}}";;
|
|
*) pathstr="${pathstr}/$i";;
|
|
esac
|
|
done
|
|
echo "$pathstr"
|
|
}
|
|
|
|
# find which package provides file that symlink points to
|
|
scan_symlink_targets() {
|
|
local name="$1" dir="$2" datadir="$3"
|
|
local symfile= targetpath=
|
|
cd "$datadir"
|
|
for symfile in "$pkgbasedir"/.control.*/.symlinks; do
|
|
local d="${symfile%/.symlinks}"
|
|
if ! [ -e "$symfile" ] || [ "$d" = "$dir" ]; then
|
|
continue
|
|
fi
|
|
|
|
while read symlink target; do
|
|
if [ "${target#/}" = "$target" ]; then
|
|
target="${symlink%/*}/$target"
|
|
fi
|
|
targetpath="$datadir"/$(normalize_path "$target")
|
|
if [ -e "$targetpath" ] || [ -L "$targetpath" ]; then
|
|
echo "$name=$pkgver-r$pkgrel" \
|
|
>> "$d"/.symlinks-needs
|
|
fi
|
|
done < "$symfile"
|
|
done
|
|
}
|
|
|
|
#find pkg-config dependencies
|
|
scan_pkgconfig_depends() {
|
|
local provides_pc="$1" controldir= name= datadir=
|
|
[ -e "$provides_pc" ] || return 0
|
|
controldir="${provides_pc%/*}"
|
|
name="$(pkginfo_val pkgname "$controldir"/.PKGINFO)"
|
|
datadir="$pkgbasedir"/$name
|
|
for i in $(sort -u "$provides_pc"); do
|
|
PKG_CONFIG_PATH="$datadir"/usr/lib/pkgconfig pkg-config \
|
|
--print-requires \
|
|
--print-requires-private ${i%=*} \
|
|
| sed -E 's/\s*([<>=]+)\s*/\1/' \
|
|
| while read pc; do
|
|
# only add files that are not self provided
|
|
if ! grep -q -w "^${pc%%[<>=]*}" "$provides_pc"; then
|
|
echo "$pc" >> "$controldir"/.needs-pc
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
# read size in bytes from stdin and show as human readable
|
|
human_size() {
|
|
awk '{ split("B KB MB GB TB PB", type)
|
|
for(i=5; y < 1; i--)
|
|
y = $1 / (2**(10*i))
|
|
printf("%.1f %s\n", y, type[i+2]) }'
|
|
}
|
|
|
|
create_apks() {
|
|
local file= dir= name= ver= apk= datadir= size=
|
|
getpkgver || return 1
|
|
mkdir -p "$PKGDEST"
|
|
if ! options_has "!tracedeps"; then
|
|
for file in "$pkgbasedir"/.control.*/.PKGINFO; do
|
|
dir="${file%/.PKGINFO}"
|
|
name="$(pkginfo_val pkgname $file)"
|
|
datadir="$pkgbasedir"/$name
|
|
subpkgname=$name
|
|
scan_shared_objects "$name" "$dir" "$datadir"
|
|
scan_symlink_targets "$name" "$dir" "$datadir"
|
|
done
|
|
for file in "$pkgbasedir"/.control.*/.provides-pc; do
|
|
scan_pkgconfig_depends "$file"
|
|
done
|
|
fi
|
|
|
|
for file in "$pkgbasedir"/.control.*/.PKGINFO; do
|
|
dir="${file%/.PKGINFO}"
|
|
name=$(pkginfo_val pkgname $file)
|
|
ver=$(pkginfo_val pkgver $file)
|
|
size=$(pkginfo_val size $file | human_size)
|
|
apk=$name-$ver.apk
|
|
datadir="$pkgbasedir"/$name
|
|
subpkgname=$name
|
|
|
|
trace_apk_deps "$name" "$dir" || return 1
|
|
msg "Package size: ${size}"
|
|
msg "Compressing data..."
|
|
(
|
|
cd "$datadir"
|
|
# data.tar.gz
|
|
set -- *
|
|
if [ "$1" = '*' ]; then
|
|
touch .dummy
|
|
set -- .dummy
|
|
fi
|
|
tar --xattrs -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
|
|
|
|
msg "Create checksum..."
|
|
# 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
|
|
cd "$dir"
|
|
tar -c $(cat "$dir"/.metafiles) | abuild-tar --cut \
|
|
| gzip -9 > control.tar.gz
|
|
abuild-sign -q control.tar.gz || exit 1
|
|
|
|
msg "Create $apk"
|
|
# create the final apk
|
|
cat control.tar.gz data.tar.gz > "$PKGDEST"/$apk
|
|
)
|
|
done
|
|
subpkgname=
|
|
}
|
|
|
|
clean_abuildrepo() {
|
|
local apk
|
|
cd "$abuildrepo" || return 1
|
|
|
|
# remove compat symlink
|
|
for d in "$abuildrepo/$CARCH"; do
|
|
[ -L "$d" ] && rm "$d"
|
|
done
|
|
|
|
# remove broken links from abuildrepo
|
|
for apk in *.apk */*.apk; do
|
|
if [ -L "$apk" ] && [ ! -f "$apk" ]; then
|
|
rm -f "$apk"
|
|
fi
|
|
done
|
|
}
|
|
|
|
mklinks_abuildrepo() {
|
|
[ -n "$REPODEST" ] && return 0
|
|
local apk
|
|
mkdir -p "$abuildrepo"/$CARCH
|
|
cd "$abuildrepo" || return 1
|
|
# create links for this package
|
|
for apk in $(listpkg); do
|
|
[ -f "$PKGDEST"/$apk ] || continue
|
|
ln -sf "$PKGDEST"/$apk "$abuildrepo"/$CARCH/$apk
|
|
done
|
|
}
|
|
|
|
build_abuildrepo() {
|
|
local d apk _build=build
|
|
if ! is_function package; then
|
|
# if package() is missing then build is called from rootpkg
|
|
_build=true
|
|
fi
|
|
if ! apk_up2date || [ -n "$force" ]; then
|
|
# check early if we have abuild key
|
|
abuild-sign --installed || return 1
|
|
logcmd "building ${abuildrepo##*/}/$pkgname-$pkgver-r$pkgrel"
|
|
sanitycheck && builddeps && clean && fetch && unpack \
|
|
&& prepare && mkusers && $_build && rootpkg \
|
|
&& cleanup $CLEANUP \
|
|
|| return 1
|
|
fi
|
|
update_abuildrepo_index
|
|
}
|
|
|
|
update_abuildrepo_index() {
|
|
clean_abuildrepo
|
|
mklinks_abuildrepo
|
|
|
|
cd "$abuildrepo"
|
|
local index=$CARCH/APKINDEX.tar.gz
|
|
|
|
msg "Updating the cached abuild repository index..."
|
|
local sign=".SIGN.RSA.${SIGN_PUBLIC_KEY##*/}"
|
|
local oldindex=
|
|
if [ -f "$index" ]; then
|
|
oldindex="--index $index"
|
|
fi
|
|
$APK index --quiet $oldindex --output "$index".unsigned \
|
|
--description "$repo $(cd $startdir && git describe)" \
|
|
--rewrite-arch $CARCH \
|
|
$CARCH/*.apk || exit 1
|
|
msg "Signing the index..."
|
|
abuild-sign -q "$index".unsigned || exit 1
|
|
mv "$index".unsigned "$index"
|
|
chmod 644 "$index"
|
|
}
|
|
|
|
# predefined splitfunc doc
|
|
default_doc() {
|
|
depends="$depends_doc"
|
|
pkgdesc="$pkgdesc (documentation)"
|
|
arch=${arch_doc:-"noarch"}
|
|
install_if="docs $pkgname=$pkgver-r$pkgrel"
|
|
|
|
local i
|
|
for i in doc man info html sgml licenses gtk-doc ri help; do
|
|
if [ -d "$pkgdir/usr/share/$i" ]; then
|
|
mkdir -p "$subpkgdir/usr/share"
|
|
mv "$pkgdir/usr/share/$i" "$subpkgdir/usr/share/"
|
|
fi
|
|
done
|
|
|
|
# compress man pages
|
|
local previnode= prevname= mandir="$subpkgdir"/usr/share/man
|
|
[ -d "$mandir" ] && find "$subpkgdir"/usr/share/man \
|
|
-type f \( -name \*.[0-9n] -o -name \*.[0-9][a-z]* \) \
|
|
-exec stat -c "%i %n" {} \; | sort -n \
|
|
| while read inode name; do
|
|
|
|
if [ "$inode" = "$previnode" ]; then
|
|
# update hard link
|
|
rm "$name"
|
|
ln "$prevname".gz "$name".gz
|
|
else
|
|
gzip -9 "$name"
|
|
fi
|
|
|
|
previnode="$inode"
|
|
prevname="$name"
|
|
done
|
|
[ -d "$mandir" ] && find "$subpkgdir"/usr/share/man \
|
|
-type l \( -name \*.[0-9n] -o -name \*.[0-9][a-z]* \) \
|
|
| while read symlink; do
|
|
|
|
ln -s $(readlink $symlink).gz "$symlink".gz
|
|
rm "$symlink"
|
|
done
|
|
|
|
rm -f "$subpkgdir/usr/share/info/dir"
|
|
|
|
# remove if empty, ignore error (not empty)
|
|
rmdir "$pkgdir/usr/share" "$pkgdir/usr" 2>/dev/null
|
|
|
|
return 0
|
|
}
|
|
|
|
doc() {
|
|
default_doc
|
|
}
|
|
|
|
# predefined splitfunc doc
|
|
default_dbg() {
|
|
local f
|
|
binfiles=$(scanelf -R "$pkgdir" | grep ET_DYN | sed "s:$pkgdir\/::g" | sed "s:ET_DYN ::g")
|
|
for f in $binfiles; do
|
|
srcdir=$(dirname $pkgdir/$f)
|
|
srcfile=$(basename $pkgdir/$f)
|
|
dstdir=$(dirname $subpkgdir/usr/lib/debug/$f.debug)
|
|
dstfile=$(basename $subpkgdir/usr/lib/debug/$f.debug)
|
|
if [ ! -d $dstdir ] ; then
|
|
mkdir -p $dstdir
|
|
fi
|
|
cd $srcdir
|
|
objcopy --only-keep-debug $srcfile $dstfile
|
|
objcopy --add-gnu-debuglink=$dstfile $srcdir/$srcfile
|
|
mv $dstfile $dstdir
|
|
strip $srcfile
|
|
done
|
|
return 0
|
|
}
|
|
|
|
dbg() {
|
|
default_dbg
|
|
}
|
|
|
|
# predefined splitfunc dev
|
|
default_dev() {
|
|
local i= j=
|
|
depends="$depends_dev"
|
|
pkgdesc="$pkgdesc (development files)"
|
|
|
|
cd "$pkgdir" || return 0
|
|
local libdirs=usr/
|
|
[ -d lib/ ] && libdirs="lib/ $libdirs"
|
|
for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
|
|
usr/share/gettext usr/bin/*-config \
|
|
usr/share/vala/vapi usr/share/gir-[0-9]*\
|
|
usr/share/qt*/mkspecs \
|
|
usr/lib/qt*/mkspecs \
|
|
usr/lib/cmake \
|
|
$(find . -name include -type d) \
|
|
$(find $libdirs -name '*.[acho]' \
|
|
-o -name '*.prl' 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
|
|
# move *.so links needed when linking the apps to -dev packages
|
|
for i in lib/*.so usr/lib/*.so; do
|
|
if [ -L "$i" ]; then
|
|
mkdir -p "$subpkgdir"/"${i%/*}"
|
|
mv "$i" "$subpkgdir/$i" || return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
dev() {
|
|
default_dev
|
|
}
|
|
|
|
# predefined splitfunc libs
|
|
default_libs() {
|
|
pkgdesc="$pkgdesc (libraries)"
|
|
local dir= file=
|
|
for dir in lib usr/lib; do
|
|
for file in "$pkgdir"/$dir/lib*.so.[0-9]*; do
|
|
[ -f "$file" ] || continue
|
|
mkdir -p "$subpkgdir"/$dir
|
|
mv "$file" "$subpkgdir"/$dir/
|
|
done
|
|
done
|
|
}
|
|
|
|
libs() {
|
|
default_libs
|
|
}
|
|
|
|
is_function() {
|
|
type "$1" 2>&1 | head -n 1 | egrep -q "is a (shell )?function"
|
|
}
|
|
|
|
do_fakeroot() {
|
|
if [ -n "$FAKEROOT" ]; then
|
|
$FAKEROOT -- "$@"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# build and package in fakeroot
|
|
rootpkg() {
|
|
local _package=package
|
|
if ! is_function package; then
|
|
# if package() is missing then run 'build' in fakeroot instead
|
|
warning "No package() function in APKBUILD"
|
|
_package=build
|
|
fi
|
|
cd "$startdir"
|
|
rm -rf "$pkgdir"
|
|
[ -n "$FAKEROOT" ] && msg "Entering fakeroot..."
|
|
do_fakeroot "$abuild_path" $color_opt \
|
|
$_package \
|
|
prepare_subpackages \
|
|
prepare_language_packs \
|
|
prepare_package \
|
|
create_apks
|
|
}
|
|
|
|
srcpkg() {
|
|
getpkgver || return 1
|
|
local p="$pkgname-$pkgver-$pkgrel"
|
|
local prefix="${startdir##*/}"
|
|
local i files="$prefix/APKBUILD"
|
|
for i in $source; do
|
|
files="$files $prefix/$(filename_from uri $i)"
|
|
done
|
|
mkdir -p "$PKGDEST"
|
|
msg "Creating source package $p.src.tar.gz..."
|
|
(cd .. && tar -zcf "$PKGDEST/$p.src.tar.gz" $files)
|
|
}
|
|
|
|
# return true if arch is supported or noarch
|
|
check_arch() {
|
|
list_has $CARCH $arch || [ "$arch" = "noarch" ] || [ "$arch" = "all" ]
|
|
}
|
|
|
|
# return true if libc is not masked in options
|
|
check_libc() {
|
|
! list_has "!libc_$CLIBC" $options
|
|
}
|
|
|
|
# check if package is up to date
|
|
apk_up2date() {
|
|
getpkgver || return 1
|
|
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/$(filename_from_uri $i)"
|
|
else
|
|
s="$startdir/${i##*/}"
|
|
fi
|
|
if [ "$s" -nt "$pkg" ]; then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
abuildindex_up2date() {
|
|
local i
|
|
getpkgver || return 1
|
|
local dir="$abuildrepo"/$CARCH
|
|
local apk="${pkgname%:*}-$pkgver-r$pkgrel.apk"
|
|
local idx="$dir"/APKINDEX.tar.gz
|
|
local file="$dir"/$apk
|
|
|
|
# check if index is missing
|
|
[ -f "$idx" ] || return 1
|
|
|
|
# if link or file is missing, then we need update abuildrepo index
|
|
[ -f "$file" ] || return 1
|
|
|
|
# if file exists and is newer than index, then we need update index
|
|
[ "$file" -nt "$idx" ] && return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
up2date() {
|
|
check_arch || return 0
|
|
check_libc || return 0
|
|
apk_up2date && abuildindex_up2date
|
|
}
|
|
|
|
# rebuild package and abuildrepo index if needed
|
|
abuildindex() {
|
|
up2date && return 0
|
|
build_abuildrepo
|
|
}
|
|
|
|
# source all APKBUILDs and output:
|
|
# 1) origin of package
|
|
# 2) all dependencies
|
|
# the output is i in a format easy parseable for awk
|
|
parse_aports_makedepends() {
|
|
# lets run this in a subshell since we source all APKBUILD here
|
|
(
|
|
aportsdir=$(realpath ${APKBUILD%/APKBUILD}/..)
|
|
for i in $aportsdir/*/APKBUILD; do
|
|
# no forks in this loop or it will be painfully slow!
|
|
pkgname=
|
|
subpackages=
|
|
depends=
|
|
makedepends=
|
|
. $i
|
|
dir=${i%/APKBUILD}
|
|
deps=
|
|
# filter out conflicts from deps and version info
|
|
for j in $depends $makedepends; do
|
|
case "$j" in
|
|
!*) continue;;
|
|
esac
|
|
deps="$deps ${j%%[<>=]*}"
|
|
done
|
|
for j in $pkgname $subpackages; do
|
|
echo "o ${j%%:*} $dir"
|
|
set -- $deps
|
|
echo -n "d ${j%%:*} $1"
|
|
shift
|
|
while [ $# -gt 0 ]; do
|
|
echo -n ",$1"
|
|
shift
|
|
done
|
|
echo
|
|
done
|
|
done
|
|
)
|
|
}
|
|
|
|
trace_makedepends() {
|
|
local deps= i=
|
|
# strip versions from deps
|
|
for i in "$@"; do
|
|
deps="$deps ${i%%[<>=]*}"
|
|
done
|
|
[ -z "$deps" ] && return 0
|
|
( parse_aports_makedepends
|
|
if [ -z "$upgrade" ]; then
|
|
# list installed pkgs and prefix with 'i '
|
|
$APK info --quiet | sort | sed 's/^/i /'
|
|
fi
|
|
) | awk -v pkgs="$deps" '
|
|
|
|
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 pkg= i= missing=
|
|
local hostdeps= builddeps= installed_hostdeps= installed_builddeps=
|
|
[ -n "$nodeps" ] && return 0
|
|
msg "Analyzing dependencies..."
|
|
|
|
# add depends unless it is a subpackage or package itself
|
|
if cross_compiling && [ -n "$makedepends_build" -o -n "$makedepends_host" ]; then
|
|
builddeps="$makedepends_build"
|
|
for i in $BUILD_BASE; do
|
|
[ "$pkgname" = "${i%%[<>=]*}" ] && continue
|
|
subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
|
|
done
|
|
hostdeps="$makedepends_host"
|
|
for i in $depends; do
|
|
[ "$pkgname" = "${i%%[<>=]*}" ] && continue
|
|
subpackages_has ${i%%[<>=]*} || hostdeps="$hostdeps $i"
|
|
done
|
|
else
|
|
builddeps="$makedepends"
|
|
for i in $BUILD_BASE $depends; do
|
|
[ "$pkgname" = "${i%%[<>=]*}" ] && continue
|
|
subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
|
|
done
|
|
fi
|
|
|
|
installed_builddeps=$($APK info --installed $builddeps)
|
|
[ -n "$hostdeps" ] && installed_hostdeps=$($APK info --root "$CBUILDROOT" --installed $hostdeps)
|
|
|
|
# find which deps are missing
|
|
for i in $builddeps; do
|
|
if [ "${i#\!}" != "$i" ] && $APK info --quiet --installed "${i#\!}"; then
|
|
error "Conflicting package installed: ${i#\!}"
|
|
elif ! deplist_has $i $installed_builddeps || [ -n "$upgrade" ]; then
|
|
missing="$missing $i"
|
|
fi
|
|
done
|
|
for i in $hostdeps; do
|
|
if [ "${i#\!}" != "$i" ] && $APK info --quiet --installed --root "$CBUILDROOT" "${i#\!}"; then
|
|
error "Conflicting package installed: ${i#\!}"
|
|
elif ! deplist_has $i $installed_hostdeps || [ -n "$upgrade" ]; then
|
|
missing="$missing $i"
|
|
fi
|
|
done
|
|
|
|
if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
|
|
# if we dont have any missing deps we are done now
|
|
[ -z "$missing" ] && return 0
|
|
error "Missing dependencies: $missing Use -r to autoinstall or -R to build"
|
|
return 1
|
|
fi
|
|
|
|
uninstall_after=".makedepends-$pkgname $uninstall_after"
|
|
if [ -n "$install_deps" ] && [ -z "$recursive" ]; then
|
|
# make a --simulate run first to detect missing deps
|
|
# apk-tools --virtual is no goot at reporting those.
|
|
$SUDO_APK add --repository "$abuildrepo" $apk_opt_wait \
|
|
--simulate --quiet $builddeps || return 1
|
|
$SUDO_APK add --repository "$abuildrepo" $apk_opt_wait \
|
|
--virtual .makedepends-$pkgname $builddeps || return 1
|
|
if [ -n "$hostdeps" ]; then
|
|
$SUDO_APK add --root "$CBUILDROOT" --repository "$abuildrepo" $apk_opt_wait \
|
|
--simulate --quiet $hostdeps || return 1
|
|
$SUDO_APK add --root "$CBUILDROOT" --repository "$abuildrepo" $apk_opt_wait \
|
|
--virtual .makedepends-$pkgname $hostdeps || return 1
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
if [ -n "$CBUILDROOT" ]; then
|
|
error "Recursive rebuilding is not supported when cross compiling."
|
|
return 1
|
|
fi
|
|
[ -z "$recursive" ] && return 1
|
|
|
|
# find dependencies that are installed but missing in repo.
|
|
for i in $builddeps; do
|
|
local m=$($APK search --repository "$abuildrepo" ${i%%[<>=]*})
|
|
if [ -z "$m" ]; then
|
|
missing="$missing $i"
|
|
fi
|
|
done
|
|
|
|
for i in $(trace_makedepends $missing); do
|
|
# i = pkg:dir
|
|
local dir=${i#*:}
|
|
local pkg=${i%:*}
|
|
|
|
# ignore if dependency is in other repo
|
|
[ -d "$dir" ] || continue
|
|
|
|
# check if dep is blacklisted
|
|
if list_has $pkg $ABUILD_BLACKLIST; then
|
|
error "$pkg is blacklisted"
|
|
return 1
|
|
fi
|
|
|
|
# break circular deps
|
|
list_has $pkg $ABUILD_VISITED && continue
|
|
export ABUILD_VISITED="$ABUILD_VISITED $pkg"
|
|
|
|
msg "Entering $dir"
|
|
cd "$dir" && $0 $forceroot $keep $quiet $install_deps \
|
|
$recursive $upgrade $color_opt abuildindex || return 1
|
|
done
|
|
$SUDO_APK add --upgrade --repository "$abuildrepo" \
|
|
$apk_opt_wait \
|
|
--virtual .makedepends-$pkgname $builddeps
|
|
}
|
|
|
|
# replace the md5sums in the APKBUILD
|
|
checksum() {
|
|
local s files
|
|
[ -z "$source" ] && [ -n "${md5sums}${sha256sums}${sha512sums}" ] \
|
|
&& msg "Removing checksums from APKBUILD"
|
|
sed -i -e '/^md5sums="/,/"\$/d; /^md5sums=''/,/''\$/d' "$APKBUILD"
|
|
sed -i -e '/^sha512sums="/,/"\$/d; /^sha512sums=''/,/''\$/d' "$APKBUILD"
|
|
sed -i -e '/^sha256sums="/,/"\$/d; /^sha256sums=''/,/''\$/d' "$APKBUILD"
|
|
[ -z "$source" ] && return 0
|
|
fetch
|
|
for s in $source; do
|
|
files="$files $(filename_from_uri $s)"
|
|
done
|
|
|
|
# for compatibility/backporting reasons we still add md5sum
|
|
msg "Updating the md5sums in APKBUILD..."
|
|
md5sums="$(cd "$srcdir" && md5sum $files)" || die "md5sum failed"
|
|
echo "md5sums=\"$md5sums\"" >>"$APKBUILD"
|
|
|
|
msg "Updating the sha256sums in APKBUILD..."
|
|
sha256sums="$(cd "$srcdir" && sha256sum $files)" \
|
|
|| die "sha256sum failed"
|
|
echo "sha256sums=\"$sha256sums\"" >>"$APKBUILD"
|
|
|
|
msg "Updating the sha512sums in APKBUILD..."
|
|
sha512sums="$(cd "$srcdir" && sha512sum $files)" \
|
|
|| die "sha512sum failed"
|
|
echo "sha512sums=\"$sha512sums\"" >>"$APKBUILD"
|
|
}
|
|
|
|
stripbin() {
|
|
local bin
|
|
if options_has "!strip" || [ "$arch" = "noarch" ]; then
|
|
return 0
|
|
fi
|
|
cd "${subpkgdir:-$pkgdir}" || return 1
|
|
msg "Stripping binaries"
|
|
scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
|
|
| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
|
|
| while read filename; do
|
|
XATTR=$(getfattr --match="*" --dump "${filename}")
|
|
${CROSS_COMPILE}strip "${filename}"
|
|
[ -n "$XATTR" ] && (echo "$XATTR" | setfattr --restore=-)
|
|
done
|
|
}
|
|
|
|
# simply list target apks
|
|
listpkg() {
|
|
local name
|
|
getpkgver || return 1
|
|
for name in $(listpkgnames) ; do
|
|
echo "$name-$pkgver-r$pkgrel.apk"
|
|
done
|
|
}
|
|
|
|
source_has() {
|
|
local i
|
|
for i in $source; do
|
|
[ "$1" = "${i##*/}" ] && return 0
|
|
[ "$1" = "${i%%::*}" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
subpackages_has() {
|
|
local i
|
|
for i in $subpackages; do
|
|
[ "$1" = "${i%:*}" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
subpackage_types_has() {
|
|
local i
|
|
for i in $subpackages; do
|
|
[ "$1" = "${i##*-}" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
list_has() {
|
|
local needle="$1"
|
|
local i
|
|
shift
|
|
for i in $@; do
|
|
[ "$needle" = "$i" ] && return 0
|
|
[ "$needle" = "!$i" ] && return 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
options_has() {
|
|
list_has "$1" $options
|
|
}
|
|
|
|
depends_has() {
|
|
deplist_has "$1" $depends
|
|
}
|
|
|
|
makedepends_has() {
|
|
deplist_has "$1" $makedepends
|
|
}
|
|
|
|
md5sums_has() {
|
|
list_has "$1" $md5sums
|
|
}
|
|
|
|
install_has() {
|
|
list_has "$1" $install
|
|
}
|
|
|
|
# install package after build
|
|
post_add() {
|
|
getpkgver || return 1
|
|
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 $apk_opt_wait --upgrade "$pkgf" \
|
|
|| die "Failed to install $1"
|
|
}
|
|
|
|
deps() {
|
|
local builddeps i
|
|
builddeps="$makedepends"
|
|
for i in $depends; do
|
|
[ "$pkgname" = "${i%%[<>=]*}" ] && continue
|
|
subpackages_has ${i%%[<>=]*} || builddeps="$builddeps $i"
|
|
done
|
|
$SUDO_APK add $apk_opt_wait --repository "$abuildrepo" \
|
|
--virtual .makedepends-$pkgname \
|
|
$builddeps
|
|
}
|
|
|
|
undeps (){
|
|
$SUDO_APK del $apk_opt_wait .makedepends-$pkgname
|
|
if cross_compiling; then
|
|
$SUDO_APK del --root "$CBUILDROOT" $apk_opt_wait \
|
|
.makedepends-$pkgname
|
|
fi
|
|
}
|
|
|
|
# compat
|
|
installdeps() { deps; }
|
|
uninstalldeps() { undeps; }
|
|
index() { update_abuildrepo_index; }
|
|
|
|
all() {
|
|
if ! [ -n "$force" ]; then
|
|
check_arch
|
|
if [ $? -ne 0 ]; then
|
|
echo "Package not available for the target architecture ($CARCH). Aborting."
|
|
return 0
|
|
fi
|
|
check_libc || return 0
|
|
fi
|
|
if up2date && [ -z "$force" ]; then
|
|
msg "Package is up to date"
|
|
else
|
|
build_abuildrepo
|
|
fi
|
|
}
|
|
|
|
# This abuild hook will checkout an svn or git repository by specifying
|
|
# $svnurl or $giturl in APKBUILD. You can checkout a specific branch in
|
|
# git by adding -b $branch in $giturl. $reporev will select the correct
|
|
# commit, revision or tag for you. If you specify $disturl your distfile
|
|
# will automatically be uploaded with rsync to the url provided.
|
|
# Base version defaults to 0 except if specified by $verbase.
|
|
|
|
snapshot() {
|
|
# check if we setup vars correctly
|
|
[ -z "$disturl" ] && warning "Missing disturl in APKBUILD, auto uploading disabled."
|
|
[ -z "$svnurl" ] && [ -z "$giturl" ] && die "Missding repository url in APKBUILD!"
|
|
[ -n "$svnurl" ] && [ -n "$giturl" ] && die "You can only use a single repository!"
|
|
local _date=$(date +%Y%m%d)
|
|
local _format="tar.gz"
|
|
# remove any repositories left in srcdir
|
|
abuild clean
|
|
mkdir -p "$srcdir" && cd "$srcdir"
|
|
# clone git repo and archive
|
|
if [ -n "$giturl" ]; then
|
|
local _version=${verbase:-0}_git${_date}
|
|
command -v git >/dev/null || \
|
|
die "Missing git! Install git to support git clone."
|
|
[ -z "$reporev" ] && local _rev="HEAD" && local _depth="--depth=1"
|
|
msg "Creating git snapshot: $pkgname-$_version"
|
|
git clone $_depth --bare $giturl $pkgname-$_version || return 1
|
|
git --git-dir $pkgname-$_version archive \
|
|
--format=$_format \
|
|
-o $pkgname-$_version.$_format \
|
|
--prefix=$pkgname-$_version/ $_rev \
|
|
|| return 1
|
|
fi
|
|
# export svn repo and archive
|
|
if [ -n "$svnurl" ]; then
|
|
local _version=${verbase:-0}_svn${_date}
|
|
command -v svn >/dev/null || \
|
|
die "Missing svn! Install subverion to support svn export."
|
|
[ -n "$reporev" ] && local _rev="-r $reporev"
|
|
msg "Creating svn snapshot: $pkgname-$_version"
|
|
svn co $_rev $svnurl $pkgname-$_version || return 1
|
|
tar zcf $pkgname-$_version.$_format $pkgname-$_version || return 1
|
|
fi
|
|
# upload to defined distfiles url
|
|
if [ -n "$disturl" ]; then
|
|
command -v rsync >/dev/null || \
|
|
die "Missing rsync! Install rsync to enable automatic uploads."
|
|
msg "Uploading to $disturl"
|
|
rsync --progress -La $pkgname-$_version.$_format \
|
|
$disturl || return 1
|
|
cd "$startdir"
|
|
# set the pkgver to current date and update checksum
|
|
sed -i -e "s/^pkgver=.*/pkgver=${_version}/" \
|
|
APKBUILD || return 1
|
|
abuild checksum
|
|
fi
|
|
}
|
|
|
|
usage() {
|
|
echo "$program $program_version"
|
|
cat << EOF
|
|
usage: $program [options] [-i PKG] [-P REPODEST] [-p PKGDEST]
|
|
[-s SRCDEST] [cmd] ...
|
|
$program [-c] -n PKGNAME[-PKGVER]
|
|
Options:
|
|
-A Print CARCH and exit
|
|
-c Enable colored output
|
|
-d Disable dependency checking
|
|
-f Force specified cmd, even if they are already done
|
|
-F Force run as root
|
|
-h Show this help
|
|
-i Install PKG after successful build
|
|
-k Keep built packages, even if APKBUILD or sources are newer
|
|
-K Keep buildtime temp dirs and files (srcdir/pkgdir/deps)
|
|
-m Disable colors (monochrome)
|
|
-p Set package destination directory
|
|
-P Set PKGDEST to REPODEST/<repo>/\$CARCH, where repo is the parents dir name
|
|
-q Quiet
|
|
-r Install missing dependencies from system repository (using sudo)
|
|
-R Recursively build and install missing dependencies (using sudo)
|
|
-s Set source package destination directory
|
|
-u Recursively build and upgrade all dependencies (using sudo)
|
|
|
|
Commands:
|
|
build Compile and install package into \$pkgdir
|
|
checksum Generate checksum to be included in APKBUILD
|
|
clean Remove temp build and install dirs
|
|
cleancache Remove downloaded files from \$SRCDEST
|
|
cleanoldpkg Remove binary packages except current version
|
|
cleanpkg Remove already built binary and source package
|
|
deps Install packages listed in makedepends and depends
|
|
fetch Fetch sources to \$SRCDEST and verify checksums
|
|
index Regenerate the APKINDEX for abuildrepo
|
|
listpkg List target packages
|
|
package Create package in \$PKGDEST
|
|
prepare Apply patches
|
|
rootpkg Run 'package', the split functions and create apks as fakeroot
|
|
sanitycheck Basic sanity check of APKBUILD
|
|
snapshot Create a \$giturl or \$svnurl snapshot and upload to \$disturl
|
|
sourcecheck Check if remote source package exists upstream
|
|
srcpkg Make a source package
|
|
undeps Uninstall packages listed in makedepends and depends
|
|
unpack Unpack sources to \$srcdir
|
|
up2date Compare target and sources dates
|
|
verify Verify checksums
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
APKBUILD="${APKBUILD:-./APKBUILD}"
|
|
unset force
|
|
unset recursive
|
|
while getopts "AcdfFhi:kKimnp:P:qrRs:u" opt; do
|
|
case $opt in
|
|
'A') echo "$CARCH"; exit 0;;
|
|
'c') enable_colors
|
|
color_opt="-c";;
|
|
'd') nodeps=1;;
|
|
'f') force="-f";;
|
|
'F') forceroot="-F";;
|
|
'h') usage;;
|
|
'i') install_after="$install_after $OPTARG";;
|
|
'k') keep="-k";;
|
|
'K') CLEANUP="" ERROR_CLEANUP="" ;;
|
|
'm') disable_colors
|
|
color_opt="-m";;
|
|
'n') die "Use newapkbuild to create new aports";;
|
|
'p') PKGDEST=$OPTARG;;
|
|
'P') REPODEST=$OPTARG;;
|
|
'q') quiet="-q";;
|
|
'r') install_deps="-r";;
|
|
'R') recursive="-R";;
|
|
's') SRCDEST=$OPTARG;;
|
|
'u') upgrade="-u"
|
|
recursive="-R";;
|
|
esac
|
|
done
|
|
shift $(( $OPTIND - 1 ))
|
|
|
|
# check so we are not root
|
|
if [ "$(whoami)" = "root" ] && [ -z "$FAKEROOTKEY" ]; then
|
|
[ -z "$forceroot" ] && die "Do not run abuild as root"
|
|
FAKEROOT=
|
|
fi
|
|
|
|
# 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"}
|
|
|
|
repo=${startdir%/*}
|
|
repo=${repo##*/}
|
|
|
|
SRCDEST=${SRCDEST:-$startdir}
|
|
PKGDEST=${PKGDEST:-$startdir}
|
|
|
|
# set a default CC
|
|
: ${CC:=gcc}
|
|
export CC
|
|
|
|
cd "$startdir" || die
|
|
. "$APKBUILD"
|
|
|
|
# If REPODEST is set then it will override the PKGDEST
|
|
if [ -n "$REPODEST" ]; then
|
|
PKGDEST="$REPODEST/$repo/$CARCH"
|
|
# for recursive action
|
|
export REPODEST
|
|
abuildrepo="$REPODEST"/$repo
|
|
else
|
|
abuildrepo="$abuildrepo_base"/$repo
|
|
fi
|
|
|
|
# if we want build debug package
|
|
if [ -n "$DEBUG" ] || subpackage_types_has "dbg"; then
|
|
CFLAGS="$CFLAGS -g"
|
|
CXXFLAGS="$CXXFLAGS -g"
|
|
options="$options !strip"
|
|
fi
|
|
|
|
# If we are handling a sub package then reset subpackages and install
|
|
if [ -n "$subpkgname" ]; then
|
|
origsubpackages="$subpackages"
|
|
subpackages=
|
|
fi
|
|
pkgdir="$pkgbasedir/$pkgname"
|
|
controldir="$pkgbasedir"/.control.${subpkgname:-$pkgname}
|
|
|
|
trap 'die "Aborted by user"' INT
|
|
set_xterm_title "abuild: $pkgname"
|
|
|
|
if [ -z "$1" ]; then
|
|
set all
|
|
fi
|
|
|
|
while [ $# -gt 0 ]; do
|
|
runpart $1
|
|
shift
|
|
done
|
|
|
|
for i in $install_after; do
|
|
post_add $i
|
|
done
|
|
|
|
cleanup
|
|
|