From f677ca69e0a929133c8c389111a81df513c0b12e Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Tue, 26 Sep 2017 12:06:46 -0400 Subject: [PATCH 1/3] 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 pkglowerlower<=upper pkg>=lower=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. --- mk/pkgformat/pkg/reduce-depends.awk | 251 +++++++++---- mk/pkgformat/pkg/tests/Kyuafile | 1 + mk/pkgformat/pkg/tests/reduce-depends_test | 395 +++++++++++++++++++++ 3 files changed, 582 insertions(+), 65 deletions(-) create mode 100755 mk/pkgformat/pkg/tests/reduce-depends_test diff --git a/mk/pkgformat/pkg/reduce-depends.awk b/mk/pkgformat/pkg/reduce-depends.awk index add1e9d0c56a..eb85dcf9d86d 100755 --- a/mk/pkgformat/pkg/reduce-depends.awk +++ b/mk/pkgformat/pkg/reduce-depends.awk @@ -2,7 +2,7 @@ # # $NetBSD: reduce-depends.awk,v 1.4 2017/05/19 14:58:51 joerg 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,103 @@ # 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 +} + +function add_reduced(reduced, pattern, dir, depend) +{ + depend = pattern ":" dir + if (!(depend in reduced)) reduced[depend] = depend +} + +### +# 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. +# +# 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 +142,12 @@ BEGIN { 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 +159,17 @@ BEGIN { 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)) { - 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 +178,106 @@ BEGIN { } } - # 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. - # - for (p = 0; p < P; p++) { - pkgpath = pkgpaths[p] - D = depends[pkgpath, 0]; - match_all = 1; + for (pkgpath in pkgsrcdirs) { + 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 + 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) + } + 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)) { + add_reduced(reduced, pattern, dir) + } else { + pkgbase[pkgpath] = base } - ge_depends[dep] = dep } - 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] + add_reduced(reduced, patterns[pkgpath, d], dir) } + } else if (lower_bound || upper_bound) { + pattern = pkgbase[pkgpath] gt lower_bound lt upper_bound + add_reduced(reduced, pattern, dir) } - for (dep in ge_depends) - delete ge_depends[dep] + + delete lt_patterns + delete le_patterns + delete gt_patterns + delete ge_patterns } - # Output reduced dependencies. - for (n = 0; n < N; n++) - print reduced[n]; + # Output reduced dependencies in sorted order. + N = 1 + for(pattern in reduced) output[N++] = pattern + for(i = 1; i < N; i++) { + pattern = output[i] + j = i - 1 + while((j > 0) && (output[j] > pattern)) { + output[j+1] = output[j] + j-- + } + output[j+1] = pattern + } + for (i = 1; i < N; i++) print(output[i]) } diff --git a/mk/pkgformat/pkg/tests/Kyuafile b/mk/pkgformat/pkg/tests/Kyuafile index 14a0caf28e97..cba480a2305f 100644 --- a/mk/pkgformat/pkg/tests/Kyuafile +++ b/mk/pkgformat/pkg/tests/Kyuafile @@ -46,4 +46,5 @@ syntax( 2 ) test_suite( "pkgsrc_pkgformat_pkg" ) +atf_test_program { name = "reduce-depends_test" } atf_test_program { name = "scripts_test" } diff --git a/mk/pkgformat/pkg/tests/reduce-depends_test b/mk/pkgformat/pkg/tests/reduce-depends_test new file mode 100755 index 000000000000..f3ad1ad9fc1c --- /dev/null +++ b/mk/pkgformat/pkg/tests/reduce-depends_test @@ -0,0 +1,395 @@ +#!/usr/bin/env atf-sh +# +# Copyright (c) 2017 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Johnny C. Lam. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# ENVIRONMENT +# The following variables are used if they are set: +# +# AWK +# The name or path to the awk(1) utility. +# +# PKGSRCDIR +# The location of the pkgsrc source tree. The default is +# "/usr/pkgsrc". + +write_contents() +{ + local file="$1"; shift + echo ">>> $file" + cat "$file" + echo "<<< $file" +} + +check_reduce() +{ + : ${AWK:=awk} + : ${PKGSRCDIR:=/usr/pkgsrc} + + local input="$1"; shift + local expected="$1"; shift + + case $input in + /*) ;; + *) input="${HOME}/$input" ;; + esac + + ( cd ${PKGSRCDIR}/pkgtools/pkg_install && + ${AWK} -f ${PKGSRCDIR}/mk/pkgformat/pkg/reduce-depends.awk \ + "$(cat $input)" + ) > value + + if cmp expected value; then + : "success" + else + write_contents expected + write_contents value + atf_fail "output does not match expected" + fi +} + + +### +### skip_irreducible_depends_test +### + +atf_test_case skip_irreducible_depends_test + +skip_irreducible_depends_test_head() +{ + atf_set "descr" "skip irreducible dependencies" +} + +skip_irreducible_depends_test_body() +{ + cat > input << EOF +cwrappers-1{,nb1}:../../pkgtools/cwrappers +pkg_install-{0nb3,1nb2}:../../pkgtools/pkg_install +pkg_install<=1:../../pkgtools/pkg_install +EOF + cat > expected << EOF +cwrappers-1{,nb1}:../../pkgtools/cwrappers +pkg_install-{0nb3,1nb2}:../../pkgtools/pkg_install +pkg_install<=1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### less_or_equal_depends_test +### + +atf_test_case less_or_equal_depends_test + +less_or_equal_depends_test_head() +{ + atf_set "descr" "reduce only <=" +} + +less_or_equal_depends_test_body() +{ + cat > input << EOF +pkg_install<=1:../../pkgtools/pkg_install +pkg_install<=2:../../pkgtools/pkg_install +pkg_install<=3:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install<=1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### less_depends_test +### + +atf_test_case less_depends_test + +less_depends_test_head() +{ + atf_set "descr" "reduce only <" +} + +less_depends_test_body() +{ + cat > input << EOF +pkg_install<1:../../pkgtools/pkg_install +pkg_install<2:../../pkgtools/pkg_install +pkg_install<3:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install<1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### greater_or_equal_depends_test +### + +atf_test_case greater_or_equal_depends_test + +greater_or_equal_depends_test_head() +{ + atf_set "descr" "reduce only >=" +} + +greater_or_equal_depends_test_body() +{ + cat > input << EOF +pkg_install>=1:../../pkgtools/pkg_install +pkg_install>=2:../../pkgtools/pkg_install +pkg_install>=3:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>=3:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### greater_depends_test +### + +atf_test_case greater_depends_test + +greater_depends_test_head() +{ + atf_set "descr" "reduce only >" +} + +greater_depends_test_body() +{ + cat > input << EOF +pkg_install>1:../../pkgtools/pkg_install +pkg_install>2:../../pkgtools/pkg_install +pkg_install>3:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>3:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### less_and_less_equal_same_bound_test +### + +atf_test_case less_and_less_equal_same_bound_test + +less_and_less_equal_same_bound_test_head() +{ + atf_set "descr" "reduce < and <=, same bound" +} + +less_and_less_equal_same_bound_test_body() +{ + cat > input << EOF +pkg_install<1:../../pkgtools/pkg_install +pkg_install<=1:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install<1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### greater_and_greater_equal_same_bound_test +### + +atf_test_case greater_and_greater_equal_same_bound_test + +greater_and_greater_equal_same_bound_test_head() +{ + atf_set "descr" "reduce > and >=, same bound" +} + +greater_and_greater_equal_same_bound_test_body() +{ + cat > input << EOF +pkg_install>1:../../pkgtools/pkg_install +pkg_install>=1:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### lower_and_upper_bounds_test +### + +atf_test_case lower_and_upper_bounds_test + +lower_and_upper_bounds_test_head() +{ + atf_set "descr" "reduce >, >=, <, and <= into one interval" +} + +lower_and_upper_bounds_test_body() +{ + cat > input << EOF +pkg_install>1:../../pkgtools/pkg_install +pkg_install>=1:../../pkgtools/pkg_install +pkg_install<2:../../pkgtools/pkg_install +pkg_install<=2:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>1<2:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### overlapping_intervals_test +### + +atf_test_case overlapping_intervals_test + +overlapping_intervals_test_head() +{ + atf_set "descr" "reduce overlapping intervals" +} + +overlapping_intervals_test_body() +{ + cat > input << EOF +pkg_install>1<3:../../pkgtools/pkg_install +pkg_install>2<4:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>2<3:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### disjoint_test +### + +atf_test_case disjoint_test + +disjoint_test_head() +{ + atf_set "descr" "can't reduce disjoint intervals" +} + +disjoint_test_body() +{ + cat > input << EOF +pkg_install<1:../../pkgtools/pkg_install +pkg_install>1:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install<1:../../pkgtools/pkg_install +pkg_install>1:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### strings_in_versions_test +### + +atf_test_case strings_in_versions_test + +strings_in_versions_test_head() +{ + atf_set "descr" "strings as separators in versions strings" +} + +strings_in_versions_test_body() +{ + cat > input << EOF +pkg_install>=1.0<2.0:../../pkgtools/pkg_install +pkg_install>1.1beta3nb2:../../pkgtools/pkg_install +pkg_install<1.2:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>1.1beta3nb2<1.2:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +### +### multiple_package_dependencies_test +### + +atf_test_case multiple_package_dependencies_test + +multiple_package_dependencies_test_head() +{ + atf_set "descr" "multiple package dependencies" +} + +multiple_package_dependencies_test_body() +{ + cat > input << EOF +cwrappers>1:../../pkgtools/cwrappers +cwrappers>=1:../../pkgtools/cwrappers +cwrappers<2:../../pkgtools/cwrappers +cwrappers<=2:../../pkgtools/cwrappers +pkg_install>=1.0<2.0:../../pkgtools/pkg_install +pkg_install>1.1beta3nb2:../../pkgtools/pkg_install +pkg_install<1.2:../../pkgtools/pkg_install +EOF + cat > expected << EOF +cwrappers>1<2:../../pkgtools/cwrappers +pkg_install>1.1beta3nb2<1.2:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + +atf_init_test_cases() +{ + atf_add_test_case skip_irreducible_depends_test + atf_add_test_case less_or_equal_depends_test + atf_add_test_case less_depends_test + atf_add_test_case greater_or_equal_depends_test + atf_add_test_case greater_depends_test + atf_add_test_case less_and_less_equal_same_bound_test + atf_add_test_case greater_and_greater_equal_same_bound_test + atf_add_test_case lower_and_upper_bounds_test + atf_add_test_case overlapping_intervals_test + atf_add_test_case disjoint_test + atf_add_test_case strings_in_versions_test + atf_add_test_case multiple_package_dependencies_test +} From 40a221902bb821a6761a6f052e1e7b59eb390669 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Sat, 30 Sep 2017 02:26:03 -0400 Subject: [PATCH 2/3] reduce-depends.awk: Preserve order of dependencies. Restore feature from the old script by preserving the order of the dependencies with respect to their package directories. This is important because the buildlink framework causes dependency lists emitted to have the property where each package of the list only depends on packages listed before it. --- mk/pkgformat/pkg/reduce-depends.awk | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/mk/pkgformat/pkg/reduce-depends.awk b/mk/pkgformat/pkg/reduce-depends.awk index eb85dcf9d86d..92555dcfefc1 100755 --- a/mk/pkgformat/pkg/reduce-depends.awk +++ b/mk/pkgformat/pkg/reduce-depends.awk @@ -166,6 +166,7 @@ BEGIN { cmd = "cd " shquote(dir) " && " PWD_CMD while ((cmd | getline pkgpath) > 0) { if (!(pkgpath in pkgsrcdirs)) { + pkgpaths[P++] = pkgpath pkgsrcdirs[pkgpath] = dir } D = ++patterns[pkgpath, 0] @@ -178,7 +179,8 @@ BEGIN { } } - for (pkgpath in pkgsrcdirs) { + for (p = 0; p < P; p++) { + pkgpath = pkgpaths[p] dir = pkgsrcdirs[pkgpath] D = patterns[pkgpath, 0] for (d = 1; d <= D; d++) { @@ -206,7 +208,8 @@ BEGIN { 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)) { - add_reduced(reduced, pattern, dir) + depend = pattern ":" dir + if (!(depend in reduced)) reduced[depend] = ++N } else { pkgbase[pkgpath] = base } @@ -254,11 +257,13 @@ BEGIN { ((gt == ">" && version_cmp(lower_bound, ">=", upper_bound)) || (gt == ">=" && version_cmp(lower_bound, ">", upper_bound)))) { for (d = 1; d <= D; d++) { - add_reduced(reduced, patterns[pkgpath, d], dir) + 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 - add_reduced(reduced, pattern, dir) + depend = pattern ":" dir + if (!(depend in reduced)) reduced[depend] = ++N } delete lt_patterns @@ -267,17 +272,7 @@ BEGIN { delete ge_patterns } - # Output reduced dependencies in sorted order. - N = 1 - for(pattern in reduced) output[N++] = pattern - for(i = 1; i < N; i++) { - pattern = output[i] - j = i - 1 - while((j > 0) && (output[j] > pattern)) { - output[j+1] = output[j] - j-- - } - output[j+1] = pattern - } - for (i = 1; i < N; i++) print(output[i]) + # Output reduced dependencies. + for (depend in reduced) output[reduced[depend]] = depend + for (i = 1; i <= N; i++) print(output[i]) } From 5f972781a0e673775c293df44101da3e17aad7f2 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Sat, 30 Sep 2017 10:13:59 -0400 Subject: [PATCH 3/3] reduce-depends.awk: Fix the ERE used to match version strings. The pkg_info(1) manpage says that underscore (_) is valid and is equivalent to a period (.) in a version string. --- mk/pkgformat/pkg/reduce-depends.awk | 2 +- mk/pkgformat/pkg/tests/reduce-depends_test | 25 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/mk/pkgformat/pkg/reduce-depends.awk b/mk/pkgformat/pkg/reduce-depends.awk index 92555dcfefc1..8796ae18731e 100755 --- a/mk/pkgformat/pkg/reduce-depends.awk +++ b/mk/pkgformat/pkg/reduce-depends.awk @@ -144,7 +144,7 @@ BEGIN { # Match version numbers with an ERE. # XXX This matches more than it should. - VERSION_RE = "[0-9A-Za-z.+]+" + 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 diff --git a/mk/pkgformat/pkg/tests/reduce-depends_test b/mk/pkgformat/pkg/tests/reduce-depends_test index f3ad1ad9fc1c..e9d2bbcbdcfd 100755 --- a/mk/pkgformat/pkg/tests/reduce-depends_test +++ b/mk/pkgformat/pkg/tests/reduce-depends_test @@ -348,6 +348,30 @@ EOF atf_pass } +### +### underscores_in_versions_test +### + +atf_test_case underscores_in_versions_test + +underscores_in_versions_test_head() +{ + atf_set "descr" "underscores in versions strings" +} + +underscores_in_versions_test_body() +{ + cat > input << EOF +pkg_install>=1.0_beta3:../../pkgtools/pkg_install +pkg_install<1.2:../../pkgtools/pkg_install +EOF + cat > expected << EOF +pkg_install>=1.0_beta3<1.2:../../pkgtools/pkg_install +EOF + check_reduce input expected + atf_pass +} + ### ### multiple_package_dependencies_test ### @@ -391,5 +415,6 @@ atf_init_test_cases() atf_add_test_case overlapping_intervals_test atf_add_test_case disjoint_test atf_add_test_case strings_in_versions_test + atf_add_test_case underscores_in_versions_test atf_add_test_case multiple_package_dependencies_test }