pkgsrc-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[pkgsrc/trunk]: pkgsrc/mk/pkgformat/pkg reduce-depends.awk: Reduce "pkg>1" an...



details:   https://anonhg.NetBSD.org/pkgsrc/rev/a04d6c6f038a
branches:  trunk
changeset: 369562:a04d6c6f038a
user:      jlam <jlam%pkgsrc.org@localhost>
date:      Sun Oct 01 04:00:40 2017 +0000

description:
reduce-depends.awk: Reduce "pkg>1" and "pkg<2" into "pkg>1<2".

Enhance the reduce-depends.awk script to reduce a larger set of
dependencies into a single dependency.  The patterns representing
intervals of version numbers (can be open-ended) are of the form:

        pkg>lower
        pkg>=lower
        pkg<upper
        pkg<=upper
        pkg>lower<upper
        pkg>lower<=upper
        pkg>=lower<upper
        pkg>=lower<=upper

These patterns are now condensed into a single dependency of the
same form.  For example, given the following patterns:

        pkg>=1.0
        pkg>2.0
        pkg<3.0
        pkg<=4.0
        pkg>=2.5<3.5

the reduced pattern becomes:

        pkg>=2.5<3.0

Add the test script used to help with refactoring and adding the
new feature to the script.

This is a mostly complete rewrite of the script; change the
license to the standard 2-clause BSD license used by TNF.

diffstat:

 mk/pkgformat/pkg/reduce-depends.awk        |  240 ++++++++++++----
 mk/pkgformat/pkg/tests/Kyuafile            |    3 +-
 mk/pkgformat/pkg/tests/reduce-depends_test |  421 +++++++++++++++++++++++++++++
 3 files changed, 601 insertions(+), 63 deletions(-)

diffs (truncated from 758 to 300 lines):

diff -r 2b65d2addda0 -r a04d6c6f038a mk/pkgformat/pkg/reduce-depends.awk
--- a/mk/pkgformat/pkg/reduce-depends.awk       Sat Sep 30 21:52:17 2017 +0000
+++ b/mk/pkgformat/pkg/reduce-depends.awk       Sun Oct 01 04:00:40 2017 +0000
@@ -1,8 +1,8 @@
 #!/usr/bin/awk -f
 #
-# $NetBSD: reduce-depends.awk,v 1.4 2017/05/19 14:58:51 joerg Exp $
+# $NetBSD: reduce-depends.awk,v 1.5 2017/10/01 04:00:40 jlam Exp $
 #
-# Copyright (c) 2006 The NetBSD Foundation, Inc.
+# Copyright (c) 2006-2017 The NetBSD Foundation, Inc.
 # All rights reserved.
 #
 # This code is derived from software contributed to The NetBSD Foundation
@@ -16,13 +16,6 @@
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-#    must display the following acknowledgement:
-#        This product includes software developed by the NetBSD
-#        Foundation, Inc. and its contributors.
-# 4. Neither the name of The NetBSD Foundation nor the names of its
-#    contributors may be used to endorse or promote products derived
-#    from this software without specific prior written permission.
 #
 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -43,22 +36,99 @@
 #      reduce-depends.awk -- reduce a list of dependencies
 #
 # SYNOPSIS
-#      reduce-depends.awk "depends_list"
+#      reduce-depends.awk depends-list
 #
 # DESCRIPTION
 #      reduce-depends.awk removes some extraneous dependencies from the
 #      dependency list.  The dependency list should be passed as a single
 #      argument, and the output will be a list of the reduced dependencies,
-#      echo one on a new line.
+#      each dependency separated by a new line.
+#
+#      depends-list    A whitespace-separated list of dependencies.
+#                      This must be passed to the script as a single
+#                      argument.
 #
 # ENVIRONMENT
-#      CAT
+#      CAT     The name or path to the cat(1) utility.
+#
 #      PKG_ADMIN
+#              The name or path to the pkg_admin(1) utility.
+#
 #      PWD_CMD
-#      TEST
+#              The command to get the physical path to the current
+#              working directory.  The default is "pwd -P".
+#
+#      TEST    The name or path to the test(1) utility.
 #
 ######################################################################
 
+function shquote(s)
+{
+       # Escape single quotes (') by replacing them with '\''.
+       gsub(/'/, "'\\''", s)
+       # Surround with single quotes (').
+       return "'" s "'"
+}
+
+function version_cmp(v1, cmp, v2,      cmd, pattern, pkg)
+{
+       pkg = shquote("test-" v1)
+       test_pattern = shquote("test" cmp v2)
+       cmd = PKG_ADMIN " pmatch " test_pattern " " pkg
+       if (system(cmd) == 0) {
+               # v1 "cmp" v2
+               return 1
+       }
+       return 0
+}
+
+###
+# get_endpoint(cmp, patterns)
+#
+# Parameters:
+#      cmp (string)
+#              The relational operator ("<", "<=", ">", ">=").
+#
+#      patterns (array)
+#              The keys of the array form the set of dependency
+#              patterns that need to be reduced to a single pattern.
+#              The patterns all use the relational operator (cmp)
+#              and each expresses a ray of version strings.  The
+#              value associated with each key is the endpoint for
+#              that pattern.
+#
+# Return value:
+#      endpoint (string)
+#              The endpoint for the ray of version strings.
+#
+# Description:
+#      Returns a version string that is the endpoint of the ray of
+#      version strings formed from the intersection of the rays
+#      expressed by the patterns listed in the patterns array.
+#
+function get_endpoint(cmp, patterns,   endpoint, key, match_all, pattern, pkg)
+{
+       endpoint = ""                   # return value if patterns array is empty
+       for (key in patterns) {
+               endpoint = patterns[key]
+               pkg = shquote(gensub(cmp, "-", 1, key))
+               match_all = 1
+               for (pattern in patterns) {
+                       if (key == pattern) continue
+                       # Fix up the pattern to be closed if it is open.
+                       if (cmp == "<")         sub("<", "<=", pattern)
+                       else if (cmp == ">")    sub(">", ">=", pattern)
+                       cmd = PKG_ADMIN " pmatch " shquote(pattern) " " pkg
+                       if (system(cmd) != 0) {
+                               match_all = 0
+                               break
+                       }
+               }
+               if (match_all == 1) break
+       }
+       return endpoint
+}
+
 BEGIN {
        CAT = ENVIRON["CAT"] ? ENVIRON["CAT"] : "cat"
        PKG_ADMIN = ENVIRON["PKG_ADMIN"] ? ENVIRON["PKG_ADMIN"] : "pkg_admin"
@@ -68,8 +138,12 @@
        PROGNAME = "reduce-depends.awk"
        ERRCAT = CAT " 1>&2"
 
-       # Gather all dependencies into the depends array.  Index 0 of the
-       # depends[pkgpath] array is the number of patterns associated with
+       # Match version numbers with an ERE.
+       # XXX This matches more than it should.
+       VERSION_RE = "[0-9A-Za-z._+]+"
+
+       # Gather all dependencies into the patterns array.  Index 0 of the
+       # patterns[pkgpath] array is the number of patterns associated with
        # that pkgpath.
        #
        args = ARGV[1]
@@ -81,19 +155,19 @@
                        print "ERROR: [" PROGNAME "] invalid dependency pattern: " ARGV[i] | ERRCAT
                        exit 1
                }
-               if (pattern_seen[pattern] == 1)
-                       continue
+               if (pattern_seen[pattern] == 1) continue
                pattern_seen[pattern] = 1
-               cmd = TEST " -d " dir
+               cmd = TEST " -d " shquote(dir)
                if (system(cmd) == 0) {
-                       cmd = "cd " dir " && " PWD_CMD
+                       cmd = "cd " shquote(dir) " && " PWD_CMD
                        while ((cmd | getline pkgpath) > 0) {
                                if (!(pkgpath in pkgsrcdirs)) {
+                                       # Record package paths in the order they are seen.
                                        pkgpaths[P++] = pkgpath
                                        pkgsrcdirs[pkgpath] = dir
                                }
-                               depends[pkgpath, 0]++;
-                               depends[pkgpath, depends[pkgpath, 0]] = pattern
+                               D = ++patterns[pkgpath, 0]
+                               patterns[pkgpath, D] = pattern
                        }
                        close(cmd)
                } else {
@@ -102,61 +176,103 @@
                }
        }
 
-       # Reduce dependencies to the strictest set of dependencies it
-       # can derive from all of depends[...].  It only understands
-       # dependencies of the form foo>=1.0, and leaves the other
-       # dependencies undisturbed.
-       #
-       # The algorithm takes dependencies of the form foo>=1.0 and
-       # converts them to foo-1.0.  It then compares this pkg name against
-       # each dependency to see if it satisfies them all.  The key fact
-       # is the the strictest dependency, when converted to a pkg name,
-       # will satisfy every dependency.
-       #
+       # Reduce dependency patterns by package path.
        for (p = 0; p < P; p++) {
                pkgpath = pkgpaths[p]
-               D = depends[pkgpath, 0];
-               match_all = 1;
+               dir = pkgsrcdirs[pkgpath]
+               D = patterns[pkgpath, 0]
                for (d = 1; d <= D; d++) {
-                       dep = depends[pkgpath, d]
-                       if (dep ~ /[{]/ || \
-                           dep ~ />=[0-9][0-9\.]*(nb[0-9]+)?<[0-9]+/ || \
-                           dep !~ />=[0-9]+/)
-                       {
-                               reduced[N++] = dep ":" pkgsrcdirs[pkgpath]
-                               continue
+                       # Repeatedly strip off possible boundary conditions to
+                       # arrive at the PKGBASE.
+                       pattern = patterns[pkgpath, d]
+                       lt_bound = ""; le_bound = ""; ge_bound = ""; gt_bound = ""
+                       if (match(pattern, "<" VERSION_RE "$")) {
+                               lt_bound = substr(pattern, RSTART + 1, RLENGTH)
+                               pattern = substr(pattern, 1, RSTART - 1)
+                       }
+                       if (match(pattern, "<=" VERSION_RE "$")) {
+                               le_bound = substr(pattern, RSTART + 2, RLENGTH)
+                               pattern = substr(pattern, 1, RSTART - 1)
+                       }
+                       if (match(pattern, ">" VERSION_RE "$")) {
+                               gt_bound = substr(pattern, RSTART + 1, RLENGTH)
+                               pattern = substr(pattern, 1, RSTART - 1)
                        }
-                       ge_depends[dep] = dep
+                       if (match(pattern, ">=" VERSION_RE "$")) {
+                               ge_bound = substr(pattern, RSTART + 2, RLENGTH)
+                               pattern = substr(pattern, 1, RSTART - 1)
+                       }
+                       base = pattern
+                       if (lt_bound) lt_patterns[base "<"  lt_bound] = lt_bound
+                       if (le_bound) le_patterns[base "<=" le_bound] = le_bound
+                       if (gt_bound) gt_patterns[base ">"  gt_bound] = gt_bound
+                       if (ge_bound) ge_patterns[base ">=" ge_bound] = ge_bound
+                       if (!(lt_bound || le_bound || gt_bound || ge_bound)) {
+                               depend = pattern ":" dir
+                               if (!(depend in reduced)) reduced[depend] = ++N
+                       } else {
+                               pkgbase[pkgpath] = base
+                       }
                }
-               for (dep in ge_depends) {
-                       dep2pkg = dep; sub(">=", "-", dep2pkg)
-                       match_all = 1
-                       for (pattern in ge_depends) {
-                               cmd = PKG_ADMIN " pmatch \"" pattern "\" " dep2pkg
-                               if (system(cmd) != 0) {
-                                       match_all = 0
-                                       break
-                               }
+               lt_bound = get_endpoint("<",  lt_patterns)
+               le_bound = get_endpoint("<=", le_patterns)
+               gt_bound = get_endpoint(">",  gt_patterns)
+               ge_bound = get_endpoint(">=", ge_patterns)
+
+               # Lower bound and relational operator.
+               lower_bound = ""; gt = ""
+               if (gt_bound && ge_bound) {
+                       if (version_cmp(gt_bound, ">=", ge_bound)) {
+                               lower_bound = gt_bound; gt = ">"
+                       } else {
+                               lower_bound = ge_bound; gt = ">="
                        }
-                       if (match_all == 0) continue
-                       reduced[N++] = dep ":" pkgsrcdirs[pkgpath]
-                       break
+               } else if (gt_bound) {
+                       lower_bound = gt_bound; gt = ">"
+               } else if (ge_bound) {
+                       lower_bound = ge_bound; gt = ">="
                }
-               #
+
+               # Upper bound and relational operator.
+               upper_bound = ""; lt = ""
+               if (lt_bound && le_bound) {
+                       if (version_cmp(lt_bound, "<=", le_bound)) {
+                               upper_bound = lt_bound; lt = "<"
+                       } else {
+                               upper_bound = le_bound; lt = "<="
+                       }
+               } else if (lt_bound) {
+                       upper_bound = lt_bound; lt = "<"
+               } else if (le_bound) {
+                       upper_bound = le_bound; lt = "<="
+               }
+
                # If there are conflicting dependencies, then just pass them
                # through and let the rest of the pkgsrc machinery handle it.
                #
-               if (match_all == 0) {
+               # Othewise, build a new dependency based on the intersection
+               # of the rays determined by the various bounds.
+               #
+               if (lower_bound && upper_bound &&
+                   ((gt == ">" && version_cmp(lower_bound, ">=", upper_bound)) ||
+                    (gt == ">=" && version_cmp(lower_bound, ">", upper_bound)))) {
                        for (d = 1; d <= D; d++) {
-                               dep = depends[pkgpath, d]
-                               reduced[N++] = dep ":" pkgsrcdirs[pkgpath]
+                               depend = patterns[pkgpath, d] ":" dir
+                               if (!(depend in reduced)) reduced[depend] = ++N
                        }
+               } else if (lower_bound || upper_bound) {
+                       pattern = pkgbase[pkgpath] gt lower_bound lt upper_bound



Home | Main Index | Thread Index | Old Index