aboutsummaryrefslogtreecommitdiff
path: root/pbuilder-satisfydepends-experimental
diff options
context:
space:
mode:
authorlool <lool>2006-11-06 20:55:12 +0000
committerlool <lool>2006-11-06 20:55:12 +0000
commit1aa3024fb4b430b2336f6b5fe870f81496344ebc (patch)
treec546c8d8601ddf12d840cc2ae489645a21214e0a /pbuilder-satisfydepends-experimental
parentc348757fc7a8c4d87ce0ba3012ffc54e55b53f81 (diff)
downloadpbuilder-1aa3024fb4b430b2336f6b5fe870f81496344ebc.tar
pbuilder-1aa3024fb4b430b2336f6b5fe870f81496344ebc.tar.gz
* pbuilder-satisfydepends-experimental, Makefile: alternate
implementation of pbuilder-satisfydepends which supports pulling build-deps with a version on the apt-get command-line; this is derived from pbuilder-satisfydepends with the following changes: - Add and use new package_versions() and candidate_version() helpers; the former returns all versions of a package available via APT, the later APT's candidate version. - For versionned build-deps, when building the "apt-get install" command, try APT's candidate version or all available versions available from APT in ascending order (the reverse order of apt-cache's output); checkbuilddep_versiondeps() isn't used for this part of the process anymore, but it is still used to honor build-conflicts. - Recover from APT errors caused by unsufficient dependencies ("libfoo-dev Depends: bar but baz is to be installed") and missing dependencies libfoo-dev Depends: bar but it is not going to be installed", or simply "libfoo-dev Depends: bar"); this permits simply listing build-deps when uploading to experimental; achieved by moving the version matching logic in the new versioneddep_to_aptcmd() helper. * pbuilderrc, pbuilderrc.5: document the availability of the alternate implementation.
Diffstat (limited to 'pbuilder-satisfydepends-experimental')
-rwxr-xr-xpbuilder-satisfydepends-experimental365
1 files changed, 365 insertions, 0 deletions
diff --git a/pbuilder-satisfydepends-experimental b/pbuilder-satisfydepends-experimental
new file mode 100755
index 0000000..633acf7
--- /dev/null
+++ b/pbuilder-satisfydepends-experimental
@@ -0,0 +1,365 @@
+#!/bin/bash
+# pbuilder -- personal Debian package builder
+# Copyright (C) 2001,2002,2003,2005-2006 Junichi Uekawa
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# module to satisfy dependency.
+
+set -e
+
+function package_versions() {
+ local PACKAGE="$1"
+ ( $CHROOTEXEC /usr/bin/apt-cache show "$PACKAGE" ) | sed -n 's/^Version: \(.*\)$/\1/p'
+}
+
+function candidate_version() {
+ local PACKAGE="$1"
+ LC_ALL=C $CHROOTEXEC apt-cache policy "$PACKAGE" | sed -n 's/ *Candidate: *\(.*\)/\1/p'
+}
+
+function checkbuilddep_versiondeps () {
+ local PACKAGE="$1"
+ local COMPARESTRING="$2"
+ local DEPSVERSION="$3"
+ local PACKAGEVERSIONS=$( package_versions "$PACKAGE" | xargs)
+ # no versioned provides.
+ if [ "${FORCEVERSION}" = "yes" ]; then
+ return 0;
+ fi
+ for PACKAGEVERSION in $PACKAGEVERSIONS ; do
+ if dpkg --compare-versions "$PACKAGEVERSION" "$COMPARESTRING" "$DEPSVERSION"; then
+ # satisfies depends
+ return 0;
+ fi
+ done
+ echo " Tried versions: $PACKAGEVERSIONS"
+ # cannot satisfy depends
+ return 1;
+}
+
+function expand_arch () {
+ local ARCH="$1"
+ local EXPANDED_ARCH
+
+ # just keep the original behavior.
+ echo "$ARCH"
+ return
+
+ # the following may be used if dpkg change is set to stone.
+ if echo "$ARCH" | grep "-" > /dev/null; then
+ EXPANDED_ARCH=$ARCH
+ else
+ EXPANDED_ARCH="linux-$ARCH"
+ fi
+ local WC1=$(echo $EXPANDED_ARCH | sed 's/^[^-]*/any/')
+ local WC2=$(echo $EXPANDED_ARCH | sed 's/[^-]*$/any/')
+ echo "$ARCH\\|$EXPANDED_ARCH\\|$WC1\\|$WC2"
+}
+
+function checkbuilddep_archdeps () {
+ # returns FALSE on INSTALL
+ local INSTALLPKG="$1"
+ local ARCH="$2"
+ if echo "$INSTALLPKG" | sed 's/.*\(\[.*\]\)/\1/' | grep "[[/][!]\($(expand_arch $ARCH)\)[]/]" > /dev/null; then
+ # if !$ARCH exists in there, ERROR.
+ return 0;
+ fi
+ if ! echo "$INSTALLPKG" | sed 's/.*\(\[.*\]\)/\1/' | grep "[!]" > /dev/null; then
+ if ! echo "$INSTALLPKG" | sed 's/.*\(\[.*\]\)/\1/' | grep "[[/]\($(expand_arch $ARCH)\)[]/]" > /dev/null; then
+ # if $ARCH does not exist, ERROR.
+ return 0;
+ fi
+ fi
+ return 1;
+}
+
+function checkbuilddep_provides () {
+ local PACKAGENAME="$1"
+ # PROVIDED needs to be used outside of this function.
+ PROVIDED=$($CHROOTEXEC /usr/bin/apt-cache showpkg $PACKAGENAME | awk '{p=0}/^Reverse Provides:/,/^$/{p=1}{if(p && ($0 !~ "Reverse Provides:")){PACKAGE=$1}} END{print PACKAGE}')
+}
+
+# returns either "package=version", to append to an apt-get install line, or
+# package
+function versioneddep_to_aptcmd () {
+ local INSTALLPKG="$1"
+
+ local PACKAGE
+ local PACKAGE_WITHVERSION
+ local PACKAGEVERSIONS
+ local CANDIDATE_VERSION
+ local COMPARESTRING
+ local DEPSVERSION
+
+ PACKAGE="$(echo "$INSTALLPKG" | sed -e 's/^[/]*//' -e 's/[[/(].*//')"
+ PACKAGE_WITHVERSION="$PACKAGE"
+
+ # if not versionned, we skip directly to outputting $PACKAGE
+ if echo "$INSTALLPKG" | grep '[(]' > /dev/null; then
+ # package versions returned by APT, in reversed order
+ PACKAGEVERSIONS="$( package_versions "$PACKAGE" | tac | xargs )"
+ CANDIDATE_VERSION="$( candidate_version "$PACKAGE" )"
+
+ # try the candidate version, then all available versions (asc)
+ for VERSION in $CANDIDATE_VERSION $PACKAGEVERSIONS; do
+ COMPARESTRING=$(echo "$INSTALLPKG" | tr "/" " " | sed 's/^.*([ ]*\(<<\|<=\|>=\|=\|<\|>>\|>\)[ ]*\(.*\)).*$/\1/')
+ DEPSVERSION="$(echo "$INSTALLPKG" | tr "/" " " | sed 's/^.*([ ]*\(<<\|<=\|>=\|=\|<\|>>\|>\)[ ]*\(.*\)).*$/\2/')"
+ if dpkg --compare-versions "$VERSION" "$COMPARESTRING" "$DEPSVERSION"; then
+ if [ $VERSION != $CANDIDATE_VERSION ]; then
+ PACKAGE_WITHVERSION="$PACKAGE=$VERSION"
+ fi
+ break;
+ fi
+ done
+ fi
+
+ echo "$PACKAGE_WITHVERSION"
+}
+
+function checkbuilddep_internal () {
+# Use this function to fulfill the dependency (almost)
+
+ local ARCH=$(dpkg-architecture -qDEB_HOST_ARCH)
+ local INSTALLPKG
+ local INSTALLPKGLIST
+ local INSTALLPKGMULTI
+ local CURRENTREALPKGNAME
+ local SATISFIED
+ local PACKAGEVERSIONS
+ local CANDIDATE_VERSION
+ echo " -> Attempting to parse the build-deps $Id$"
+ for INSTALLPKGMULTI in $(cat ${DEBIAN_CONTROL} | \
+ awk '
+BEGIN{source=1}
+/^$/ {source=0}
+/^Source:/ {source=1}
+/^[^ ]*:/ {p=0}
+tolower($0) ~ /^'"${BD_REGEXP}"':/ {p=1}
+{if(p && source) {print $0}}' | \
+ sed 's/^[^: ]*://' | \
+ tr " " "/" | \
+ awk 'BEGIN{RS=","} {print}'); do
+ echo " -> Considering build-dep$(echo "$INSTALLPKGMULTI" | tr "/" " " )"
+ SATISFIED="no"
+ for INSTALLPKG in $(echo "$INSTALLPKGMULTI" | \
+ awk 'BEGIN{RS="|"} {print}'); do
+ CURRENTREALPKGNAME=$(echo "$INSTALLPKG" | sed -e 's/^[/]*//' -e 's/[[/(].*//')
+ if echo "$INSTALLPKG" | grep '\[' > /dev/null ; then
+ if checkbuilddep_archdeps "$INSTALLPKG" "$ARCH"; then
+ SATISFIED="yes"
+ echo " -> This package is not for this architecture"
+ continue;
+ fi
+ fi
+
+ CURRENT_APT_COMMAND="$(versioneddep_to_aptcmd "$INSTALLPKG")"
+
+ while [ "$SATISFIED" = "no" ]; do
+ echo " -> Trying to add ${CURRENT_APT_COMMAND}"
+ if APT_OUTPUT="$( exec 2>&1; LC_ALL=C $CHROOTEXEC /usr/bin/apt-get -s install ${INSTALLPKGLIST} ${CURRENT_APT_COMMAND} )"; then
+ # success, we're done
+ SATISFIED="yes"
+ INSTALLPKGLIST="${INSTALLPKGLIST} ${CURRENT_APT_COMMAND}"
+ break
+ fi
+ # try to parse APT's output to recognize lines such as:
+ # libfoo-dev: Depends: bar (>= xyz) but www is to be installed
+ DEP_INSTALLPKG="$(echo "$APT_OUTPUT" | \
+ sed -n \
+ -e "s/^ *.*: *Depends: *\(.*\) but.*is to be installed\$/\\1/p" \
+ -e "s/^ *.*: *Depends: *\(.*\) but it is not going to be installed\$/\\1/p" \
+ -e "s/^ *.*: *Depends: *\(.*\)\$/\\1/p" | \
+ head -1 | \
+ tr " " "/")"
+ APT_ADD_COMMAND="$(versioneddep_to_aptcmd "$DEP_INSTALLPKG")"
+ if echo "$CURRENT_APT_COMMAND" | grep -q "$APT_ADD_COMMAND"; then
+ # loop detected, give up with real packages
+ echo " -> Loop detected, last APT error was: ======"
+ echo "$APT_OUTPUT"
+ echo " -> ========================================="
+ echo " -> (not adding $APT_ADD_COMMAND to $CURRENT_APT_COMMAND)"
+ break
+ fi
+ CURRENT_APT_COMMAND="$CURRENT_APT_COMMAND $APT_ADD_COMMAND"
+ done
+ if [ "$SATISFIED" = "yes" ]; then
+ break;
+ fi
+
+ echo " -> Cannot install ${CURRENT_APT_COMMAND}; apt errors follow:"
+ if $CHROOTEXEC /usr/bin/apt-get -s install ${INSTALLPKGLIST} "${CURRENT_APT_COMMAND}"; then
+ :
+ fi
+ # package could not be found. -- looking for alternative.
+ PROVIDED=""
+ checkbuilddep_provides "${CURRENTREALPKGNAME}"
+ if [ -n "$PROVIDED" ]; then
+ # something provides this package
+ echo " -> Considering $PROVIDED to satisfy the dependency "
+ if $CHROOTEXEC /usr/bin/apt-get -s install ${INSTALLPKGLIST} ${PROVIDED} >& /dev/null; then
+ SATISFIED="yes";
+ INSTALLPKGLIST="${INSTALLPKGLIST} ${PROVIDED}"
+ else
+ # show the error for diagnostic purposes
+ echo " -> Cannot install $PROVIDED; apt errors follow:"
+ if $CHROOTEXEC /usr/bin/apt-get -s install ${INSTALLPKGLIST} ${PROVIDED}; then
+ :
+ fi
+ fi
+ fi
+ if [ "$SATISFIED" = "yes" ]; then
+ break;
+ fi
+ done;
+ if [ "$SATISFIED" = "no" ]; then
+ echo "E: Could not satisfy build-dependency." >&2
+ if [ "$CONTINUE_FAIL" != "yes" ]; then
+ exit 2
+ fi
+ fi
+ done;
+
+ # now actually install the packages
+ echo " -> Installing ${INSTALLPKGLIST}"
+ if ! $CHROOTEXEC apt-get -y --force-yes install ${INSTALLPKGLIST}; then
+ echo " -> Trying to fix apt error"
+ # Work around an apt bug which causes configure to fail.
+ if $CHROOTEXEC dpkg --configure --pending && $CHROOTEXEC apt-get -y --force-yes install ${INSTALLPKGLIST}; then
+ echo " -> Apt bug workaround succeeded"
+ elif [ "$CONTINUE_FAIL" != "yes" ]; then
+ echo "E: Unrecoverable error installing build-dependencies." >&2
+ exit 1
+ fi
+ fi
+
+ # start processing build-conflicts.
+ for INSTALLPKG in $(cat "${DEBIAN_CONTROL}" | \
+ awk 'BEGIN{source=1}
+/^$/ {source=0}
+/^Source:/ {source=1}
+/^[^ ]*:/{p=0}
+tolower($0) ~ /^'"${BC_REGEXP}"':/ {p=1}
+{if(p && source) {print $0}}' | \
+ sed 's/^[^: ]*://' | \
+ tr " " "/" | \
+ awk 'BEGIN{RS=","} {print}'); do
+ CURRENTREALPKGNAME=$(echo "$INSTALLPKG" | sed -e 's/^[/]*//' -e 's/[[/(].*//')
+ echo " -> Considering ${CURRENTREALPKGNAME}"
+
+ if echo "$INSTALLPKG" | grep '\[' > /dev/null ; then
+ # this package has arch-conflicts.
+ if checkbuilddep_archdeps "$INSTALLPKG" "$ARCH"; then
+ echo "I: Ignoring other-arch"
+ continue;
+ fi
+ fi
+ if echo "$INSTALLPKG" | grep '[(]' > /dev/null ; then
+ # this package has version-conflicts
+ if ! checkbuilddep_versiondeps ${CURRENTREALPKGNAME} \
+ $(echo "$INSTALLPKG" | tr "/" " " | sed 's/^.*([ ]*\(<<\|<=\|>=\|=\|<\|>>\|>\)[ ]*\(.*\)).*$/\1/') \
+ $(echo "$INSTALLPKG" | tr "/" " " | sed 's/^.*([ ]*\(<<\|<=\|>=\|=\|<\|>>\|>\)[ ]*\(.*\)).*$/\2/'); then
+ echo "I: Satisfies version, not trying"
+ continue;
+ fi
+ fi
+
+ # if package exists, remove it.
+ if $CHROOTEXEC /usr/bin/dpkg -s $(echo "$INSTALLPKG" | tr "/" " " | awk '{print $1}') 2>&1 | grep ^Package: > /dev/null; then
+ if ! $CHROOTEXEC /usr/bin/apt-get -y remove ${CURRENTREALPKGNAME} ; then
+ echo "E: Could not satisfy build-conflicts" >&2
+ exit 1
+ fi
+ else
+ echo "I: ${CURRENTREALPKGNAME} package is not installed, no need to remove"
+ fi
+ done
+ echo " -> Finished parsing the build-deps"
+}
+
+
+function print_help () {
+ # print out help message
+ cat <<EOF
+pbuilder-satisfydepends -- satisfy dependencies
+Copyright 2002-2006 Junichi Uekawa <dancer@debian.org>
+
+--help: give help
+--control: specify control file (debian/control, *.dsc)
+--chroot: operate inside chroot
+--binary-all: include binary-all
+--binary-arch: include binary-arch only
+--echo: echo mode, do nothing. (--force-version required for most operation)
+--force-version: skip version check.
+--continue-fail: continue even when failed.
+
+EOF
+}
+
+
+DEBIAN_CONTROL=debian/control
+CHROOTEXEC=""
+BD_REGEXP="build-(depends|depends-indep)"
+BC_REGEXP="build-(conflicts|conflicts-indep)"
+FORCEVERSION=""
+CONTINUE_FAIL="no"
+
+
+while [ -n "$1" ]; do
+ case "$1" in
+ --control|-c)
+ DEBIAN_CONTROL="$2"
+ shift; shift
+ ;;
+ --chroot)
+ CHROOTEXEC="chroot $2 "
+ shift; shift
+ ;;
+ --internal-chrootexec)
+ CHROOTEXEC="$2"
+ shift; shift
+ ;;
+ --binary-all)
+ BD_REGEXP='build-(depends|depends-indep)'
+ BC_REGEXP='build-(conflicts|conflicts-indep)'
+ shift
+ ;;
+ --binary-arch)
+ BD_REGEXP='build-depends'
+ BC_REGEXP='build-conflicts'
+ shift
+ ;;
+ --echo)
+ CHROOTEXEC="echo $CHROOTEXEC"
+ shift
+ ;;
+ --continue-fail)
+ CONTINUE_FAIL="yes"
+ shift
+ ;;
+ --force-version)
+ FORCEVERSION="yes"
+ shift;
+ ;;
+ --help|-h|*)
+ print_help
+ exit 1
+ ;;
+ esac
+done
+
+
+checkbuilddep_internal