aboutsummaryrefslogtreecommitdiff
path: root/lib/cpt-deps
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cpt-deps')
-rwxr-xr-xlib/cpt-deps177
1 files changed, 177 insertions, 0 deletions
diff --git a/lib/cpt-deps b/lib/cpt-deps
new file mode 100755
index 0000000..1429ae9
--- /dev/null
+++ b/lib/cpt-deps
@@ -0,0 +1,177 @@
+# Dependeny and ordering functions
+
+pkg_depends() {
+ # Resolve all dependencies and generate an ordered list.
+ # This does a depth-first search. The deepest dependencies are
+ # listed first and then the parents in reverse order.
+ contains "$deps" "$1" || {
+ # Filter out non-explicit, aleady installed dependencies.
+ # Only filter installed if called from 'pkg_build()'.
+ [ "$pkg_build" ] && [ -z "$2" ] &&
+ (pkg_list "$1" >/dev/null) && return
+
+ while read -r dep type || [ "$dep" ]; do
+ # Skip comments and empty lines.
+ [ "${dep##\#*}" ] || continue
+ # Skip test dependencies unless $CPT_TEST is set to 1.
+ #
+ # Skip make dependencies on the 'tree' operation for child packages
+ # or when the 'first-nomake' argument is given.
+ case $type in
+ test) [ "$CPT_TEST" = 1 ] || continue ;;
+ make) [ "$2" = tree ] && [ -z "${3#first-nomake}" ] && continue
+ esac
+
+ # Recurse through the dependencies of the child packages. Forward
+ # the 'tree' operation.
+ if [ "$2" = tree ]; then
+ pkg_depends "$dep" tree
+ else
+ pkg_depends "$dep"
+ fi
+ done 2>/dev/null < "$(pkg_find "$1")/depends" ||:
+
+ # After child dependencies are added to the list,
+ # add the package which depends on them.
+ [ "$2" = explicit ] || [ "$3" ] || deps="$deps $1 "
+ }
+}
+
+pkg_order() {
+ # Order a list of packages based on dependence and
+ # take into account pre-built tarballs if this is
+ # to be called from 'cpt i'.
+ order=; redro=; deps=
+
+ for pkg do case $pkg in
+ *.tar.*) deps="$deps $pkg " ;;
+ *) pkg_depends "$pkg" raw
+ esac done
+
+ # Filter the list, only keeping explicit packages.
+ # The purpose of these two loops is to order the
+ # argument list based on dependence.
+ for pkg in $deps; do ! contains "$*" "$pkg" || {
+ order="$order $pkg "
+ redro=" $pkg $redro"
+ } done
+
+ deps=
+}
+
+pkg_fix_deps() {
+ # Dynamically look for missing runtime dependencies by checking each binary
+ # and library with either 'ldd' or 'readelf'. This catches any extra
+ # libraries and or dependencies pulled in by the package's build suite.
+ log "$1" "Checking for missing dependencies"
+
+ # Go to the directory containing the built package to
+ # simplify path building.
+ cd "$pkg_dir/$1/$pkg_db/$1"
+
+ # Make a copy of the depends file if it exists to have a
+ # reference to 'diff' against.
+ if [ -f depends ]; then
+ cp -f depends "$mak_dir/d"
+ dep_file=$mak_dir/d
+ else
+ dep_file=/dev/null
+ fi
+
+ # Generate a list of all installed manifests.
+ pkg_name=$1
+ set +f; set -f -- "$sys_db/"*/manifest
+
+ # Get a list of binaries and libraries, false files
+ # will be found, however it's faster to get 'ldd' to check
+ # them anyway than to filter them out.
+ find "$pkg_dir/$pkg_name/" -type f 2>/dev/null |
+
+ while read -r file; do
+ case ${elf_prog:-ldd} in
+ *readelf) "$elf_prog" -d "$file" 2>/dev/null ;;
+ *) ldd "$file" 2>/dev/null ;;
+ esac |
+ while read -r dep; do
+ # Skip lines containing 'ldd'.
+ [ "${dep##*ldd*}" ] || continue
+ case $dep in *NEEDED*\[*\] | *'=>'*) ;; *) continue; esac
+
+ # readelf output:
+ # 0x0000 (NEEDED) Shared library: [libc.so]
+ dep=${dep##*\[}
+ dep=${dep%%\]*}
+
+ # ldd output:
+ # libc.so => /lib/ld-musl-x86_64.so.1
+ dep=${dep#* => }
+ dep=${dep% *}
+
+ # Figure out which package owns the file. Skip file if it is owned
+ # by the current package. This also handles cases where a '*-bin'
+ # package exists on the system, so the package manager doesn't think
+ # that the package we are building depends on the *-bin version of
+ # itself, or any other renamed versions of the same software.
+ pkg_owner -l "/${dep#/}\$" "$PWD/manifest" >/dev/null && continue
+ pkg_owner -l "/${dep#/}\$" "$@" ||:
+ done ||:
+ done >> depends
+
+ # Remove duplicate entries from the new depends file.
+ # This removes duplicate lines looking *only* at the
+ # first column.
+ sort -uk1,1 -o depends depends 2>/dev/null ||:
+
+ # Display a diff of the new dependencies against the old ones.
+ diff -U 3 "$dep_file" depends 2>/dev/null ||:
+
+ # Remove the depends file if it is empty.
+ [ -s depends ] || rm -f depends
+}
+
+pkg_get_base() (
+ # Print the packages defined in the /etc/cpt-base file.
+ # If an argument is given, it prints a space seperated list instead
+ # of a list seperated by newlines.
+
+ # cpt-base is an optional file, return with success if it doesn't exist.
+ [ -f "$CPT_ROOT/etc/cpt-base" ] || return 0
+ nonl=$1; set --
+
+ # Older versions of shellcheck warns us that the variable is changing on the
+ # subshell. That is our purpose here, thank you very much.
+ # shellcheck disable=SC2030
+ while read -r pkgname _; do
+ [ "${pkgname##\#*}" ] || continue
+ set -- "$@" "$pkgname"
+ done < "$CPT_ROOT/etc/cpt-base"
+ if [ "$nonl" ]; then printf '%s ' "$@"; else printf '%s\n' "$@"; fi
+)
+
+pkg_gentree() (
+ # Generate an ordered dependency tree of a package. Useful for testing
+ # whether the generated dependency tree is enough to actually building a
+ # given package. A second argument can be given as a combination of
+ # characters (similar to 'tar(1)' keys) which will be used as an option
+ # parser. See the documentation for more information on the keys.
+ # shellcheck disable=2030
+ deps='' reverse='' nonl='' make_deps=first
+ for op in $(sepchar "$2"); do
+ case "$op" in
+ b) deps="$(pkg_get_base nonl)" ;;
+ x) make_deps=first-nomake ;;
+ r) reverse=1 ;;
+ n) nonl=1 ;;
+ *) return 1
+ esac
+ done
+ pkg_depends "$1" tree "${make_deps:+first}"
+ eval set -- "$deps"
+ pkg_order "$@"
+ if [ "$reverse" ]; then eval set -- "$redro"; else eval set -- "$order"; fi
+ if [ "$nonl" ]; then printf '%s ' "$@"; else printf '%s\n' "$@"; fi
+)
+
+# Local Variables:
+# mode: sh
+# End: