summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorapocelipes <[email protected]>2026-08-09 05:35:46 +0800
committerapocelipes <[email protected]>2026-08-09 06:08:45 +0800
commit1d8683111e485d8a1172b6b689da6dddb3127735 (patch)
treec575cedb7b6cf3f18ec255441c8dc6c25c82df22
parent6ac4ea833193a4319a1eb6e5f588d1877fd48064 (diff)
fix(semver): correct version selection
semver_rangen() accepts an exact version as a range, and SemVer comparison ignores build metadata. This can select a different version than requested. Try exact string matches for versions and tags before falling back to the range selection.
-rw-r--r--core/src/xmake/semver/select.c51
-rwxr-xr-xtests/modules/semver/test.lua35
2 files changed, 64 insertions, 22 deletions
diff --git a/core/src/xmake/semver/select.c b/core/src/xmake/semver/select.c
index 283afb050..82de60e74 100644
--- a/core/src/xmake/semver/select.c
+++ b/core/src/xmake/semver/select.c
@@ -33,6 +33,14 @@
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
+static tb_bool_t xm_semver_is_exact_version(tb_char_t const *version_str, tb_size_t version_len) {
+ semver_t version = { 0 };
+ if (!semvern(&version, version_str, version_len)) {
+ semver_dtor(&version);
+ return tb_true;
+ }
+ return tb_false;
+}
static tb_bool_t xm_semver_select_from_versions_tags1(
lua_State *lua, tb_int_t fromidx, semver_t *semver, semver_range_t const *range, semvers_t *matches) {
// clear matches
@@ -179,6 +187,7 @@ tb_int_t xm_semver_select(lua_State *lua) {
// select version
tb_bool_t ok = tb_false;
tb_bool_t is_range = tb_false;
+ tb_bool_t is_exact = tb_false;
tb_char_t const *range_str = tb_null;
semver_t semver = { 0 };
semvers_t matches = { 0 };
@@ -193,30 +202,28 @@ tb_int_t xm_semver_select(lua_State *lua) {
// parse the version range string
is_range = semver_rangen(&range, range_str, range_len) == 0;
- if (is_range) {
- // attempt to select version from the versions list first
- if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) {
- ok = tb_true;
- break;
- }
+ is_exact = xm_semver_is_exact_version(range_str, range_len);
- // attempt to select version from the tags list
- if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) {
- ok = tb_true;
- break;
- }
- } else {
- // attempt to select version from the versions list first
- if (xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) {
- ok = tb_true;
- break;
- }
+ // attempt to select version from the versions list first
+ if ((is_exact || !is_range) &&
+ xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) {
+ ok = tb_true;
+ break;
+ }
+ if (is_range && xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) {
+ ok = tb_true;
+ break;
+ }
- // attempt to select version from the tags list
- if (xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) {
- ok = tb_true;
- break;
- }
+ // attempt to select version from the tags list
+ if ((is_exact || !is_range) &&
+ xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) {
+ ok = tb_true;
+ break;
+ }
+ if (is_range && xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) {
+ ok = tb_true;
+ break;
}
// attempt to select version from the branches
diff --git a/tests/modules/semver/test.lua b/tests/modules/semver/test.lua
index 1ab6dc8aa..3c14ad1d7 100755
--- a/tests/modules/semver/test.lua
+++ b/tests/modules/semver/test.lua
@@ -18,6 +18,41 @@ function test_semver_select(t)
, "^1.5.0"
,{"1.4.0", "1.5.0", "1.5.1"})
+ _check_semver_select(t, {"3.53.0+200", "version"}
+ , "3.53.0+200"
+ , {"3.53.0+0", "3.53.0+100", "3.53.0+200"})
+
+ _check_semver_select(t, {"3.53.0+100", "version"}
+ , "3.53.0+999"
+ , {"3.53.0+100"})
+
+ _check_semver_select(t, {"1.2.3", "version"}
+ , "1.2.3"
+ , {"1.2.3+1", "1.2.3"})
+
+ _check_semver_select(t, {"1.2.9", "version"}
+ , "1.2"
+ , {"1.2", "1.2.9"})
+
+ _check_semver_select(t, {"1.9.0", "version"}
+ , "^1.2.3"
+ , {"^1.2.3", "1.2.3", "1.9.0"})
+
+ _check_semver_select(t, {"v1.2.3+7", "version"}
+ , "1.2.3"
+ , {"v1.2.3+7"}
+ , {"1.2.3"})
+
+ _check_semver_select(t, {"3.53.0+200", "tag"}
+ , "3.53.0+200"
+ , nil
+ , {"3.53.0+0", "3.53.0+200"})
+
+ _check_semver_select(t, {"3.53.0+100", "tag"}
+ , "3.53.0+999"
+ , nil
+ , {"3.53.0+100"})
+
_check_semver_select(t, {"master", "branch"}
, "master"
, {"1.4.0", "1.5.0", "1.5.1"}