Skip to content

Commit d87dfe8

Browse files
adrien-cottexdelaruelle
authored andcommitted
Accept abbreviated upper bounds in version ranges
Range matching already includes more precise versions of an abbreviated upper bound, but parsing rejects ranges whose lower bound extends that upper bound. Allow these ranges so callers can constrain a minimum version to the same major or minor version without inventing an upper limit. Fixes #698 Assisted-by: Codex:gpt-6-astra Signed-off-by: Adrien Cotte <adrien.cotte@asplus.fr>
1 parent 31741fc commit d87dfe8

6 files changed

Lines changed: 36 additions & 1 deletion

File tree

‎NEWS.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ Modules 5.7.0 (not yet released)
255255
shell meta-characters. Completion candidates were passed to ``compgen -W``
256256
which evaluates command substitution syntax. (fix `CVE-2026-85013`_ found
257257
by AISLE in partnership with Red Hat)
258+
* Accept abbreviated upper bounds in version ranges such as ``@3.20:3`` to
259+
select versions starting at ``3.20`` within major version ``3``.
258260

259261
.. _CVE-2026-85013: https://github.com/envmodules/modules/security/advisories/GHSA-8hrw-p88g-qhmg
260262

‎doc/source/design/advanced-module-version-specifiers.rst‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ Specification
9191

9292
- for instance *@1:1.10* will matches *1.0* and *1.8* but not *1.12*
9393

94+
- the upper bound may be less precise than the lower bound
95+
96+
- an abbreviated upper bound includes all versions that extend it,
97+
provided they also satisfy the lower bound
98+
- for instance *@1.2:1* matches *1.2* and *1.10* but not *1.1* or *2.0*
99+
- a reversed range remains invalid unless the lower bound extends the
100+
abbreviated upper bound, so *@2.0:1* is still rejected
101+
94102
- version could be specified as list
95103

96104
- soft@vers,vers,vers

‎doc/source/module.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3235,6 +3235,9 @@ the activation of the extended default mechanism (see
32353235
to refer to more precise version numbers like ``1.2.3``. Characters ``.`` and
32363236
``-`` are considered version number separator to determine abbreviated
32373237
versions. Range of versions on its side natively handles abbreviated versions.
3238+
The upper bound may be less precise than the lower bound. An abbreviated
3239+
upper bound includes all versions that extend it, provided they also satisfy
3240+
the lower bound.
32383241

32393242
In order to be specified in a range of versions or compared to a range of
32403243
versions, the version major element should corresponds to a number. For

‎doc/source/modulefile.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,9 @@ notation like ``@1`` to refer to more precise version numbers like ``1.2.3``.
21372137
Characters ``.`` and ``-`` are considered version number separator to
21382138
determine abbreviated versions. Range of versions on its side natively handles
21392139
abbreviated versions.
2140+
The upper bound may be less precise than the lower bound. An abbreviated
2141+
upper bound includes all versions that extend it, provided they also satisfy
2142+
the lower bound.
21402143

21412144
In order to be specified in a range of versions or compared to a range of
21422145
versions, the version major element should corresponds to a number. For

‎tcl/modspec.tcl‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,9 @@ proc parseModuleVersionSpecifier {modspec} {
12461246
set cmpspec le
12471247
set versspec $hivers
12481248
# between or equal
1249-
} elseif {[versioncmp $lovers $hivers] == 1} {
1249+
# An abbreviated upper bound includes its more precise versions.
1250+
} elseif {[versioncmp $lovers $hivers] == 1 && ![string match\
1251+
$hivers[extendedDefaultCharGlobMatch] $lovers]} {
12501252
set invalidversrange 1
12511253
} else {
12521254
set cmpspec be

‎testsuite/modules.70-maint/272-adv_version_spec-range.exp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ testouterr_cmd sh {load mod@1::} ERR "$err_specvers'1::'"
8484
testouterr_cmd sh {load mod@1,:,} ERR "$err_specvers'1,:,'"
8585
testouterr_cmd sh {load mod@,:} ERR "$err_specvers',:'"
8686
testouterr_cmd sh {load mod@1.3:1.2} ERR "$err_rangevers'1.3:1.2'"
87+
testouterr_cmd sh {load mod@4.1:3} ERR "$err_rangevers'4.1:3'"
88+
testouterr_cmd sh {load mod@1.30:1.3} ERR "$err_rangevers'1.30:1.3'"
8789
testouterr_cmd sh {load mod@,<} ERR "$err_specvers',<'"
8890
testouterr_cmd sh {load mod@:<} ERR "$err_rangevers':<'"
8991
testouterr_cmd sh {load mod@1/1:2} ERR "$err_specvers'1/1:2'"
@@ -113,6 +115,7 @@ testouterr_cmd sh {load extdfl @1.2:} $ans {}
113115
testouterr_cmd sh {load extdfl @:1.3.1} $ans {}
114116
testouterr_cmd sh {load extdfl @:1.3.7} $ans {}
115117
testouterr_cmd sh {load extdfl @1.2:1.3} $ans {}
118+
testouterr_cmd sh {load extdfl @1.2:1} $ans {}
116119
testouterr_cmd sh {load extdfl @1.2.3:1.3.7} $ans {}
117120
testouterr_cmd sh {load extdfl @:2.0.1} $ans {}
118121
testouterr_cmd sh {load extdfl @:2.0} $ans {}
@@ -162,6 +165,7 @@ testouterr_cmd sh {path extdfl/ @1.2:1.3} [list [list text $mp/extdfl/1.3.1]] {}
162165

163166
# test all sub-cmd concerned by context
164167
testouterr_cmd sh {avail -t extdfl @1.3:1.4} OK "$mp:\nextdfl/1.3.1(default)\nextdfl/1.3.7\nextdfl/1.4.5"
168+
testouterr_cmd sh {avail -t extdfl @1.3.7:1} OK "$mp:\nextdfl/1.3.7\nextdfl/1.4.5"
165169
testouterr_cmd_re sh {whatis extdfl@1.3.7:1.4.5} OK "$modlin $mpre $modlin
166170
\\s+extdfl/1.3.7: extdfl/1.3.7
167171
\\s+extdfl/1.4.5: extdfl/1.4.5"
@@ -187,6 +191,18 @@ testouterr_cmd sh {spider -t ext?fl @1.3:} OK "$mp:\nextdfl/1.3.1(default)\nextd
187191
testouterr_cmd sh {avail -t e??.* @:1.4} OK "$mp:\ne.t.fl/1.3.1\ne.t.fl/1.3.7\ne.t.fl/1.4.5"
188192

189193
# additional version tests
194+
# Abbreviated upper bounds apply independently of extended defaults.
195+
foreach extdfl {0 1} {
196+
setenv_var MODULES_EXTENDED_DEFAULT $extdfl
197+
set ans [list [list text $mp/extdfl/1.3.7] [list text $mp/extdfl/1.4.5]]
198+
testouterr_cmd sh {paths extdfl@1.3.7:1} $ans {}
199+
testouterr_cmd sh {paths -i EXTDFL@1.3.7:1} $ans {}
200+
set ans [list [list text $mp/extdfl/1.3.7]]
201+
testouterr_cmd sh {paths extdfl@1.3.7:1.3} $ans {}
202+
testouterr_cmd sh {paths extdfl@1.3.7:1.3,9:10} $ans {}
203+
}
204+
unsetenv_var MODULES_EXTENDED_DEFAULT
205+
190206
testouterr_cmd sh {avail -t extdfl8 @1.33:} OK "$mp:\nextdfl8/1.33"
191207
testouterr_cmd sh {avail -t extdfl8 @:1.3} OK "$mp:\nextdfl8/1.3.1\nextdfl8/1.3.7"
192208
testouterr_cmd sh {spider -t extdfl8 @:1.3} OK "$mp:\nextdfl8/1.3.1\nextdfl8/1.3.7"
@@ -297,6 +313,7 @@ set ans [list]
297313
lappend ans [list set _LMFILES_ $mp/extdfl2/3.1.7]
298314
lappend ans [list set LOADEDMODULES extdfl2/3.1.7]
299315
testouterr_cmd sh {load extdfl2@3.0.2:3.1.7} $ans {}
316+
testouterr_cmd sh {load extdfl2@3.1.7:3.1} $ans {}
300317
testouterr_cmd sh {load extdfl2@:3.1.7} $ans {}
301318
testouterr_cmd sh {load extdfl2@:3.1.7} $ans {}
302319
testouterr_cmd sh "load $mp/extdfl2 @:3.1.7" ERR "$err_file'$mp/extdfl2 @:3.1.7'"

0 commit comments

Comments
 (0)