#! /usr/bin/env bash
# Set timezone to default
TZ=UTC
export TZ
targetmode='install'
if [ "$1" == '--cpio' ]; then
targetmode='archive'
shift
fi
pkg="$(echo "$1" | sed 's@/*$@@;s@^\.*/*@@')"
if [ -z "${pkg}" ]; then
echo "Usage: build [--cpio] <package>" 2>&1
exit 1
fi
function download() {
if [ ! -e "${pkgarchive}" ]; then
# Download
## Cleanup
rm -f src.new
## Fetch file
wget -O src.new "${url}" || exit 1
## Verify signature
src_sha256="$(openssl sha256 'src.new' | sed 's@^.*= @@')"
if [ "${src_sha256}" != "${sha256}" ]; then
echo "SHA256 mismatch: Downloaded: ${src_sha256} != Expected: ${sha256}" >&2
exit 1
fi
## Move file into place
mv src.new "${pkgarchive}"
fi
}
function extract() {
local decompress
# Decompress archive
## Determine type of archive
case "${url}" in
*.tar.xz|*.tar.xz'?'*|*.txz)
decompress='xz'
;;
*.tar.gz|*.tar.gz'?'*|*.tgz)
decompress='gzip'
;;
*.tar.bz2|*.tar.bz2'?'*|*.tbz2)
decompress='bzip2'
;;
*.zip|*.zip'?'*)
decompress='unzip'
;;
*)
echo "Unknown compression method: ${url}" >&2
exit 1
;;
esac
## Do decompression
case "${decompress}" in
unzip)
unzip "${pkgarchive}" || die 'Unable to uncompress archive'
;;
*)
"${decompress}" -dc "${pkgarchive}" | tar -xf - || die 'Unable to uncompress archive'
;;
esac
}
function apply_patches() {
local patch
for patch in "${pkgdir}/patches"/*; do
if [ ! -e "${patch}" ]; then
continue
fi
case "${patch}" in
*.diff|*.patch)
;;
*)
continue
;;
esac
if [ -e "${patch}.sh" ]; then
if ! sh "${patch}.sh"; then
continue
fi
fi
patch -p1 < "${patch}"
done
}
function verifyRequiredPackages() {
local pkg pkgdomain pkgversion
local pkgdir pkgconfigdir pkgfound
for pkg in "${require[@]}"; do
pkgdomain=''
pkgversion=''
pkgchanges=(CFLAGS LDFLAGS PATH PKG_CONFIG_PATH)
case "${pkg}" in
*:*)
pkgchanges=($(echo "${pkg}" | cut -f 2 -d ':'))
pkg="$(echo "${pkg}" | cut -f 1 -d ':')"
;;
esac
case "${pkg}" in
@*)
# Fake package
continue
;;
*/*@*)
pkgdomain="$(echo "${pkg}" | cut -f 2 -d '@')"
pkgversion="$(echo "${pkg}" | cut -f 2 -d '/' | cut -f 1 -d '@')"
pkg="$(echo "${pkg}" | cut -f 1 -d '/')"
;;
*/*)
pkgversion="$(echo "${pkg}" | cut -f 2 -d '/')"
pkg="$(echo "${pkg}" | cut -f 1 -d '/')"
;;
*@*)
pkgdomain="$(echo "${pkg}" | cut -f 2 -d '@')"
pkg="$(echo "${pkg}" | cut -f 1 -d '@')"
;;
esac
if [ -z "${pkgdomain}" ]; then
pkgdomain="${domain}"
fi
pkgfound='0'
for pkgdir in "/opt/appfs/${pkgdomain}/${pkg}/platform"/${pkgversion:-latest} "/opt/appfs/${pkgdomain}/${pkg}/platform"/${pkgversion:-*}; do
pkgconfigdir="${pkgdir}/lib/pkgconfig"
if [ ! -d "${pkgdir}" ]; then
continue
fi
# If the package version was unspecified, fully resolve
# the directory that we found
if [ -z "${pkgversion}" ]; then
pkgdir="$(readlink -f "${pkgdir}")"
fi
pkgfound='1'
for pkgchange in "${pkgchanges[@]}"; do
case "${pkgchange}" in
CFLAGS)
CFLAGS="${CFLAGS} -isystem ${pkgdir}/include"
CPPFLAGS="${CPPFLAGS} -isystem ${pkgdir}/include"
export CFLAGS CPPFLAGS
;;
LDFLAGS)
LDFLAGS="${LDFLAGS} -L${pkgdir}/lib -Wl,-rpath,${pkgdir}/lib"
export LDFLAGS
;;
PATH)
PATH="${PATH}:${pkgdir}/bin"
export PATH
;;
PKG_CONFIG_PATH)
if [ -d "${pkgconfigdir}" ]; then
PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:${pkgconfigdir}"
export PKG_CONFIG_PATH
fi
;;
esac
done
break
done
if [ "${pkgfound}" = '0' ]; then
die "Package ${pkg}/${pkgversion:-*}@${pkgdomain} not found."
fi
done
}
function verifyPrerequisites() {
:
}
function determineOsArch() {
os="$(uname -s | dd conv=lcase 2>/dev/null)"
arch="$(uname -m | dd conv=lcase 2>/dev/null)"
case "${arch}" in
i?86)
arch='ix86'
;;
esac
}
function determinePrefix() {
determineOsArch
prefixsuffix="${pkg}/${os}-${arch}/${version}"
prefix="/opt/appfs/${domain}/${prefixsuffix}"
destdir="$(pwd)/INST"
mkdir "${destdir}" || die
}
function preconfigure() {
:
}
function postconfigure() {
:
}
function configure_gcc() {
local glibcdir linuxheadersdir
local dynlinker
local gcc_default_headers
local pkg use_native_platform
glibcdir="/opt/appfs/core.appfs.rkeene.org/glibc/platform/latest"
glibcdir="$(readlink -f "${glibcdir}")"
linuxheadersdir="/opt/appfs/core.appfs.rkeene.org/linux-headers/platform/latest"
linuxheadersdir="$(readlink -f "${linuxheadersdir}")"
dynlinker="$(ls "${glibcdir}"/lib/ld-linux*.so.* | tail -n 1)"
if [ ! -f "${dynlinker}" ]; then
die 'glibc directory is not available (appfs running/working?)'
fi
use_native_platform='0'
for pkg in "${require[@]}"; do
case "${pkg}" in
@native-os)
use_native_platform='1'
;;
esac
done
if [ "${use_native_platform}" = '0' ]; then
gcc_default_headers="$(echo '' | ${CPP:-cpp} -v 2>&1 | sed '/^End of search list/,$ d;0,/search starts here:$/ d' | grep '/gcc/' | sed 's@^ *@-isystem @' | tr $'\n' ' ')"
CC="${CC:-gcc} -nostdinc ${gcc_default_headers} -isystem ${glibcdir}/include"
CXX="${CXX:-g++} -nostdinc ${gcc_default_headers} -isystem ${glibcdir}/include"
if ! echo " ${require[*]} " | grep ' linux-headers[/@: ]' >/dev/null; then
CC="${CC} -isystem ${linuxheadersdir}/include"
CXX="${CXX} -isystem ${linuxheadersdir}/include"
fi
else
CC="${CC:-gcc} -isystem ${glibcdir}/include"
CXX="${CXX:-g++} -isystem ${glibcdir}/include"
fi
BUILD_CC="${CC}"
HOST_CC="${CC}"
LDFLAGS="${LDFLAGS} -L${glibcdir}/lib -Wl,-rpath,${glibcdir}/lib -Wl,--dynamic-linker,${dynlinker}"
if [ -z "${appfs_build_no_default_symver}" ]; then
LDFLAGS="${LDFLAGS} -Wl,--default-symver"
fi
PKG_CONFIG_LIBDIR="${glibcdir}/lib/pkgconfig"
export CC BUILD_CC HOST_CC LDFLAGS PKG_CONFIG_LIBDIR
}
function configure() {
configure_gcc
./configure --prefix="${prefix}" --sysconfdir="${prefix}/etc" --libdir="${prefix}/lib" --localstatedir=/var "${configure_extra[@]}"
}
function prebuild() {
:
}
function postbuild() {
:
}
function build() {
grep "DESTDIR" Makefile >/dev/null || die "Don't know how to build this software"
make "${make_extra[@]}"
}
function preinstall() {
:
}
function postinstall() {
:
}
function install() {
make install DESTDIR="${destdir}"
}
function cleanup() {
cd "${workdir}" || exit 1
cd .. || exit 1
rm -rf "${workdir}"
}
function die() {
local message
message="$1"
if [ -n "${message}" ]; then
echo "error: ${message}" >&2
fi
exit 1
}
scriptdir="$(cd "$(dirname "$(which "$0")")" && pwd)"
if [ -z "${scriptdir}" ]; then
echo "Unable to locate script directory" >&2
exit 1
fi
cd "${scriptdir}" || exit 1
if [ -f 'build.conf' ]; then
. 'build.conf'
fi
if [ -d "pkgs/${pkg}" ]; then
pkgdir="$(pwd)/pkgs/${pkg}"
pkgfile="${pkgdir}/info"
else
pkgfile="$(pwd)/pkgs/${pkg}"
pkgdir="${pkgfile}"
fi
if [ ! -e "${pkgfile}" ]; then
echo "Invalid package." >&2
exit 1
fi
pkgdate="$(for artifact in $(find "${pkgdir}" -type f -print0 | xargs -n 1 -0 fossil finfo --limit 1 --width 0 2>/dev/null | grep '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] ' | sed 's@^[^ ]* \[@@;s@\].*@@' | sort -u); do fossil info "${artifact}" | awk '/^uuid:/{ print $3 $4 }' | sed 's@[-:]@@g;s@..$@\.&@'; done | sort -n | tail -n 1)"
if [ -z "${pkgdate}" ]; then
pkgdate="$(find "${pkgdir}" -type f -printf '%TY%Tm%Td%TH%TM.%TS\n' 2>/dev/null | cut -f 1-2 -d '.' | sort -n | tail -n 1)"
fi
. "${pkgfile}"
archivedir="$(pwd)/ARCHIVE"
workdir="workdir-$$${RANDOM}${RANDOM}${RANDOM}"
pkgarchive="${archivedir}/${pkg}-${version}.archive"
mkdir "${archivedir}" >/dev/null 2>/dev/null
mkdir "${workdir}" || exit 1
cd "${workdir}" || exit 1
workdir="$(pwd)"
# Download
download
# Extract
extract
# If we just have one directory, use that directory
dir="$(echo *)"
if [ -e "${dir}" ]; then
mv "${dir}"/* .
fi
# Verify pre-requisites are met
verifyRequiredPackages || die 'Required packages missing'
verifyPrerequisites || die 'Prerequisities failed'
# Start logging
set -x
# Determine properties
determinePrefix
# Apply patches
apply_patches
# Start the build
preconfigure || die 'preconfigure failed'
configure || die 'configure failed'
postconfigure || die 'postconfigure failed'
prebuild || die 'prebuild failed'
build || die 'build failed'
postbuild || die 'postbuild failed'
preinstall || die 'preinstall failed'
install || die 'install failed'
postinstall || die 'postinstall failed'
(
case "${targetmode}" in
install)
appdir="$(appfsinstalldir)/${prefixsuffix}"
mkdir -p "${appdir}"
cd "${destdir}/${prefix}" || exit 1
cp -rp * "${appdir}"
find "${appdir}" -print0 | xargs -0 touch -t "${pkgdate}"
find "${appdir}" -print0 | xargs -0 touch -m -t "${pkgdate}"
find "${appdir}" -print0 | xargs -0 touch -a -t "${pkgdate}"
;;
archive)
archivefile="${scriptdir}/${pkg}-${version}-$(echo "${pkgdate}" | sed 's@\.@@g')-${os}-${arch}-${domain}.cpio"
cd "${destdir}/${prefix}/../../.." || exit 1
find "${prefixsuffix}" -print0 | xargs -0 touch -t "${pkgdate}"
find "${prefixsuffix}" -print0 | xargs -0 touch -m -t "${pkgdate}"
find "${prefixsuffix}" -print0 | xargs -0 touch -a -t "${pkgdate}"
find "${prefixsuffix}" | sort | cpio --owner 0:0 -H newc -o > "${archivefile}"
;;
esac
) || die 'final installation failed'
cleanup
exit 0