diff options
| author | ruki <[email protected]> | 2017-09-11 22:56:08 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-09-11 11:36:50 +0800 |
| commit | c3a7d94a71c62bbccc2931d84b713b1b44c6a5c5 (patch) | |
| tree | 288b9efaaee0f087b09d6b9631692dc654117aae | |
| parent | 9f42256a7eef0c84267d5f88cf71865e58dc54f2 (diff) | |
improve semver module and select master version
| -rw-r--r-- | core/src/sv/include/semver.h | 15 | ||||
| -rw-r--r-- | core/src/xmake/semver/parse.c | 40 | ||||
| -rw-r--r-- | core/src/xmake/semver/prefix.h | 23 | ||||
| -rw-r--r-- | core/src/xmake/semver/satisfies.c | 33 | ||||
| -rw-r--r-- | core/src/xmake/semver/select.c | 267 | ||||
| -rw-r--r-- | core/src/xmake/semver/semver.c | 48 | ||||
| -rwxr-xr-x | tests/modules/semver/test.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/semver.lua | 1 |
8 files changed, 291 insertions, 140 deletions
diff --git a/core/src/sv/include/semver.h b/core/src/sv/include/semver.h index bdc005702..0cde4cdd9 100644 --- a/core/src/sv/include/semver.h +++ b/core/src/sv/include/semver.h @@ -198,8 +198,11 @@ SV_API void semvers_pclear(semvers_t *self); #define semvers_growth(s, n) \ semvers_pgrowth(&(s),n) +#define semvers_pgrow(s, n) \ + semvers_pgrowth((s),(s)->length+(n)) + #define semvers_grow(s, n) \ - semvers_pgrowth(&(s),(s).length+(n)) + semvers_pgrow(&(s), n) #define semvers_resize(s, n) \ ((s).length=semvers_growth(s, n)) @@ -207,11 +210,17 @@ SV_API void semvers_pclear(semvers_t *self); #define semvers_erase(s, i) \ semvers_perase(&(s), i) +#define semvers_ppush(s, x) \ + (semvers_pgrow(s,1),(s)->data[(s)->length++]=(x)) + #define semvers_push(s, x) \ - (semvers_grow(s,1),(s).data[(s).length++]=(x)) + semvers_ppush(&(s), x) + +#define semvers_ppop(s) \ + (s)->data[--(s)->length] #define semvers_pop(s) \ - (s).data[--(s).length] + semvers_ppop(&(s)) #define semvers_unshift(s, x) \ (semvers_grow(s,1),memmove((s).data+1,(s).data,(s).length++*sizeof(semver_t)),(s).data[0]=(x)) diff --git a/core/src/xmake/semver/parse.c b/core/src/xmake/semver/parse.c index 976f198fb..2180d7800 100644 --- a/core/src/xmake/semver/parse.c +++ b/core/src/xmake/semver/parse.c @@ -38,28 +38,46 @@ * implementation */ -// parse wrapper +/* version = semver.parse("v1.0.1-beta") + * + * + { + patch = 1 + , raw = v1.0.1-beta + , version = v1.0.1-beta + , major = 1 + , build = + { + } + + , minor = 0 + , prerelease = + { + beta + } + } + * + */ tb_int_t xm_semver_parse(lua_State* lua) { - semver_t semver = {0}; - // check tb_assert_and_check_return_val(lua, 0); // get the version string - tb_char_t const* str = luaL_checkstring(lua, 1); - tb_check_return_val(str, 0); + tb_char_t const* version_str = luaL_checkstring(lua, 1); + tb_check_return_val(version_str, 0); - if (semvern(&semver, str, tb_strlen(str))) { + // parse version string + semver_t semver = {0}; + if (semvern(&semver, version_str, tb_strlen(version_str))) + { lua_pushnil(lua); - lua_pushfstring(lua, "Unable to parse semver '%s'", str); - + lua_pushfstring(lua, "unable to parse semver '%s'", version_str); return 2; } - lua_pushsemver(lua, semver); - semver_dtor(&semver); - // ok + lua_pushsemver(lua, &semver); + semver_dtor(&semver); return 1; } diff --git a/core/src/xmake/semver/prefix.h b/core/src/xmake/semver/prefix.h index 17c4e9f5a..2a4155aa8 100644 --- a/core/src/xmake/semver/prefix.h +++ b/core/src/xmake/semver/prefix.h @@ -29,9 +29,28 @@ * includes */ #include "../prefix.h" - #include "semver.h" -void lua_pushsemver(lua_State *lua, semver_t semver); +/* ////////////////////////////////////////////////////////////////////////////////////// + * extern + */ +__tb_extern_c_enter__ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +/* push struct semver + * + * @param lua the lua context + * @param semver the semver struct + * + */ +tb_void_t lua_pushsemver(lua_State *lua, semver_t const* semver); + +/* ////////////////////////////////////////////////////////////////////////////////////// + * leave + */ +__tb_extern_c_leave__ #endif diff --git a/core/src/xmake/semver/satisfies.c b/core/src/xmake/semver/satisfies.c index f3b34890f..f630558d9 100644 --- a/core/src/xmake/semver/satisfies.c +++ b/core/src/xmake/semver/satisfies.c @@ -38,37 +38,40 @@ * implementation */ -// satisfies wrapper +/* satisfies the given version range? + * + * semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true + */ tb_int_t xm_semver_satisfies(lua_State* lua) { - semver_t semver = {0}; - semver_range_t range = {0}; - // check tb_assert_and_check_return_val(lua, 0); // get the version string - tb_char_t const* str = luaL_checkstring(lua, 1); - tb_char_t const* range_str = luaL_checkstring(lua, 2); + tb_char_t const* version_str = luaL_checkstring(lua, 1); + tb_char_t const* range_str = luaL_checkstring(lua, 2); + tb_assert_and_check_return_val(version_str && range_str, 0); - tb_check_return_val(str, 0); - tb_check_return_val(range_str, 0); - - if (semvern(&semver, str, tb_strlen(str))) { + // parse the version string + semver_t semver = {0}; + if (semvern(&semver, version_str, tb_strlen(version_str))) + { lua_pushnil(lua); - lua_pushfstring(lua, "Unable to parse semver '%s'", str); - + lua_pushfstring(lua, "unable to parse semver '%s'", version_str); return 2; } - if (semver_rangen(&range, range_str, tb_strlen(range_str))) { + // parse the version range string + semver_range_t range = {0}; + if (semver_rangen(&range, range_str, tb_strlen(range_str))) + { semver_dtor(&semver); lua_pushnil(lua); - lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str); - + lua_pushfstring(lua, "unable to parse semver range '%s'", range_str); return 2; } + // satisfies this range? lua_pushboolean(lua, semver_range_match(semver, range)); semver_dtor(&semver); semver_range_dtor(&range); diff --git a/core/src/xmake/semver/select.c b/core/src/xmake/semver/select.c index 6400de6a8..ea81b1e0c 100644 --- a/core/src/xmake/semver/select.c +++ b/core/src/xmake/semver/select.c @@ -32,129 +32,226 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ -#include <stdlib.h> #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// - * implementation + * private implementation */ - -// satisfies wrapper -tb_int_t xm_semver_select(lua_State* lua) +static tb_bool_t xm_semver_select_from_versions_tags(lua_State* lua, tb_int_t fromidx, semver_t* semver, semver_range_t const* range, semvers_t* matches) { - semver_t semver = {0}; - semvers_t matches = {0}; - semver_range_t range = {0}; - lua_Integer i; - size_t range_len = 0, source_len; - tb_char_t const* source_str; - tb_char_t const* source; - tb_bool_t is_range; + // clear matches + semvers_pclear(matches); - lua_settop(lua, 4); + // select all matches + tb_int_t i = 0; + luaL_checktype(lua, fromidx, LUA_TTABLE); + for (i = lua_objlen(lua, fromidx); i > 0; --i) + { + lua_pushinteger(lua, i); + lua_gettable(lua, fromidx); - // check - tb_assert_and_check_return_val(lua, 0); + tb_char_t const* source_str = luaL_checkstring(lua, -1); + if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) + { + if (semver_range_pmatch(semver, range)) semvers_ppush(matches, *semver); + else semver_dtor(semver); + } + } - // get the version string - tb_char_t const* range_str = luaL_checkstring(lua, 1); - tb_check_return_val(range_str, 0); - range_len = tb_strlen(range_str); + // no matches? + tb_check_return_val(matches->length, tb_false); - is_range = semver_rangen(&range, range_str, range_len) == 0; - if (is_range) { - source = "versions"; - luaL_checktype(lua, 2, LUA_TTABLE); - for (i = lua_objlen(lua, 2); i > 0; --i) { - lua_pushinteger(lua, i); - lua_gettable(lua, 2); + // sort matches + semvers_psort(matches); - source_str = luaL_checkstring(lua, -1); - tb_check_return_val(source_str, 0); + // get the newest version + semver_t top = semvers_ppop(matches); + lua_createtable(lua, 0, 2); - if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) { - if (semver_range_match(semver, range)) { - semvers_push(matches, semver); - } else { - semver_dtor(&semver); - } - } - } - if (matches.length) { - goto match; - } - semvers_clear(matches); - source = "tags"; - luaL_checktype(lua, 3, LUA_TTABLE); - for (i = lua_objlen(lua, 3); i > 0; --i) { - lua_pushinteger(lua, i); - lua_gettable(lua, 3); + // return results + lua_pushstring(lua, top.raw); + lua_setfield(lua, -2, "version"); - source_str = luaL_checkstring(lua, -1); - tb_check_return_val(source_str, 0); + lua_pushstring(lua, fromidx == 2? "versions" : "tags"); + lua_setfield(lua, -2, "source"); - if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) { - if (semver_range_match(semver, range)) { - semvers_push(matches, semver); - } else { - semver_dtor(&semver); - } - } - } - if (matches.length) { - goto match; - } - semvers_dtor(matches); - semver_range_dtor(&range); - } + // exit the popped semver + semver_dtor(&top); - source = "branches"; - luaL_checktype(lua, 4, LUA_TTABLE); - for (i = lua_objlen(lua, 4); i > 0; --i) { + // ok + return tb_true; +} +static tb_bool_t xm_semver_select_from_branches(lua_State* lua, tb_int_t fromidx, tb_char_t const* range_str, tb_size_t range_len) +{ + tb_int_t i = 0; + luaL_checktype(lua, fromidx, LUA_TTABLE); + for (i = lua_objlen(lua, fromidx); i > 0; --i) + { lua_pushinteger(lua, i); - lua_gettable(lua, 4); + lua_gettable(lua, fromidx); - source_str = luaL_checkstring(lua, -1); - tb_check_return_val(source_str, 0); - source_len = tb_strlen(source_str); + tb_char_t const* source_str = luaL_checkstring(lua, -1); + tb_check_continue(source_str); - if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) { + tb_size_t source_len = tb_strlen(source_str); + if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) + { lua_createtable(lua, 0, 2); lua_pushlstring(lua, source_str, source_len); lua_setfield(lua, -2, "version"); - lua_pushstring(lua, source); + lua_pushstring(lua, "branches"); lua_setfield(lua, -2, "source"); - return 1; + // ok + return tb_true; } } - if (!is_range) { - lua_pushnil(lua); - lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str); + // no matches + return tb_false; +} +static tb_bool_t xm_semver_select_master_from_versions_tags(lua_State* lua, tb_int_t fromidx, semver_t* semver, semvers_t* matches) +{ + // clear matches + semvers_pclear(matches); - return 2; + // push all versions to matches + tb_int_t i = 0; + luaL_checktype(lua, fromidx, LUA_TTABLE); + for (i = lua_objlen(lua, fromidx); i > 0; --i) + { + lua_pushinteger(lua, i); + lua_gettable(lua, fromidx); + + tb_char_t const* source_str = luaL_checkstring(lua, -1); + if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) + semvers_ppush(matches, *semver); } - lua_pushnil(lua); - lua_pushfstring(lua, "Unable to select version for range '%s'", range_str); - return 2; - match: - semvers_sort(matches); - semver = semvers_pop(matches); + // no matches? + tb_check_return_val(matches->length, tb_false); + + // sort matches + semvers_psort(matches); + + // get the newest match + semver_t top = semvers_ppop(matches); lua_createtable(lua, 0, 2); - lua_pushstring(lua, semver.raw); + // return results + lua_pushstring(lua, top.raw); lua_setfield(lua, -2, "version"); - lua_pushstring(lua, source); + lua_pushstring(lua, fromidx == 2? "versions" : "tags"); lua_setfield(lua, -2, "source"); + // exit the popped semver + semver_dtor(&top); + + // ok + return tb_true; +} + + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* select version + * + * local versioninfo, errors = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"master", "dev"}) + */ +tb_int_t xm_semver_select(lua_State* lua) +{ +// lua_settop(lua, 4); + + // check + tb_assert_and_check_return_val(lua, 0); + + // select version + tb_bool_t ok = tb_false; + tb_bool_t is_range = tb_false; + tb_char_t const* range_str = tb_null; + semver_t semver = {0}; + semvers_t matches = {0}; + semver_range_t range = {0}; + do + { + // get the version range string + range_str = luaL_checkstring(lua, 1); + tb_check_break(range_str); + + // get the range string length + tb_size_t range_len = tb_strlen(range_str); + + // 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_tags(lua, 2, &semver, &range, &matches)) + { + ok = tb_true; + break; + } + + // attempt to select version from the tags list + if (xm_semver_select_from_versions_tags(lua, 3, &semver, &range, &matches)) + { + ok = tb_true; + break; + } + } + + // attempt to select version from the branches + if (xm_semver_select_from_branches(lua, 4, range_str, range_len)) + { + ok = tb_true; + break; + } + + // select the lastest version from the tags and versions if be master + if (!tb_strcmp(range_str, "master")) + { + // attempt to select master version from the versions list + if (xm_semver_select_master_from_versions_tags(lua, 2, &semver, &matches)) + { + ok = tb_true; + break; + } + + // attempt to select master version from the tags list + if (xm_semver_select_master_from_versions_tags(lua, 3, &semver, &matches)) + { + ok = tb_true; + break; + } + } + + } while (0); + + // exit matches semvers_dtor(matches); - semver_dtor(&semver); + + // exit range semver_range_dtor(&range); + // failed? + if (!ok) + { + if (!is_range) + { + lua_pushnil(lua); + lua_pushfstring(lua, "unable to parse semver range '%s'", range_str); + } + + lua_pushnil(lua); + lua_pushfstring(lua, "unable to select version for range '%s'", range_str); + return 2; + } + + // ok return 1; } diff --git a/core/src/xmake/semver/semver.c b/core/src/xmake/semver/semver.c index 27dfb3fb6..f6e93dc23 100644 --- a/core/src/xmake/semver/semver.c +++ b/core/src/xmake/semver/semver.c @@ -19,7 +19,7 @@ * Copyright (C) 2015 - 2017, TBOOX Open Source Group. * * @author uael - * @file semver.c + * @file semver->c * */ @@ -37,53 +37,53 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ - -void lua_pushsemver(lua_State *lua, const semver_t semver) +tb_void_t lua_pushsemver(lua_State *lua, semver_t const* semver) { - semver_id_t const *id; - tb_uchar_t i = 0; + // check + tb_assert(lua && semver); + // return a semver table lua_createtable(lua, 0, 7); - lua_pushstring(lua, semver.raw); + lua_pushstring(lua, semver->raw); lua_setfield(lua, -2, "raw"); - lua_pushlstring(lua, semver.raw, semver.len); + lua_pushlstring(lua, semver->raw, semver->len); lua_setfield(lua, -2, "version"); - lua_pushinteger(lua, semver.major); + lua_pushinteger(lua, semver->major); lua_setfield(lua, -2, "major"); - lua_pushinteger(lua, semver.minor); + lua_pushinteger(lua, semver->minor); lua_setfield(lua, -2, "minor"); - lua_pushinteger(lua, semver.patch); + lua_pushinteger(lua, semver->patch); lua_setfield(lua, -2, "patch"); + // push prelease table lua_pushstring(lua, "prerelease"); lua_newtable(lua); - id = &semver.prerelease; - while (id && id->len) { - if (id->numeric) { - lua_pushinteger(lua, id->num); - } else { - lua_pushlstring(lua, id->raw, id->len); - } + + tb_uchar_t i = 0; + semver_id_t const* id = &semver->prerelease; + while (id && id->len) + { + if (id->numeric) lua_pushinteger(lua, id->num); + else lua_pushlstring(lua, id->raw, id->len); id = id->next; lua_rawseti(lua, -2, ++i); } lua_settable(lua, -3); + // push the build table i = 0; lua_pushstring(lua, "build"); lua_newtable(lua); - id = &semver.build; - while (id && id->len) { - if (id->numeric) { - lua_pushinteger(lua, id->num); - } else { - lua_pushlstring(lua, id->raw, id->len); - } + id = &semver->build; + while (id && id->len) + { + if (id->numeric) lua_pushinteger(lua, id->num); + else lua_pushlstring(lua, id->raw, id->len); id = id->next; lua_rawseti(lua, -2, ++i); } diff --git a/tests/modules/semver/test.lua b/tests/modules/semver/test.lua index 884eaf82e..f6583930e 100755 --- a/tests/modules/semver/test.lua +++ b/tests/modules/semver/test.lua @@ -33,6 +33,10 @@ function _test_semver_select() , {"v1.2.0", "v1.6.0"} , {"master", "dev"}) + _check_semver_select({"1.5.1", "versions"} + , "master" + , {"1.4.0", "1.5.0", "1.5.1"}) + print("semver.select: ok!") end diff --git a/xmake/core/sandbox/modules/import/core/base/semver.lua b/xmake/core/sandbox/modules/import/core/base/semver.lua index 08a43dd76..85642195b 100644 --- a/xmake/core/sandbox/modules/import/core/base/semver.lua +++ b/xmake/core/sandbox/modules/import/core/base/semver.lua @@ -51,6 +51,7 @@ end -- semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true -- function sandbox_core_base_semver.satisfies(version, range) + -- satisfies version local result, errors = semver.satisfies(version, range) if errors then |
