#!/bin/bash # # Copyright (C) 2007 Lauri Leukkunen # # Redesigned/refactored by Lauri T. Aarnio; # Portion Copyright (c) 2008 Nokia Corporation. # All rights reserved. # # Licensed under GPL version 2 # # ------------------- # # dpkg-checkbuilddeps wrapper for SB2. # # ENVIRONMENT VARIABLES: # - set SBOX_CHECKBUILDDEPS_VERBOSE to non-empty value to get # verbose description about what is missing. # - SBOX_DOUBLECHECK_DEPS; see the text below: # # Currently there are two algorithms for this: Old and new. # # The old one, implemented completely as a shell script, # ignores many things that should be checked. The new one is # is written in perl, but the implementation is still # incomplete. Currently things work so that this shell # script digs out the needed variables and feeds them to # the perl script (the old algorithm is off by default). # # Alternatively, the old and new algorithms can both be # enabled by setting environment variable SBOX_DOUBLECHECK_DEPS # to any non-empty value. I haven't seen any cases where the # old algorithm would be better that the new one, but I'm # interested to hear if there are any...before this old # stuff will be completely removed / Lauri T. Aarnio 2009-01-31. # # Here is description of the OLD algorithm: # Idea behind operation is to first check target's package db, # then check if missing packages are tools that could be used # from the host (or sbox_tools_root, if that has been set) # # There might also be dependencies that SB2 itself solves; # for example, gcc-* dependencies might be resolved by the # cross compiler. # # Requirements: # - Package db maps to *target* package db # - can switch temporarily to tools mode, and then the # db maps to *tools* package db # # [N.B. The new algorithm solves this: # FIXME: This implementation is still incomplete, as this does not # check package versions while checking host/tools_root tools. # Also, it would be a good idea to do a "visibility check" for host packages, # too (see how sb2-check-pkg-mappings does it for target's pkg db)] args="$*" prog="$0" progbase=`basename $0` SBOX_REDIRECT_IGNORE="" function error_not_inside_sb2() { echo "SB2: $progbase: This wrapper can only be used from inside" echo "the scratchbox 2'ed environment" exit 1 } function verbose_message() { if [ -n "$SBOX_CHECKBUILDDEPS_VERBOSE" ]; then echo "$*" 1>&2 fi } if [ -z "$SBOX_SESSION_DIR" ] then error_not_inside_sb2 fi . $SBOX_SESSION_DIR/sb2-session.conf # A generated, temporary package db which only contains packages that # are usable thru the current mapping mode: TARGET_DPKG_ADMINDIR_USABLE_PKGS=$sbox_temp_dpkg_admin_dir cfgfile_host_accepted_pkgs=$sbox_dir/share/scratchbox2/modeconf/host-accepted-packages.$sbox_mapmode cfgfile_host_ignored_pkgs=$sbox_dir/share/scratchbox2/modeconf/host-ignored-packages.$sbox_mapmode # Execute a command in tools mode. forces /usr/bin/perl to tools, # otherwise the shell which is running this script may try to take perl from # the rootstrap - some, but not all, of the dpkg* tools are perl scripts. # Return status is in $tools_mode_tool_stat when this returns. function run_in_tools_mode() { SBOX_REDIRECT_FORCE="/usr/bin/perl" SBOX_SESSION_MODE=tools \ eval "$*" tools_mode_tool_stat=$? } # Check if a named package exists of the host. # Returns result in three variables: # - $installed_to_host is either "yes" or "no" # - $check_result_msg and $check_result_msg2 return a more detailed # explanation of the result (strings). function check_host_pkg() { pkgname=$1 installed_to_host="no" # default check_result_msg="'$pkgname' not found." check_result_msg2="" # Check if it can be accepted from the host: g=`grep "^$pkgname\$" $cfgfile_host_accepted_pkgs` if [ -z "$g" ] then # No, the package has not been aproved to be used from the host. # first check if this requirement should be ignored completely: if [ -f $cfgfile_host_ignored_pkgs ] then # ignorelist exists g=`grep "^$pkgname\$" $cfgfile_host_ignored_pkgs` if [ -z "$g" ] then check_result_msg="'$pkgname' is missing (must be installed to the rootstrap)" else check_result_msg="'$pkgname' is missing, but this is ignored by configuration" installed_to_host="yes" return fi fi pkg_stat_tmp=`mktemp -p $SBOX_SESSION_DIR/tmp pkg-stat.XXXXXXXXXX` # next check again if the package exists on the target, # just to be able to give a better error message. if dpkg-query -s "$pkgname" >$pkg_stat_tmp 2>&1 then if grep -q "ok installed" $pkg_stat_tmp then rm $pkg_stat_tmp check_result_msg="'$pkgname': OOPS. Needed from the the rootstrap (installed there)," check_result_msg2=" but unusable (not fully visible due to SB2 mapping rules)" return fi fi rm $pkg_stat_tmp check_result_msg="'$pkgname' is missing, must be installed to the rootstrap" return fi # package is not present in the rootstrap, but # it can be accepted from the host environment. run_in_tools_mode dpkg-query -s "$pkgname" >/dev/null 2>&1 if [ $tools_mode_tool_stat == 0 ]; then installed_to_host="yes" check_result_msg="'$pkgname' found from the host environment" return fi # not installed. Test if this can be ignored. if [ -f $cfgfile_host_ignored_pkgs ] then g=`grep "^$pkgname\$" $cfgfile_host_ignored_pkgs` if [ -n "$g" ] then check_result_msg="'$pkgname' is not available (ignored by configuration)" installed_to_host="yes" return fi fi check_result_msg="'$pkgname' is missing (can be installed to the host)" return 1 } function check_gcc_dependency() { required_gcc=$1 prefix="$2" if [ -f $HOME/.scratchbox2/$sbox_target/sb2.config.d/gcc.config.sh ] then # a cross compiler has been configured if [ "$required_gcc" = "gcc" ] then # requires GCC, but does not depend on gcc version verbose_message "$prefix""SB2 provides gcc" return 0 fi # # Find out if gcc version is suitable, try all configured # toolchains for gcc_conf_file in \ $HOME/.scratchbox2/$sbox_target/sb2.config.d/gcc*.config.sh do if [ -f $gcc_conf_file ]; then . $gcc_conf_file short_vrs="gcc-$SBOX_CROSS_GCC_SHORTVERSION" full_vrs="gcc-$SBOX_CROSS_GCC_VERSION" if [ "$required_gcc" = "$short_vrs" -o \ "$required_gcc" = "$full_vrs" ]; then verbose_message "$prefix""SB2 provides $required_gcc" return 0 fi fi done fi # else a cross-compiler is not available, gcc comes from tools # Failed, SB2 environment does not provide a suitable gcc. return 1 } function check_sb2_builddeps() { orig_missing="$1" prefix="$2" new_missing="" ret=0 # Currently, SB2 can fulfill "gcc" and "gcc-" for m in $orig_missing do case $m in gcc*) check_gcc_dependency "$m" "$prefix" if [ $? != 0 ]; then # gcc check failed new_missing="$new_missing $m" fi ;; *) # keep it in the list of missing pkgs new_missing="$new_missing $m" ;; esac done missing_deps="$new_missing" if [ -z "$new_missing" ]; then # all resolved. true else # still missing something false fi } function check_host_builddeps() { missing="$1" prefix="$2" ret=0 # do the magic here verbose_message "$prefix""SB2 Checking host build deps.." list_ok=1 # default to ok # $m will be the package to test, or pkg/pkg[/...] if there are # alternatives (unfortunately '|' has special meaning in shell's # "case" statement, so we'll have to replace it by '/') for m in $(echo $missing | sed -e 's/([^)]\+)//g' | \ sed -e 's:[ ]*|[ ]*:/:g') do ## echo " Testing $m:" case "$m" in */*) # alternatives.. has_one_alternative=0 for mmm in $(echo $m | sed -e 's:/: :') do verbose_message "$prefix"" ...$mmm" check_host_pkg $mmm if [ "$installed_to_host" = "yes" ] then verbose_message "$prefix"" $mmm = ok" has_one_alternative=1 else verbose_message "$prefix"" no $mmm.." fi done if [ $has_one_alternative == 0 ] then verbose_message "$prefix"" Requirement $m failed; none of the alternatives were found." list_ok=0 else verbose_message "$prefix"" '$m': At least one alternative found, ok." fi ;; *) # No alternatives. check_host_pkg $m verbose_message "$prefix"" $check_result_msg" if [ -n "$check_result_msg2" ] then verbose_message "$prefix"" $check_result_msg2" fi if [ "$installed_to_host" = "no" ] then list_ok=0 fi esac done if [ $list_ok == 0 ]; then # somethings missing false else true fi } function check_host_builddeps_by_real_tool() { ret=0 verbose_message "SB2 Checking tools build deps..." x_missing_dep_file=`mktemp -p $SBOX_SESSION_DIR/tmp tools_missing_deps.XXXXXXXXXX` # Run dpkg-checkbuilddeps in the "tools" mode # Note: Can't use a pipeline here, we want to the # dpkg-checkbuilddeps' return status. run_in_tools_mode /usr/bin/dpkg-checkbuilddeps \ $args > $x_missing_dep_file 2>&1 if [ $tools_mode_tool_stat == 0 ]; then # real dpkg-checkbuilddeps says "all ok" rm $x_missing_dep_file tools_missing_deps="" return 0 fi # else real dpkg-checkbuilddeps failed. # sed -e 's/^/ /' < $x_missing_dep_file tools_missing_deps=$(egrep \ "^dpkg-checkbuilddeps: Unmet build dependencies:" \ $x_missing_dep_file | \ sed 's/dpkg-checkbuilddeps: Unmet build dependencies: //') rm $x_missing_dep_file if [ -n "$tools_missing_deps" ]; then # failing target deps, and missing packages are listed # in $tools_missing_deps = continue by checking if those are # available on the host environment return 1 else # failing target deps, but $tools_missing_deps is empty. Something # is fatally wrong. echo "dpkg-checkbuilddeps: FATAL: Failed to check dependencies from tools_root DB" exit 1 fi } function check_target_builddeps() { ret=0 verbose_message "SB2 Checking target build deps..." missing_dep_file=`mktemp -p $SBOX_SESSION_DIR/tmp missing_deps.XXXXXXXXXX` # dpkg-checkbuilddeps with another package db.. # a special rule in the tools mode is needed because the # version which is available in /usr/bin may not know about the # --admindir option. Can't use a pipeline here, we want to the # dpkg-checkbuilddeps' return status. SBOX_TOOLS_MODE_VAR_LIB_DPKG_STATUS_LOCATION=$TARGET_DPKG_ADMINDIR_USABLE_PKGS/status \ run_in_tools_mode /usr/bin/dpkg-checkbuilddeps \ $args > $missing_dep_file 2>&1 if [ $tools_mode_tool_stat == 0 ]; then # real dpkg-checkbuilddeps says "all ok" rm $missing_dep_file return 0 fi # else real dpkg-checkbuilddeps failed. if [ -n "$SBOX_CHECKBUILDDEPS_VERBOSE" ]; then sed -e 's/^/ /' < $missing_dep_file fi missing_deps=$(egrep \ "^dpkg-checkbuilddeps: Unmet build dependencies:" \ $missing_dep_file | \ sed 's/dpkg-checkbuilddeps: Unmet build dependencies: //') rm $missing_dep_file if [ -n "$missing_deps" ]; then # failing target deps, and missing packages are listed # in $missing_deps = continue by checking if those are # available on the host environment return 1 else # failing target deps, but $missing_deps is empty. Something # is fatally wrong. echo "dpkg-checkbuilddeps: FATAL: Failed to check dependencies from target_root DB" exit 1 fi } function compare_target_and_host_results_with_new_tool() { t_missing=$missing_deps h_missing=$tools_missing_deps both_required=`cat $TARGET_DPKG_ADMINDIR_USABLE_PKGS/both-required` host_accepted=`grep -v "#" $cfgfile_host_accepted_pkgs` host_ignored="" if [ -f $cfgfile_host_ignored_pkgs ] then # ignorelist exists host_ignored=`grep -v "#" $cfgfile_host_ignored_pkgs` fi verbose_message "SB2 Combining results from target and tools..." $sbox_dir/share/scratchbox2/lib/sb2-cmp-checkbuilddeps-output.pl \ "$t_missing" "$h_missing" "$both_required" "$host_accepted" "$host_ignored" result2=$? return $result2 #### if [ $? = 0 ]; then #### result2="ok" ####else #### result2="fail" ####fi } # First, make sure we are in a correct directory: if [ ! -f debian/control ] then echo "dpkg-checkbuilddeps: failure: cannot read debian/control: No such file or directory" 1>&2 exit 1 fi # Next, check that the list of usable packages exists and is up-to-date. # That list is really a temporary package database, which contains only # packages that are usable thru this mapping mode. sb2-check-pkg-mappings -u check_target_builddeps check_target_builddeps_result=$? missing_deps_after_target_check="$missing_deps" function old_deps_checker() { if [ $check_target_builddeps_result == 0 ]; then # nothing is missing = nothing needed from the host side verbose_message "OLD_CHK: Target rootstrap => all dependencies OK" return 0 fi verbose_message "OLD_CHK: Build dependencies missing from the target environment:" verbose_message "OLD_CHK: $missing_deps" # Something is missing. Check if SB2 can fulfill the requirements: check_sb2_builddeps "$missing_deps" "OLD_CHK: " if [ $? == 0 ]; then # OK now, nothing needed from the host side verbose_message "OLD_CHK: SB2 tools check => all dependencies OK" return 0 fi # Something is missing. To be able to get the missing packages from the # host environment, at least the list of allowed packages is needed: # if [ ! -f $cfgfile_host_accepted_pkgs ] then verbose_message "OLD_CHK:" verbose_message "OLD_CHK: Configuration file $cfgfile_host_accepted_pkgs" verbose_message "OLD_CHK: does not exist. This means that no packages have been approved to be used" verbose_message "OLD_CHK: from the host environment in this mapping mode ($sbox_mapmode)." return 1 fi check_host_builddeps "$missing_deps" "OLD_CHK: " if [ $? != 0 ]; then verbose_message "OLD_CHK: Failed. Host environment did not meet all requirements." return 1 fi # since we're here, everything is more or less ok verbose_message "OLD_CHK: All OK." return 0 } function new_deps_checker() { check_sb2_builddeps "$missing_deps" "" # $missing_deps has been updated check_host_builddeps_by_real_tool # $tools_missing_deps now contains a list of missing # packages, liste by the real dpkg-checkbuilddeps compare_target_and_host_results_with_new_tool new_deps_checker_result=$? } function deps_check_failed_exit_1() { verbose_message "Failed." if [ -z "$SBOX_CHECKBUILDDEPS_VERBOSE" ]; then echo "dpkg-checkbuilddeps: (Set env.var. SBOX_CHECKBUILDDEPS_VERBOSE='y' and run this command again to get more details)" 1>&2 fi exit 1 } if [ -n "$SBOX_DOUBLECHECK_DEPS" ]; then old_deps_checker old_deps_checker_result=$? fi missing_deps="$missing_deps_after_target_check" new_deps_checker if [ -n "$SBOX_DOUBLECHECK_DEPS" ]; then if [ "$new_deps_checker_result" != "$old_deps_checker_result" ]; then verbose_message "INCONSISTENT: new and old methods do not agree:" if [ "$new_deps_checker_result" = 0 ]; then verbose_message " : new => dependency checks OK" else verbose_message " : new => dependency checks FAILED" fi if [ "$old_deps_checker_result" = 0 ]; then verbose_message " : old => dependency checks OK" else verbose_message " : old => dependency checks FAILED" fi deps_check_failed_exit_1 fi fi if [ "$new_deps_checker_result" != "0" ]; then deps_check_failed_exit_1 fi # since we're here, everything is more or less ok echo "All OK." exit 0