aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormerakor <cem@ckyln.com>2021-11-04 12:45:33 +0000
committermerakor <cem@ckyln.com>2021-11-04 12:45:33 +0000
commit9444ce1f01c9e1206e7beeddeb2bf7d263d11883 (patch)
treec11384156f6014aea7cd5f8ec2a7a147cd0c48f0
parentd3fdbdd8de5cc9deda840d612385773184dd7866 (diff)
parent731f0c9d775b2cbb6fa77d8bbe1c505b16fa6abf (diff)
downloadcpt-9444ce1f01c9e1206e7beeddeb2bf7d263d11883.tar.gz
merge branch 'tsort'
FossilOrigin-Name: 024e8148eae99f3ecfaef936f019cb82eb4cd240ae9202e5d95b8e52fde1222c
-rw-r--r--src/cpt-lib.in85
1 files changed, 67 insertions, 18 deletions
diff --git a/src/cpt-lib.in b/src/cpt-lib.in
index a881d0e..68a611b 100644
--- a/src/cpt-lib.in
+++ b/src/cpt-lib.in
@@ -76,6 +76,47 @@ colors_enabled() {
esac
}
+_dep_append() {
+ dep_graph=$(printf '%s\n%s %s\n' "$dep_graph" "$@" ;)
+}
+
+_tsort() {
+ # Return a linear reverse topological sort of the piped input, so we
+ # generate a proper build order. Returns 1 if a dependency cycle occurs.
+ #
+ # I was really excited when I saw POSIX specified a tsort(1) implementation,
+ # but the specification is quite vague, it doesn't specify cycles as a
+ # reason of error, and implementations differ on how it's handled. coreutils
+ # tsort(1) exits with an error, while openbsd tsort(1) doesn't. Both
+ # implementations are correct according to the specification. This leaves us
+ # with the following awk script, because the POSIX shell is not up for the
+ # job without super ugly hacks.
+ awk 'function fv(s) {
+ for (sp in e) {
+ split (e[sp],t)
+ for (j in t) if (s == t[j]) return 0
+ } return 1
+ }
+ function el(_l) {for(i in e){_l=_l" "i;}; return _l;}
+ function ce(t) {if (!(t in e)) e[t]="";}
+ function err(s) {print "Dependency cycle deteced between: " s; exit 1;}
+ {ce($1);$1!=$2&&e[$1]=e[$1]" "$2;}
+ END {
+ do {p=el()
+ for (s in e) {
+ if (fv(s)) {
+ pr=s" "pr
+ split(e[s],t)
+ for(i in t){ce(t[i]);}
+ delete e[s]
+ }
+ } c=el()
+ } while (p != c)
+ if (length(p)!=0) err(p);
+ print pr
+ }'
+}
+
trap_set() {
# Function to set the trap value.
case ${1:-cleanup} in
@@ -91,20 +132,16 @@ trap_set() {
esac
}
-sepchar() (
+sepchar() {
# Seperate every character on the given string without resorting to external
# processes.
[ "$1" ] || return 0; str=$1; set --
while [ "$str" ]; do
- str_tmp=$str
- for i in $(_seq $(( ${#str} - 1 ))); do
- str_tmp=${str_tmp%?}
- done
- set -- "$@" "$str_tmp"
- str=${str#$str_tmp}
+ set -- "$@" "${str%${str#?}}"
+ str=${str#?}
done
printf '%s\n' "$@"
-)
+}
_re() {
# Check that the string supplied in $2 conforms to the regular expression
@@ -851,12 +888,9 @@ 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
-
+ contains "$pkgs" "$1" || {
+ pkgs="$pkgs $1 "
+ [ "$2" = raw ] && _dep_append "$1" "$1"
while read -r dep type || [ "$dep" ]; do
# Skip comments and empty lines.
[ "${dep##\#*}" ] || continue
@@ -869,6 +903,16 @@ pkg_depends() {
make) [ "$2" = tree ] && [ -z "${3#first-nomake}" ] && continue
esac
+ # Filter out non-explicit, already installed dependencies if called
+ # from 'pkg_build()'.
+ [ "$pkg_build" ] && (pkg_list "$dep" >/dev/null) && continue
+
+ if [ "$2" = explicit ] || [ "$3" ]; then
+ _dep_append "$dep" "$dep"
+ else
+ _dep_append "$1" "$dep"
+ fi
+
# Recurse through the dependencies of the child packages. Forward
# the 'tree' operation.
if [ "$2" = tree ]; then
@@ -878,12 +922,14 @@ pkg_depends() {
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_depends_commit() {
+ # Set deps, and cleanup dep_graph, pkgs
+ deps=$(printf '%s\n' "$dep_graph" | _tsort) dep_graph='' pkgs='' || warn "Dependency cycle detected"
+}
+
pkg_order() {
# Order a list of packages based on dependence and
# take into account pre-built tarballs if this is
@@ -891,9 +937,10 @@ pkg_order() {
order=; redro=; deps=
for pkg do case $pkg in
- *.tar.*) deps="$deps $pkg " ;;
+ *.tar.*) _dep_append "$pkg" "$pkg" ;;
*) pkg_depends "$pkg" raw
esac done
+ pkg_depends_commit
# Filter the list, only keeping explicit packages.
# The purpose of these two loops is to order the
@@ -1093,6 +1140,7 @@ pkg_build() {
# separately from those detected as dependencies.
explicit="$explicit $pkg "
} done
+ pkg_depends_commit
[ "$pkg_update" ] || explicit_build=$explicit
@@ -2150,6 +2198,7 @@ _tmp_cp() {
_tmp_create() {
# Create given file to the temporary directory and return its name
+ create_tmp
_ret=$(_tmp_name "$1")
# False positive, we are not reading from the file.
# shellcheck disable=2094