Compare commits

..

9 Commits

Author SHA1 Message Date
Ben Roberts 9119c8c973 Merge branch 'prune_virtual_fixes' 2016-09-11 17:41:08 +01:00
Ben Roberts 632053fc2f Print the builder docker commandline to aid in debugging 2016-09-11 17:19:11 +01:00
Ben Roberts 6fc14f7605 Expose /vagrant from the buildbox into the docker container to aid in debugging 2016-09-11 17:18:49 +01:00
Ben Roberts 4268b06305 Fix virtual pruning by switching from state to global variable for package_deps cache 2016-09-11 17:18:20 +01:00
mudler a66dc7bb23 builder: added check for missing DEPEND/RDEPEND in QA phase 2016-09-10 15:00:09 +02:00
mudler 1c4389a8aa Makefile: cleanup 2016-09-10 14:49:24 +02:00
mudler c2a14afdf9 dynlink-scanner: add original author to the file 2016-09-10 14:42:30 +02:00
mudler 2e7c359b8c add dynlink scanner 2016-09-10 14:41:06 +02:00
mudler e86c134e61 add depcheck 2016-09-10 12:40:45 +02:00
6 changed files with 411 additions and 13 deletions
+4
View File
@@ -25,4 +25,8 @@ install:
install -m 0755 builder $(DESTDIR)/$(USBINDIR)/ install -m 0755 builder $(DESTDIR)/$(USBINDIR)/
install -d $(DESTDIR)/$(UBINDIR) install -d $(DESTDIR)/$(UBINDIR)
install -m 0755 depcheck $(DESTDIR)/$(UBINDIR)/
install -m 0755 dynlink-scanner $(DESTDIR)/$(UBINDIR)/
gcc try_dlopen.c -o try_dlopen -ldl
install -m 0755 try_dlopen $(DESTDIR)/$(UBINDIR)/
install -m 0755 sabayon-* $(DESTDIR)/$(UBINDIR)/ install -m 0755 sabayon-* $(DESTDIR)/$(UBINDIR)/
+29 -12
View File
@@ -37,7 +37,7 @@ my $equo_masks = $ENV{EQUO_MASKS};
my $equo_unmasks = $ENV{EQUO_UNMASKS}; my $equo_unmasks = $ENV{EQUO_UNMASKS};
my $equo_install_args = $ENV{EQUO_INSTALL_ARGS} // "--multifetch=10"; my $equo_install_args = $ENV{EQUO_INSTALL_ARGS} // "--multifetch=10";
my $remote_overlay = $ENV{REMOTE_OVERLAY}; my $remote_overlay = $ENV{REMOTE_OVERLAY};
my $repoman_check = $ENV{QA_CHECKS} // 0; my $qualityassurance_checks = $ENV{QA_CHECKS} // 0;
my $remote_conf_portdir = $ENV{REMOTE_CONF_PORTDIR}; my $remote_conf_portdir = $ENV{REMOTE_CONF_PORTDIR};
my $remote_portdir = $ENV{REMOTE_PORTDIR}; my $remote_portdir = $ENV{REMOTE_PORTDIR};
@@ -123,17 +123,17 @@ auto-sync = yes' > /etc/portage/repos.conf/$reponame.conf
} }
# Input: package, depth, and atom. Package: sys-fs/foobarfs, Depth: 1 (depth of the package tree) , Atom: 1/0 (enable disable atom output) # Input: package, depth, and atom. Package: sys-fs/foobarfs, Depth: 1 (depth of the package tree) , Atom: 1/0 (enable disable atom output)
my %package_dep_cache;
sub package_deps { sub package_deps {
my $package = shift; my $package = shift;
my $depth = shift // 1; # defaults to 1 level of depthness of the tree my $depth = shift // 1; # defaults to 1 level of depthness of the tree
my $atom = shift // 0; my $atom = shift // 0;
# Since we expect this sub to be called multiple times with the same arguments, cache the results # Since we expect this sub to be called multiple times with the same arguments, cache the results
state %cache;
$cache_key = "${package}:${depth}:${atom}"; $cache_key = "${package}:${depth}:${atom}";
if ( !exists $cache{$cache_key} ) { if ( !exists $package_dep_cache{$cache_key} ) {
@dependencies = my @dependencies =
qx/equery -C -q g --depth=$depth $package/; #depth=0 it's all qx/equery -C -q g --depth=$depth $package/; #depth=0 it's all
chomp @dependencies; chomp @dependencies;
@@ -148,10 +148,10 @@ sub package_deps {
@dependencies @dependencies
); );
$cache{$cache_key} = \@dependencies; $package_dep_cache{$cache_key} = \@dependencies;
} }
return @{ $cache{$cache_key} }; return @{ $package_dep_cache{$cache_key} };
} }
#Input: nothing #Input: nothing
@@ -178,18 +178,26 @@ sub calculate_missing {
my @dependencies = package_deps( $package, $depth, 1 ); my @dependencies = package_deps( $package, $depth, 1 );
if ($prune_virtuals) { if ($prune_virtuals) {
say "[$package] Pruning dependencies of virtual packages";
my %install_dependencies = map { $_ => 1 } @dependencies; my %install_dependencies = map { $_ => 1 } @dependencies;
# Look for any virtuals and remove its immediate dependencies to avoid # Look for any virtuals and remove its immediate dependencies to avoid
# installing multiple conflicting packages one by one # installing multiple conflicting packages one by one
my @virtual_deps; my @virtual_deps = ();
for my $dep (@dependencies) { for my $dep (@dependencies) {
push( @virtual_deps, package_deps( $dep, 1, 1 ) ) if ( $dep =~ /^virtual\// ) {
if ( $dep =~ /^virtual\// ); my @child_deps = package_deps($dep, 1, 1);
push( @virtual_deps, @child_deps );
}
} }
# Deduplicate the list
@virtual_deps = uniq(@virtual_deps);
# Prune the dependencies of the virtual packages from the dependencies list
for my $dep (@virtual_deps) { for my $dep (@virtual_deps) {
$install_dependencies{$dep} = 0 if ( $dep !~ /^virtual\// ); if ( $dep !~ /^virtual\// ) {
$install_dependencies{$dep} = 0;
}
} }
@dependencies = grep { $install_dependencies{$_} } @dependencies; @dependencies = grep { $install_dependencies{$_} } @dependencies;
} }
@@ -494,7 +502,7 @@ if ($use_equo) {
} }
} }
if ( $repoman_check == 1 ) { if ( $qualityassurance_checks == 1 ) {
say "*** Repoman checks ***"; say "*** Repoman checks ***";
for ( @packages, @injected_packages ) { for ( @packages, @injected_packages ) {
say "*** QA checks for $_"; say "*** QA checks for $_";
@@ -534,6 +542,15 @@ if ($preserved_rebuild) {
} }
if ( $qualityassurance_checks == 1 ) {
say "*** Missing dependencies checks ***";
for ( @packages ) {
say "*** DEPEND for $_";
system("dynlink-scanner $_");
system("depcheck $_");
}
}
# Copy files to artifacts folder # Copy files to artifacts folder
system( system(
"mkdir -p $artifacts_folder;cp -rfv /usr/portage/packages $artifacts_folder" "mkdir -p $artifacts_folder;cp -rfv /usr/portage/packages $artifacts_folder"
+303
View File
@@ -0,0 +1,303 @@
#!/bin/bash
# PODNAME: depcheck
#
# Copyright (c) 2014 Michael Palimaka <kensington@gentoo.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# A tool to report both undeclared and potentially-unused runtime dependencies.
#
# Depends on app-misc/pax-utils, app-portage/portage-utils and
# sys-apps/gentoo-functions.
DEBUG=FALSE
IGNORE_DEPS=( "sys-libs/glibc" "sys-devel/gcc" )
IGNORE_LINKS=( "/lib64/libgcc_s.so.1" )
PKG_DIR="/var/db/pkg/"
. /lib/gentoo/functions.sh
bold() {
echo $@
return
local bold=$(tput bold)
local normal=$(tput sgr0)
echo "${bold}${@}${normal}"
}
debug() {
if [ $DEBUG = TRUE ]; then
# write to stderr so as not to interfere with function returns
echo "$@" 1>&2
fi
}
# app-foo/bar-1.2.3-r1 -> app-foo/bar
remove_atom_version() {
local atom=`qatom "${1}" | cut -d " " -f 1-2 | tr " " /`
echo $atom
}
virtualcheck() {
debug Checking if ${libowner_pn} is provided by a virtual
for virtual in $(qdepends --nocolor --name-only --${1} --query ${libowner_pn} | grep ^virtual/)
do
debug Checking if ${virtual} is in dependencies
local isvirtualdep=$(qdepends --${1} ${atom} | grep ${virtual})
if [ $? -eq 0 ]; then
used_virtuals+=( ${virtual} )
continue 2
fi
done
if [ "${1}" = "depend" ]; then
eerror "${obj} links to ${link}"
fi
eindent
eerror Missing ${1^^} on $(bold ${libowner_pn})
eoutdent
errors=1
}
check_atom() {
local errors=0
local atom=$1
local checked=()
local rdepends=()
local used_virtuals=()
local objects=`qlist -qo ${atom}`
if [ ! "${objects}" ]; then
einfo ${atom} does not have any objects installed, skipping...
echo
return
fi
if [ -z "${INSIDE_PORTAGE}" ]; then
einfo Checking ${atom} for undeclared dependencies
eindent
fi
local obj
for obj in $objects
do
debug "Checking ${obj}"
readelf -h ${obj} > /dev/null 2>&1
# can it have stuff linked to it?
if [ $? -ne 0 ]; then
debug "It can't have links, skipping"
continue
fi
local elf=`scanelf --format "#f%n" --nobanner --use-ldpath ${obj} 2>&1`
local links=`echo ${elf} | tr "," " "`
# get a list of everything that it's linked to
local link
for link in $links
do
local ignore
for ignore in "${IGNORE_LINKS[@]}"; do
if [ "${ignore}" = "${link}" ]; then
debug "Ignoring ${link} due to blacklist"
continue 2
fi
done
# only check a library once per atom for performance reasons
local check
for check in "${checked[@]}"; do
if [ "${check}" = "${link}" ]; then
debug "Already checked ${link} for this atom, skipping"
continue 2
fi
done
checked=( "${checked[@]}" "${link}" )
debug "Found ${link}"
local libowner=`qfile -vqC ${link} | uniq`
if [ ! "${libowner}" ]; then
ewarn "Warning: installed file ${obj} is linked to ${link} which is not owned by any installed atom."
continue
fi
debug "Owning package for ${link} is ${libowner}"
local libowner_pn=$(remove_atom_version ${libowner})
local my_pn=$(remove_atom_version ${atom})
rdepends+=( "${libowner_pn}" )
if [ "${libowner_pn}" = "${my_pn}" ]; then
debug "Owning package is self, ignoring"
continue
fi
local ignorelib
for ignorelib in "${IGNORE_DEPS[@]}"
do
if [ "${libowner_pn}" = "${ignorelib}" ]; then
debug "Ignoring objects belonging to ${ignorelib}"
continue 2
fi
done
debug "Checking if ${libowner_pn} is in the [R]DEPEND list of ${atom}"
local isdep
isdep=`qdepends -d ${atom} | grep ${libowner_pn}`
if [ $? -ne 0 ]; then
virtualcheck depend
fi
local isrdep
isrdep=`qdepends -r ${atom} | grep ${libowner_pn}`
if [ $? -ne 0 ]; then
virtualcheck rdepend
fi
done
done
local ebuild_rdepends=()
for rdepend in $(qdepends --nocolor --quiet --rdepend ${atom} | sed -e "s/\[[^]]*\]//g" | cut -d : -f 2-)
do
if [[ ${rdepend} = !* ]] ; then
debug Skipping blocker: ${rdepend}
continue
elif [[ ${rdepend} = virtual/* ]] ; then
for virtual in "${used_virtuals[@]}"
do
if [[ ${virtual} == $(remove_atom_version ${rdepend}) ]]; then
debug Skipping virtual: ${rdepend}
continue 2
fi
done
fi
ebuild_rdepends+=( $(remove_atom_version $rdepend) )
done
debug "Ebuild RDEPENDS: ${ebuild_rdepends[@]}"
debug "Linked RDEPENDS: ${rdepends[@]}"
local suspect_rdepends=$(comm -13 <(echo ${rdepends[@]} | sed 's/ /\n/g' | sort -u) <(echo ${ebuild_rdepends[@]} | sed 's/ /\n/g' | sort -u))
if [ "${suspect_rdepends}" ]; then
ewarn "Suspect RDEPEND: $(bold ${suspect_rdepends})"
fi
if [ -z "${INSIDE_PORTAGE}" ]; then
eoutdent
if [ -n "${CAT}" ]; then
echo
fi
fi
return $errors
}
check_package() {
local package=$1
local atoms=`qlist -IcCS ${package} | tr ' ' '-' | cut -d : -f1`
debug Package ${package} own atoms: ${atoms}
if [ ! "${atoms}" ]; then
eerror ERROR: ${package} is not a valid atom
exit 1
fi
for atom in ${atoms}; do
check_atom ${atom}
done
}
check_category() {
local errors=0
for package in `ls "${PKG_DIR}/${1}"`; do
check_package "${1}/${package}"
if [ $? -ne 0 ]; then
errors=1
fi
done;
return $errors
}
BINNAME=`basename ${0}`
if [ -z $1 ]; then
echo "Checks emerged package(s) for undeclared depedencies"
echo
echo "Usage: ${BINNAME} [ atom | -c category | -a ]"
echo
echo "Examples:"
echo "Check a single package: ${BINNAME} app-foo/bar-1.2.3"
echo "Check a category: ${BINNAME} -c app-foo"
echo "Check everything: ${BINNAME} -a"
exit 1
fi
# check a particular category
if [ "$1" = "-c" ]; then
CAT=$2
if [ ! -d "${PKG_DIR}/${CAT}" ]; then
eerror ERROR: No packages from the category ${CAT} have been emerged yet
exit 1
fi
check_category $CAT
# check everything
elif [ "$1" = "-a" ]; then
for category in `ls ${PKG_DIR}`; do
check_category $category
done;
else
check_package $1
fi
if [ $DEBUG = TRUE ]; then
if [ $? -eq 0 ]; then
einfo Checking complete, no errors found
else
eerror Checking complete, errors found
fi
fi
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
# Maciej Mrozowski <reavertm@gentoo.org>
# Returns colon separated list of linking dependencies
get_link_deps()
{
KEY=
for dep in `scanelf --use-ldpath -yBF '%f %n' "$1"`; do
if [[ -z $KEY ]]; then
KEY="$dep"
continue
fi
echo $dep
done
}
# Print linking deps for given executable or shared object in alphabetical order.
# Also try to dlopen shared objects in order to detect missing/broken dependencies.
if [[ "$1" = --linking-deps ]]; then
# Sanity check, file-5.12 is broken, bail out early
if [[ `file --version | grep --color=never file- | cut -d'-' -f2` == '5.12' ]]; then
echo "file-5.12 is broken, bailing out"
exit 1
fi
mime=`file -b --mime-type "$2"`
if [[ "$mime" == 'application/x-executable' ]] || [[ "${mime}" == 'application/x-sharedlib' ]]; then
LINK=`get_link_deps "$2"`
[[ "$mime" == 'application/x-sharedlib' ]] && /usr/bin/try_dlopen "$2"
[[ -n $LINK ]] && echo -e ${LINK//,/\\n} | sort -u
exit 0
fi
exit 1
fi
[[ -z $* ]] && echo "usage: `basename $0` <package>" && exit 0
# Check whether package is installed
if ! portageq has_version $ROOT/ $1; then
echo "$1 is not installed"
exit 1
fi
# For each installed slot
for cpv in `portageq match $ROOT/ $1`; do
echo "Processing $cpv"
# For each file that belongs to package
# run dynlink-scanner --linking-deps <file> to obtain its linking dependencies
# Assign all linking deps to packages and print package names
qfile -eR $ROOT `portageq contents $ROOT/ $cpv | xargs -r -L 1 "$0" --linking-deps` | cut -f1 -d' ' | sort -u
done
+2 -1
View File
@@ -76,11 +76,12 @@ if [ -d "$SAB_WORKSPACE"/specs ]; then
[ -e "$SAB_WORKSPACE"/specs/custom.env ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/custom.env:/opt/sabayon-build/conf/$SAB_ARCH/portage/package.env") [ -e "$SAB_WORKSPACE"/specs/custom.env ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/custom.env:/opt/sabayon-build/conf/$SAB_ARCH/portage/package.env")
[ -e "$SAB_WORKSPACE"/specs/custom.keywords ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/custom.keywords:/opt/sabayon-build/conf/$SAB_ARCH/portage/package.keywords/99-custom.keywords") [ -e "$SAB_WORKSPACE"/specs/custom.keywords ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/custom.keywords:/opt/sabayon-build/conf/$SAB_ARCH/portage/package.keywords/99-custom.keywords")
[ -d "$SAB_WORKSPACE"/specs/env ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/env/:/opt/sabayon-build/conf/$SAB_ARCH/portage/env/") [ -d "$SAB_WORKSPACE"/specs/env ] && docker_volumes+=(-v "$SAB_WORKSPACE/specs/env/:/opt/sabayon-build/conf/$SAB_ARCH/portage/env/")
[ -d "/vagrant" ] && docker_volumes+=(-v "/vagrant:/vagrant")
fi fi
echo "Spawning the package builder container for '$@'." echo "Spawning the package builder container for '$@'."
echo "" echo ""
#echo "docker run $DOCKER_OPTS ${docker_env[@]} ${docker_volumes[@]} $DOCKER_IMAGE $@" echo "docker run $DOCKER_OPTS \"${docker_env[@]}\" \"${docker_volumes[@]}\" $DOCKER_IMAGE $@"
docker run $DOCKER_OPTS "${docker_env[@]}" "${docker_volumes[@]}" $DOCKER_IMAGE $@ docker run $DOCKER_OPTS "${docker_env[@]}" "${docker_volumes[@]}" $DOCKER_IMAGE $@
+23
View File
@@ -0,0 +1,23 @@
#include <stdio.h>
#include <dlfcn.h>
/**
* Attempts to load shared libraries
* @param argc
* @param argv files to check (pass only shared libs)
* @return 0 - all shared libs loaded, 1 - error occured (invalid or broken files passed)
*/
int main(int argc, char* argv[])
{
int i;
for (i = 1; i < argc; ++i) {
void* handle = dlopen(argv[i], RTLD_NOW);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
} else {
dlclose(handle);
}
}
return 0;
}