diff --git a/NEWS.rst b/NEWS.rst index 22e706df8..064796da6 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -108,6 +108,9 @@ Modules 5.7.0 (not yet released) test suite run is aborted. * Correctly match loaded modules specified as requirement with a trailing ``/`` character after module name. (fix issue #640) +* Also consider ``-`` in addition to ``.`` as a version number separator + character when selecting a module with the :mconfig:`extended_default` + mechanism. (fix issue #619) .. _5.6 release notes: diff --git a/doc/source/changes.rst b/doc/source/changes.rst index b4ab6f329..825220fdb 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -764,6 +764,9 @@ Starting version 5.5, characters ``+`` and ``~`` may be part of module name or version as long as the string part next to these character is not a valid variant name. +Starting version 5.7, character ``-`` is considered a version number separator +for :mconfig:`extended_default` mechanism. + Environment """"""""""" diff --git a/doc/source/design/extended-default.rst b/doc/source/design/extended-default.rst index a93cd53b0..03cbae665 100644 --- a/doc/source/design/extended-default.rst +++ b/doc/source/design/extended-default.rst @@ -25,15 +25,16 @@ Specification - query soft/1 returns nothing - query soft/10.1.2 returns highest among soft/10.1.2.4 soft/10.1.2.3 -- In situation where soft/1.1(default) soft/1.2 soft/2.1 soft/2.2 +- In situation where soft/1.1(default) soft/1.2 soft/2.1 soft/2.2 soft/3.4-ad75bc9a - query soft/1 returns soft/1.1 - query soft/2 returns soft/2.2 + - query soft/3.4 returns soft/3.4-ad75bc9a -- Character considered as version number separator: ``.`` +- Characters considered as version number separator: ``.`` and ``-`` - list: ``.`` and ``-`` - - ``-`` was also considered initially, but cannot determine in all case the highest version specified after this character (may find a hash name, strings like *rc*, *alpha*, *beta*, etc) + - ``-`` is considered a version number separator character since version 5.7 - not possible with ``+`` as it is used by variant specification - Does not apply to the root part of module name diff --git a/doc/source/module.rst b/doc/source/module.rst index 807573a9c..fbde31ccf 100644 --- a/doc/source/module.rst +++ b/doc/source/module.rst @@ -3146,8 +3146,9 @@ Constraints can be expressed to refine the selection of module version to: Advanced specification of single version or list of versions may benefit from the activation of the extended default mechanism (see :envvar:`MODULES_EXTENDED_DEFAULT`) to use an abbreviated notation like ``@1`` -to refer to more precise version numbers like ``1.2.3``. Range of versions on -its side natively handles abbreviated versions. +to refer to more precise version numbers like ``1.2.3``. Characters ``.`` and +``-`` are considered version number separator to determine abbreviated +versions. Range of versions on its side natively handles abbreviated versions. In order to be specified in a range of versions or compared to a range of versions, the version major element should corresponds to a number. For @@ -5008,9 +5009,9 @@ ENVIRONMENT If set to ``1``, a specified module version is matched against starting portion of existing module versions, where portion is a substring separated - from the rest of the version string by a ``.`` character. For example + from the rest of the version string by ``.`` or ``-`` characters. For example specified modules ``mod/1`` and ``mod/1.2`` will match existing modulefile - ``mod/1.2.3``. + ``mod/1.2.3`` and ``mod/2.4`` will match ``mod/2.4-91db5cf2``. In case multiple modulefiles match the specified module version and a single module has to be selected, the explicitly set default version is returned if @@ -5026,6 +5027,9 @@ ENVIRONMENT .. versionadded:: 4.4 + .. versionchanged:: 5.7 + Character ``-`` is also considered a version number separator + .. envvar:: MODULES_FAMILY_ Module name minus version that provides for the *name* family in currently diff --git a/doc/source/modulefile.rst b/doc/source/modulefile.rst index 39169c8e7..dd587f99a 100644 --- a/doc/source/modulefile.rst +++ b/doc/source/modulefile.rst @@ -1949,8 +1949,8 @@ The equivalent :file:`.modulerc` would look like: If the extended default mechanism is enabled (see :envvar:`MODULES_EXTENDED_DEFAULT` in :ref:`module(1)`) the module version specified is matched against starting portion of existing module versions, -where portion is a substring separated from the rest of version string by a -``.`` character. +where portion is a substring separated from the rest of version string by +``.`` or ``-`` characters. When the implicit default mechanism and the `Advanced module version specifiers`_ are both enabled, a ``default`` and ``latest`` symbolic versions @@ -2081,7 +2081,9 @@ Advanced specification of single version or list of versions may benefit from the activation of the extended default mechanism (see :envvar:`MODULES_EXTENDED_DEFAULT` in :ref:`module(1)`) to use an abbreviated notation like ``@1`` to refer to more precise version numbers like ``1.2.3``. -Range of versions on its side natively handles abbreviated versions. +Characters ``.`` and ``-`` are considered version number separator to +determine abbreviated versions. Range of versions on its side natively handles +abbreviated versions. In order to be specified in a range of versions or compared to a range of versions, the version major element should corresponds to a number. For @@ -2109,6 +2111,9 @@ version will be selected. .. versionchanged:: 4.8 Use of version range is allowed in version list + .. versionchanged:: 5.7 + Character ``-`` is also considered a version number separator + Variants ^^^^^^^^ diff --git a/tcl/modspec.tcl b/tcl/modspec.tcl index 3325cdb37..97bf7e488 100644 --- a/tcl/modspec.tcl +++ b/tcl/modspec.tcl @@ -241,6 +241,10 @@ proc defineDoesModMatchAtDepthProc {contains querydepth test} { } } +proc extendedDefaultCharGlobMatch {} { + return {[-.]*} +} + # Define procedure to check module version equals pattern. Adapt procedure # code whether icase and extended_default are enabled or disabled proc defineModVersCmpProc {icase extdfl} { @@ -270,6 +274,7 @@ proc defineModVersCmpProc {icase extdfl} { # alternative definitions of modVersCmp proc proc modVersCmpProc {cmpspec versspec modvers test {psuf {}}} { set ret 0 + set echar [extendedDefaultCharGlobMatch] switch -- $cmpspec { in { # check each verspec in list until match @@ -295,26 +300,27 @@ proc modVersCmpProc {cmpspec versspec modvers test {psuf {}}} { # are always extended_default-enabled (as 1.2 includes 1.2.12 for # instance) and equal, eqstart and match tests are equivalent set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $versspec] != -1 || [string match $versspec.* $modvers])}] + $versspec] != -1 || [string match $versspec$echar $modvers])}] } le { # 'ge' comment also applies here set ret [expr {[isVersion $modvers] && ([versioncmp $versspec\ - $modvers] != -1 || [string match $versspec.* $modvers])}] + $modvers] != -1 || [string match $versspec$echar $modvers])}] } be { # 'ge' comment also applies here lassign $versspec lovers hivers set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $lovers] != -1 || [string match $lovers.* $modvers]) &&\ + $lovers] != -1 || [string match $lovers$echar $modvers]) &&\ ([versioncmp $hivers $modvers] != -1 || [string match\ - $hivers.* $modvers])}] + $hivers$echar $modvers])}] } } return $ret } proc modVersCmpProcIcase {cmpspec versspec modvers test {psuf {}}} { set ret 0 + set echar [extendedDefaultCharGlobMatch] switch -- $cmpspec { in { foreach inspec $versspec { @@ -336,24 +342,27 @@ proc modVersCmpProcIcase {cmpspec versspec modvers test {psuf {}}} { } ge { set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $versspec] != -1 || [string match -nocase $versspec.* $modvers])}] + $versspec] != -1 || [string match -nocase $versspec$echar\ + $modvers])}] } le { set ret [expr {[isVersion $modvers] && ([versioncmp $versspec\ - $modvers] != -1 || [string match -nocase $versspec.* $modvers])}] + $modvers] != -1 || [string match -nocase $versspec$echar\ + $modvers])}] } be { lassign $versspec lovers hivers set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $lovers] != -1 || [string match $lovers.* $modvers]) &&\ + $lovers] != -1 || [string match $lovers$echar $modvers]) &&\ ([versioncmp $hivers $modvers] != -1 || [string match -nocase\ - $hivers.* $modvers])}] + $hivers$echar $modvers])}] } } return $ret } proc modVersCmpProcExtdfl {cmpspec versspec modvers test {psuf {}}} { set ret 0 + set echar [extendedDefaultCharGlobMatch] switch -- $cmpspec { in { foreach inspec $versspec { @@ -372,30 +381,31 @@ proc modVersCmpProcExtdfl {cmpspec versspec modvers test {psuf {}}} { ##nagelfar ignore Non static subcommand set ret [string $test $versspec $modvers] } - if {!$ret && [string match $versspec.* $modvers]} { + if {!$ret && [string match $versspec$echar $modvers]} { set ret 1 } } ge { set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $versspec] != -1 || [string match $versspec.* $modvers])}] + $versspec] != -1 || [string match $versspec$echar $modvers])}] } le { set ret [expr {[isVersion $modvers] && ([versioncmp $versspec\ - $modvers] != -1 || [string match $versspec.* $modvers])}] + $modvers] != -1 || [string match $versspec$echar $modvers])}] } be { lassign $versspec lovers hivers set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $lovers] != -1 || [string match $lovers.* $modvers]) &&\ + $lovers] != -1 || [string match $lovers$echar $modvers]) &&\ ([versioncmp $hivers $modvers] != -1 || [string match\ - $hivers.* $modvers])}] + $hivers$echar $modvers])}] } } return $ret } proc modVersCmpProcIcaseExtdfl {cmpspec versspec modvers test {psuf {}}} { set ret 0 + set echar [extendedDefaultCharGlobMatch] switch -- $cmpspec { in { foreach inspec $versspec { @@ -414,24 +424,26 @@ proc modVersCmpProcIcaseExtdfl {cmpspec versspec modvers test {psuf {}}} { ##nagelfar ignore Non static subcommand set ret [string $test -nocase $versspec $modvers] } - if {!$ret && [string match -nocase $versspec.* $modvers]} { + if {!$ret && [string match -nocase $versspec$echar $modvers]} { set ret 1 } } ge { set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $versspec] != -1 || [string match -nocase $versspec.* $modvers])}] + $versspec] != -1 || [string match -nocase $versspec$echar\ + $modvers])}] } le { set ret [expr {[isVersion $modvers] && ([versioncmp $versspec\ - $modvers] != -1 || [string match -nocase $versspec.* $modvers])}] + $modvers] != -1 || [string match -nocase $versspec$echar\ + $modvers])}] } be { lassign $versspec lovers hivers set ret [expr {[isVersion $modvers] && ([versioncmp $modvers\ - $lovers] != -1 || [string match $lovers.* $modvers]) &&\ + $lovers] != -1 || [string match $lovers$echar $modvers]) &&\ ([versioncmp $hivers $modvers] != -1 || [string match -nocase\ - $hivers.* $modvers])}] + $hivers$echar $modvers])}] } } return $ret @@ -536,10 +548,11 @@ proc defineModEqStaticProc {icase extdfl modspec} { append procbody " if {!\$ret && \[string first / \$pmod\] != -1} { if {\$test eq {match}} { - set pmodextdfl \$pmod.* + set pmodextdfl \$pmod } else { - set pmodextdfl {$pmodescglob.*} + set pmodextdfl {$pmodescglob} } + append pmodextdfl \[extendedDefaultCharGlobMatch\] set ret \[string match $nocasearg\$pmodextdfl \$mod\] }" } @@ -958,10 +971,11 @@ proc modEqProcExtdfl {pattern mod {test equal} {trspec 1} {ismodlo 0} {vrcmp\ # try the extended default match if not root module and not eqspec test if {![info exists eqspec] && !$ret && [string first / $pmod] != -1} { if {$test eq {match}} { - set pmodextdfl $pmod.* + set pmodextdfl $pmod } else { - set pmodextdfl $pmodescglob.* + set pmodextdfl $pmodescglob } + append pmodextdfl [extendedDefaultCharGlobMatch] set ret [string match $pmodextdfl $mod] if {!$ret && [llength $altlist]} { foreach alt $altlist { @@ -1107,10 +1121,11 @@ proc modEqProcIcaseExtdfl {pattern mod {test equal} {trspec 1} {ismodlo 0}\ # try the extended default match if not root module and not eqspec test if {![info exists eqspec] && !$ret && [string first / $pmod] != -1} { if {$test eq {match}} { - set pmodextdfl $pmod.* + set pmodextdfl $pmod } else { - set pmodextdfl $pmodescglob.* + set pmodextdfl $pmodescglob } + append pmodextdfl [extendedDefaultCharGlobMatch] set ret [string match -nocase $pmodextdfl $mod] if {!$ret && [llength $altlist]} { foreach alt $altlist { diff --git a/testsuite/modules.70-maint/260-extended_default.exp b/testsuite/modules.70-maint/260-extended_default.exp index 69aabe73a..c2037475b 100644 --- a/testsuite/modules.70-maint/260-extended_default.exp +++ b/testsuite/modules.70-maint/260-extended_default.exp @@ -81,7 +81,7 @@ setenv_var MODULES_EXTENDED_DEFAULT 1 # test over different kind of module versions array set exactmatch [list extdfl/1.1.0 1 extdfl/2.0 1] -foreach {query match} [list extdfl/1 extdfl/1.3.1 extdfl/1.0 extdfl/1.0.2 extdfl/1.0.0 ERR extdfl/1.1 extdfl/1.1.0-beta extdfl/1.1.0 extdfl/1.1.0 extdfl/1.2 extdfl/1.2.10 extdfl/1.3 extdfl/1.3.1 extdfl/1.4 extdfl/1.4.5 ext*l/1.4 ERR ext?fl/1.4 ERR extdfl/2 extdfl/2.0.1 extdfl/2.0 extdfl/2.0 extdfl2/3.0 extdfl2/3.0.15 extdfl2/3 extdfl2/3.10.2 extdfl2/3.1 extdfl2/3.1.7 extdfl2/3.9 extdfl2/3.9.2 extdfl2/3.09 extdfl2/3.09.3 extdfl3/1 extdfl3/1.3/4 extdflb ERR extdflb.4 ERR extdflc ERR e.t.fl/1.4 e.t.fl/1.4.5 e??.*/1.4 ERR] { +foreach {query match} [list extdfl/1 extdfl/1.3.1 extdfl/1.0 extdfl/1.0.2 extdfl/1.0.0 extdfl/1.0.0-beta extdfl/1.1 extdfl/1.1.0-beta extdfl/1.1.0 extdfl/1.1.0 extdfl/1.2 extdfl/1.2.10 extdfl/1.3 extdfl/1.3.1 extdfl/1.4 extdfl/1.4.5 ext*l/1.4 ERR ext?fl/1.4 ERR extdfl/2 extdfl/2.0.1 extdfl/2.0 extdfl/2.0 extdfl2/3.0 extdfl2/3.0.15 extdfl2/3 extdfl2/3.10.2 extdfl2/3.1 extdfl2/3.1.7 extdfl2/3.9 extdfl2/3.9.2 extdfl2/3.09 extdfl2/3.09.3 extdfl3/1 extdfl3/1.3/4 extdflb ERR extdflb.4 ERR extdflc ERR e.t.fl/1.4 e.t.fl/1.4.5 e??.*/1.4 ERR] { if {$match eq {ERR}} { set ans ERR set tserr $err_path'$query'