aptextracttemplates() { runapt apt-extracttemplates "$@"; }
aptinternalsolver() { runapt "${APTINTERNALSOLVER}" "$@"; }
aptdumpsolver() { runapt "${APTDUMPSOLVER}" "$@"; }
+aptinternalplanner() { runapt "${APTINTERNALPLANNER}" "$@"; }
dpkg() {
"${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "$@"
fi
runapt command gdb --quiet -ex run "$CMD" --args "$CMD" "$@"
}
+lastmodification() {
+ date -u -d "@$(stat -c '%Y' "${TMPWORKINGDIRECTORY}/$1")" -R
+}
+releasefiledate() {
+ grep "^${2:-Date}:" "$1" | cut -d' ' -f 2-
+}
exitwithstatus() {
# error if we about to overflow, but ...
APTWEBSERVERBINDIR="${APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR:-"${BUILDDIRECTORY}"}"
APTINTERNALSOLVER="${APT_INTEGRATION_TESTS_INTERNAL_SOLVER:-"${BUILDDIRECTORY}/apt-internal-solver"}"
APTDUMPSOLVER="${APT_INTEGRATION_TESTS_DUMP_SOLVER:-"${BUILDDIRECTORY}/apt-dump-solver"}"
+ APTINTERNALPLANNER="${APT_INTEGRATION_TESTS_INTERNAL_PLANNER:-"${BUILDDIRECTORY}/apt-internal-planner"}"
test -x "${BUILDDIRECTORY}/apt-get" || msgdie "You need to build tree first"
# -----
mkdir -p usr/lib/apt
ln -s "${METHODSDIR}" usr/lib/apt/methods
if [ "$BUILDDIRECTORY" = "$LIBRARYPATH" ]; then
- mkdir -p usr/lib/apt/solvers
+ mkdir -p usr/lib/apt/solvers usr/lib/apt/planners
ln -s "${BUILDDIRECTORY}/apt-dump-solver" usr/lib/apt/solvers/dump
+ ln -s "${BUILDDIRECTORY}/apt-dump-solver" usr/lib/apt/planners/dump
ln -s "${BUILDDIRECTORY}/apt-internal-solver" usr/lib/apt/solvers/apt
- echo "Dir::Bin::Solvers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/solvers\";" > etc/apt/apt.conf.d/externalsolver.conf
+ ln -s "${BUILDDIRECTORY}/apt-internal-planner" usr/lib/apt/planners/apt
+ echo "Dir::Bin::Solvers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/solvers\";" >> ../aptconfig.conf
+ echo "Dir::Bin::Planners \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/planners\";" >> ../aptconfig.conf
fi
# use the autoremove from the BUILDDIRECTORY if its there, otherwise
# system
chmod 644 keys/*
ln -s "${TMPWORKINGDIRECTORY}/keys/joesixpack.pub" rootdir/etc/apt/trusted.gpg.d/joesixpack.gpg
- echo "Dir \"${TMPWORKINGDIRECTORY}/rootdir\";" > aptconfig.conf
+ echo "Dir \"${TMPWORKINGDIRECTORY}/rootdir\";" >> aptconfig.conf
echo "Dir::state::status \"${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status\";" >> aptconfig.conf
echo "APT::Get::Show-User-Simulation-Note \"false\";" >> aptconfig.conf
echo "Dir::Bin::Methods \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/methods\";" >> aptconfig.conf
# destroys coverage reporting though, so we disable changing user for the calling gpgv
echo "Dir::Bin::apt-key \"${BUILDDIRECTORY}/apt-key\";" >> aptconfig.conf
if [ "$(id -u)" = '0' ]; then
- echo 'Binary::gpgv::Debug::NoDropPrivs "true";' >>aptconfig.conf
+ echo 'Binary::gpgv::APT::Sandbox::User "root";' >> aptconfig.conf
+ # same for the solver executables
+ echo 'APT::Solver::RunAsUser "root";' >> aptconfig.conf
+ echo 'APT::Planner::RunAsUser "root";' >> aptconfig.conf
fi
cat > "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" <<EOF
fi
echo "Acquire::https::CaInfo \"${TMPWORKINGDIRECTORY}/rootdir/etc/webserver.pem\";" > rootdir/etc/apt/apt.conf.d/99https
echo "Apt::Cmd::Disable-Script-Warning \"1\";" > rootdir/etc/apt/apt.conf.d/apt-binary
+ export APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=no
echo 'Acquire::Connect::AddrConfig "false";' > rootdir/etc/apt/apt.conf.d/connect-addrconfig
configcompression '.' 'gz' #'bz2' 'lzma' 'xz'
echo 'Acquire::gpgv::Options { "--weak-digest"; "sha1"; };' > rootdir/etc/apt/apt.conf.d/no-sha1
fi
+ # most tests just need one signed Release file, not both
+ export APT_DONT_SIGN='Release.gpg'
+
+ if [ -r "${TESTDIRECTORY}/extra-environment" ]; then
+ . "${TESTDIRECTORY}/extra-environment"
+ fi
+
msgdone "info"
}
testempty --nomsg gcc -Wall -Wextra -fPIC -shared -o noopchroot.so noopchroot.c -ldl
}
configcompression() {
+ if [ "$1" = 'ALL' ]; then
+ configcompression '.' $(aptconfig dump APT::Compressor --format '%t %v%n' | sed -n 's#^Extension \.\(.*\)$#\1#p')
+ return
+ fi
local CMD='apthelper cat-file -C'
while [ -n "$1" ]; do
case "$1" in
local CONFFILE="${TMPWORKINGDIRECTORY}/rootdir/etc/apt/apt.conf.d/00force-compressor"
echo "Acquire::CompressionTypes::Order { \"${COMPRESS}\"; };
Dir::Bin::uncompressed \"/does/not/exist\";" > "$CONFFILE"
+ for COMP in $(aptconfig dump 'APT::Compressor' --format '%f%n' | cut -d':' -f 5 | uniq); do
+ if [ -z "$COMP" -o "$COMP" = '.' -o "$COMP" = "$COMPRESSOR" ]; then continue; fi
+ echo "Dir::Bin::${COMP} \"/does/not/exist\";" >> "$CONFFILE"
+ echo "APT::Compressor::${COMP}::Name \"${COMP}-disabled\";" >> "$CONFFILE"
+ done
}
-setupsimplenativepackage() {
- local NAME="$1"
- local ARCH="$2"
- local VERSION="$3"
- local RELEASE="${4:-unstable}"
- local DEPENDENCIES="$5"
- local DESCRIPTION="${6:-"an autogenerated dummy ${NAME}=${VERSION}/${RELEASE}
- If you find such a package installed on your system,
- something went horribly wrong! They are autogenerated
- und used only by testcases and serve no other purpose…"}"
-
- local SECTION="${7:-others}"
- local DISTSECTION
- if [ "$SECTION" = "${SECTION#*/}" ]; then
- DISTSECTION="main"
- else
- DISTSECTION="${SECTION%/*}"
- fi
- local BUILDDIR=incoming/${NAME}-${VERSION}
- mkdir -p ${BUILDDIR}/debian/source
- cd ${BUILDDIR}
- echo "* most suckless software product ever" > FEATURES
- test -e debian/copyright || echo "Copyleft by Joe Sixpack $(date +%Y)" > debian/copyright
- test -e debian/changelog || echo "$NAME ($VERSION) $RELEASE; urgency=low
-
- * Initial release
-
- -- Joe Sixpack <joe@example.org> $(date -R)" > debian/changelog
- test -e debian/control || echo "Source: $NAME
-Section: $SECTION
-Priority: optional
-Maintainer: Joe Sixpack <joe@example.org>
-Build-Depends: debhelper (>= 7)
-Standards-Version: 3.9.1
-
-Package: $NAME" > debian/control
- if [ "$ARCH" = 'all' ]; then
- echo "Architecture: all" >> debian/control
- else
- echo "Architecture: any" >> debian/control
- fi
- test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> debian/control
- echo "Description: $DESCRIPTION" >> debian/control
-
- test -e debian/compat || echo "7" > debian/compat
- test -e debian/source/format || echo "3.0 (native)" > debian/source/format
- test -e debian/rules || cp /usr/share/doc/debhelper/examples/rules.tiny debian/rules
- cd - > /dev/null
-}
-
-buildsimplenativepackage() {
+_setupsimplenativepackage() {
local NAME="$1"
- local NM
- if [ "$(echo "$NAME" | cut -c 1-3)" = 'lib' ]; then
- NM="$(echo "$NAME" | cut -c 1-4)"
- else
- NM="$(echo "$NAME" | cut -c 1)"
- fi
local ARCH="$2"
local VERSION="$3"
local RELEASE="${4:-unstable}"
fi
local BUILDDIR="${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}"
- msgtest "Build source package in version ${VERSION} for ${RELEASE} in ${DISTSECTION}" "$NAME"
mkdir -p "$BUILDDIR/debian/source"
echo "* most suckless software product ever" > "${BUILDDIR}/FEATURES"
echo "#!/bin/sh
echo '$NAME says \"Hello!\"'" > "${BUILDDIR}/${NAME}"
- echo "Copyleft by Joe Sixpack $(date +%Y)" > "${BUILDDIR}/debian/copyright"
+ echo "Copyleft by Joe Sixpack $(date -u +%Y)" > "${BUILDDIR}/debian/copyright"
echo "$NAME ($VERSION) $RELEASE; urgency=low
* Initial release
- -- Joe Sixpack <joe@example.org> $(date -R)" > "${BUILDDIR}/debian/changelog"
+ -- Joe Sixpack <joe@example.org> $(date -u -R)" > "${BUILDDIR}/debian/changelog"
{
echo "Source: $NAME
Priority: $PRIORITY
} > "${BUILDDIR}/debian/control"
echo '3.0 (native)' > "${BUILDDIR}/debian/source/format"
+}
+
+setupsimplenativepackage() {
+ _setupsimplenativepackage "$@"
+ local NAME="$1"
+ local VERSION="$3"
+ local BUILDDIR="${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}"
+ test -e "${BUILDDIR}/debian/compat" || echo '7' > "${BUILDDIR}/debian/compat"
+ test -e "${BUILDDIR}/debian/rules" || cp /usr/share/doc/debhelper/examples/rules.tiny "${BUILDDIR}/debian/rules"
+}
+
+buildsimplenativepackage() {
+ local NAME="$1"
+ local ARCH="$2"
+ local VERSION="$3"
+ local RELEASE="${4:-unstable}"
+ local DEPENDENCIES="$5"
+ local DESCRIPTION="$6"
+ local SECTION="${7:-others}"
+ local PRIORITY="${8:-optional}"
+ local FILE_TREE="$9"
+ local COMPRESS_TYPE="${10:-gzip}"
+ local DISTSECTION
+ if [ "$SECTION" = "${SECTION#*/}" ]; then
+ DISTSECTION="main"
+ else
+ DISTSECTION="${SECTION%/*}"
+ fi
+ local BUILDDIR="${TMPWORKINGDIRECTORY}/incoming/${NAME}-${VERSION}"
+ msgtest "Build source package in version ${VERSION} for ${RELEASE} in ${DISTSECTION}" "$NAME"
+ _setupsimplenativepackage "$@"
cd "${BUILDDIR}/.."
testsuccess --nomsg dpkg-source -b ${NAME}-${VERSION}
cd - >/dev/null
echo "pool/${NAME}_${VERSION}_${arch}.deb" >> "${BUILDDIR}/../${RELEASE}.${DISTSECTION}.pkglist"
done
+ local NM
+ if [ "$(echo "$NAME" | cut -c 1-3)" = 'lib' ]; then
+ NM="$(echo "$NAME" | cut -c 1-4)"
+ else
+ NM="$(echo "$NAME" | cut -c 1)"
+ fi
local CHANGEPATH="${BUILDDIR}/../${DISTSECTION}/${NM}/${NAME}/${NAME}_${VERSION}"
mkdir -p "$CHANGEPATH"
cp "${BUILDDIR}/debian/changelog" "$CHANGEPATH"
}
compressfile() {
- cat "${TMPWORKINGDIRECTORY}/rootdir/etc/testcase-compressor.conf" | while read compressor extension command; do
+ while read compressor extension command; do
if [ "$compressor" = '.' ]; then
if [ -n "$2" ]; then
touch -d "$2" "$1"
if [ -n "$2" ]; then
touch -d "$2" "${1}.${extension}"
fi
- done
+ done < "${TMPWORKINGDIRECTORY}/rootdir/etc/testcase-compressor.conf"
}
# can be overridden by testcases for their pleasure
fi
if [ -n "$DATE" -a "$DATE" != "now" ]; then
for release in $(find ./aptarchive -name 'Release'); do
- sed -i "s/^Date: .*$/Date: $(date -d "$DATE" '+%a, %d %b %Y %H:%M:%S %Z')/" "$release"
+ sed -i "s/^Date: .*$/Date: $(date -u -d "$DATE" -R)/" "$release"
touch -d "$DATE" "$release"
done
fi
if [ -n "$VALIDUNTIL" ]; then
sed -i "/^Date: / a\
-Valid-Until: $(date -d "$VALIDUNTIL" '+%a, %d %b %Y %H:%M:%S %Z')" $(find ./aptarchive -name 'Release')
+Valid-Until: $(date -u -d "$VALIDUNTIL" -R)" $(find ./aptarchive -name 'Release')
fi
msgdone "info"
}
}
signreleasefiles() {
- local SIGNER="${1:-Joe Sixpack}"
+ local SIGNERS="${1:-Joe Sixpack}"
local REPODIR="${2:-aptarchive}"
- local KEY="keys/$(echo "$SIGNER" | tr 'A-Z' 'a-z' | sed 's# ##g')"
- local GPG="aptkey --quiet --keyring ${KEY}.pub --secret-keyring ${KEY}.sec --readonly adv --batch --yes --digest-algo SHA512"
- msgninfo "\tSign archive with $SIGNER key $KEY… "
+ if [ -n "$1" ]; then shift; fi
+ if [ -n "$1" ]; then shift; fi
+ local KEY="keys/$(echo "$SIGNERS" | tr 'A-Z' 'a-z' | tr -d ' ,')"
+ msgninfo "\tSign archive with $SIGNERS key $KEY… "
local REXKEY='keys/rexexpired'
local SECEXPIREBAK="${REXKEY}.sec.bak"
local PUBEXPIREBAK="${REXKEY}.pub.bak"
- if [ "${SIGNER}" = 'Rex Expired' ]; then
- # the key is expired, so gpg doesn't allow to sign with and the --faked-system-time
- # option doesn't exist anymore (and using faketime would add a new obscure dependency)
- # therefore we 'temporary' make the key not expired and restore a backup after signing
- cp "${REXKEY}.sec" "$SECEXPIREBAK"
- cp "${REXKEY}.pub" "$PUBEXPIREBAK"
- local SECUNEXPIRED="${REXKEY}.sec.unexpired"
- local PUBUNEXPIRED="${REXKEY}.pub.unexpired"
- if [ -f "$SECUNEXPIRED" ] && [ -f "$PUBUNEXPIRED" ]; then
- cp "$SECUNEXPIRED" "${REXKEY}.sec"
- cp "$PUBUNEXPIRED" "${REXKEY}.pub"
- else
- if ! printf "expire\n1w\nsave\n" | $GPG --default-key "$SIGNER" --command-fd 0 --edit-key "${SIGNER}" >setexpire.gpg 2>&1; then
- cat setexpire.gpg
- exit 1
+ local SIGUSERS=""
+ while [ -n "${SIGNERS%%,*}" ]; do
+ local SIGNER="${SIGNERS%%,*}"
+ if [ "${SIGNERS}" = "${SIGNER}" ]; then
+ SIGNERS=""
+ fi
+ SIGNERS="${SIGNERS#*,}"
+ # FIXME: This should be the full name, but we can't encode the space properly currently
+ SIGUSERS="${SIGUSERS} -u ${SIGNER#* }"
+ if [ "${SIGNER}" = 'Rex Expired' ]; then
+ # the key is expired, so gpg doesn't allow to sign with and the --faked-system-time
+ # option doesn't exist anymore (and using faketime would add a new obscure dependency)
+ # therefore we 'temporary' make the key not expired and restore a backup after signing
+ cp "${REXKEY}.sec" "$SECEXPIREBAK"
+ cp "${REXKEY}.pub" "$PUBEXPIREBAK"
+ local SECUNEXPIRED="${REXKEY}.sec.unexpired"
+ local PUBUNEXPIRED="${REXKEY}.pub.unexpired"
+ if [ -f "$SECUNEXPIRED" ] && [ -f "$PUBUNEXPIRED" ]; then
+ cp "$SECUNEXPIRED" "${REXKEY}.sec"
+ cp "$PUBUNEXPIRED" "${REXKEY}.pub"
+ else
+ if ! printf "expire\n1w\nsave\n" | aptkey --quiet --keyring "${REXKEY}.pub" --secret-keyring "${REXKEY}.sec" \
+ --readonly adv --batch --yes --digest-algo "${APT_TESTS_DIGEST_ALGO:-SHA512}" \
+ --default-key "$SIGNER" --command-fd 0 --edit-key "${SIGNER}" >setexpire.gpg 2>&1; then
+ cat setexpire.gpg
+ exit 1
+ fi
+ cp "${REXKEY}.sec" "$SECUNEXPIRED"
+ cp "${REXKEY}.pub" "$PUBUNEXPIRED"
fi
- cp "${REXKEY}.sec" "$SECUNEXPIRED"
- cp "${REXKEY}.pub" "$PUBUNEXPIRED"
fi
+ if [ ! -e "${KEY}.pub" ]; then
+ local K="keys/$(echo "$SIGNER" | tr 'A-Z' 'a-z' | tr -d ' ,')"
+ cat "${K}.pub" >> "${KEY}.new.pub"
+ cat "${K}.sec" >> "${KEY}.new.sec"
+ fi
+ done
+ if [ ! -e "${KEY}.pub" ]; then
+ mv "${KEY}.new.pub" "${KEY}.pub"
+ mv "${KEY}.new.sec" "${KEY}.sec"
fi
+ local GPG="aptkey --quiet --keyring ${KEY}.pub --secret-keyring ${KEY}.sec --readonly adv --batch --yes --digest-algo ${APT_TESTS_DIGEST_ALGO:-SHA512}"
for RELEASE in $(find "${REPODIR}/" -name Release); do
- testsuccess $GPG --default-key "$SIGNER" --armor --detach-sign --sign --output "${RELEASE}.gpg" "${RELEASE}"
- local INRELEASE="$(echo "${RELEASE}" | sed 's#/Release$#/InRelease#')"
- testsuccess $GPG --default-key "$SIGNER" --clearsign --output "$INRELEASE" "$RELEASE"
# we might have set a specific date for the Release file, so copy it
- touch -d "$(stat --format "%y" ${RELEASE})" "${RELEASE}.gpg" "${INRELEASE}"
+ local DATE="$(stat --format "%y" "${RELEASE}")"
+ if [ "$APT_DONT_SIGN" = 'Release.gpg' ]; then
+ rm -f "${RELEASE}.gpg"
+ else
+ testsuccess $GPG "$@" $SIGUSERS --armor --detach-sign --sign --output "${RELEASE}.gpg" "${RELEASE}"
+ touch -d "$DATE" "${RELEASE}.gpg"
+ fi
+ local INRELEASE="${RELEASE%/*}/InRelease"
+ if [ "$APT_DONT_SIGN" = 'InRelease' ]; then
+ rm -f "$INRELEASE"
+ else
+ testsuccess $GPG "$@" $SIGUSERS --clearsign --output "$INRELEASE" "$RELEASE"
+ touch -d "$DATE" "${INRELEASE}"
+ fi
done
if [ -f "$SECEXPIREBAK" ] && [ -f "$PUBEXPIREBAK" ]; then
mv -f "$SECEXPIREBAK" "${REXKEY}.sec"
}
redatereleasefiles() {
- local DATE="$(date -d "$1" '+%a, %d %b %Y %H:%M:%S %Z')"
+ local DATE="$(date -u -d "$1" -R)"
for release in $(find aptarchive/ -name 'Release'); do
sed -i "s/^Date: .*$/Date: ${DATE}/" "$release"
touch -d "$DATE" "$release"
local APTARCHIVE2="copy://$(readlink -f "${TMPWORKINGDIRECTORY}/aptarchive" | sed 's# #%20#g')"
for LIST in $(find rootdir/etc/apt/sources.list.d/ -name 'apt-test-*.list'); do
sed -i $LIST -e "s#$APTARCHIVE#${1}#" -e "s#$APTARCHIVE2#${1}#" \
- -e "s#http://localhost:${APTHTTPPORT}/#${1}#" \
- -e "s#https://localhost:${APTHTTPSPORT}/#${1}#"
+ -e "s#http://[^@]*@\?localhost:${APTHTTPPORT}/\?#${1}#" \
+ -e "s#https://[^@]*@\?localhost:${APTHTTPSPORT}/\?#${1}#"
done
}
msgdie 'Could not fork stunnel4 successfully'
fi
addtrap 'prefix' "kill ${PID};"
- APTHTTPSPORT="$(lsof -i | awk "/^stunnel4 / && \$2 == \"${PID}\" {print \$9; exit; }" | cut -d':' -f 2)"
+ APTHTTPSPORT="$(lsof -i -n | awk "/^stunnel4 / && \$2 == \"${PID}\" {print \$9; exit; }" | cut -d':' -f 2)"
webserverconfig 'aptwebserver::port::https' "$APTHTTPSPORT" "https://localhost:${APTHTTPSPORT}"
rewritesourceslist "https://localhost:${APTHTTPSPORT}/"
}
msggroup
}
+catfile() {
+ if [ "${1##*.}" = 'deb' ]; then
+ stat >&2 "$1" || true
+ file >&2 "$1" || true
+ else
+ cat >&2 "$1" || true
+ fi
+}
msgfailoutput() {
msgreportheader 'msgfailoutput'
local MSG="$1"
local OUTPUT="$2"
shift 2
- if [ "$1" = 'grep' ]; then
+ local CMD="$1"
+ if [ "$1" = 'grep' -o "$1" = 'tail' -o "$1" = 'head' ]; then
echo >&2
while [ -n "$2" ]; do shift; done
echo "#### Complete file: $1 ####"
- cat >&2 "$1" || true
- echo '#### grep output ####'
+ catfile "$1"
+ echo "#### $CMD output ####"
elif [ "$1" = 'test' ]; then
echo >&2
# doesn't support ! or non-file flags
ls >&2 "$2" || true
elif test -e "$2"; then
echo "#### Complete file: $2 ####"
- cat >&2 "$2" || true
+ catfile "$2"
fi
fi
}
echo >&2
while [ -n "$2" ]; do
echo "#### Complete file: $2 ####"
- cat >&2 "$2" || true
+ catfile "$2"
shift
done
echo '#### cmp output ####'
fi
- cat >&2 "$OUTPUT"
+ catfile "$OUTPUT"
msgfail "$MSG"
}
local EXITCODE=$?
if expr match "$1" '^apt.*' >/dev/null; then
if [ "$1" = 'aptkey' ]; then
- if grep -q -E " Can't check signature: " "$OUTPUT" || \
- grep -q -E " BAD signature from " "$OUTPUT"; then
+ if grep -q " Can't check signature:
+ BAD signature from
+ signature could not be verified" "$OUTPUT"; then
msgpass
else
msgfailoutput "run failed with exitcode ${EXITCODE}, but no signature error" "$OUTPUT" "$@"
} | sort
}
forallsupportedcompressors() {
+ rm -f "${TMPWORKINGDIRECTORY}/rootdir/etc/apt/apt.conf.d/00force-compressor"
for COMP in $(aptconfig dump 'APT::Compressor' --format '%f%n' | cut -d':' -f 5 | uniq); do
if [ -z "$COMP" -o "$COMP" = '.' ]; then continue; fi
"$@" "$COMP"