Skip to content

Commit

Permalink
Merge pull request #44 from joewiz/semver2.0
Browse files Browse the repository at this point in the history
WIP: Adopt semver.xq library to fix version sorting & querying woes
  • Loading branch information
adamretter authored Aug 9, 2019
2 parents 83df7e1 + ebc1247 commit 4db0abd
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 56 deletions.
1 change: 1 addition & 0 deletions expath-pkg.xml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
<title>eXist-db Public Application Repository</title>
<dependency processor="http://exist-db.org" semver-min="3.5.0"/>
<dependency package="http://expath.org/ns/crypto" semver-min="0.5"/>
<dependency package="http://exist-db.org/xquery/semver-xq" semver-min="2.2.0"/>
</package>
1 change: 0 additions & 1 deletion modules/find.xql
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import module namespace response="http://exist-db.org/xquery/response";

import module namespace app="http://exist-db.org/xquery/app" at "app.xql";
import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm";
import module namespace scanrepo="http://exist-db.org/xquery/admin/scanrepo" at "scan.xql";

let $abbrev := request:get-parameter("abbrev", ())
let $name := request:get-parameter("name", ())
Expand Down
9 changes: 0 additions & 9 deletions modules/index.xql

This file was deleted.

15 changes: 3 additions & 12 deletions modules/list.xql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare namespace list="http://exist-db.org/apps/public-repo/list";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";

import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm";
import module namespace semver = "http://exist-db.org/xquery/semver";

declare option output:method "xml";
declare option output:media-type "application/xml";
Expand All @@ -18,22 +19,12 @@ declare variable $list:DEFAULT_VERSION := "2.2.0";

declare function list:is-newer-or-same($version1 as xs:string, $version2 as xs:string?) {
empty($version2) or
list:check-version($version1, $version2, function($v1, $v2) { $v1 >= $v2 })
semver:ge($version1, $version2, true())
};

declare function list:is-older-or-same($version1 as xs:string, $version2 as xs:string?) {
empty($version2) or
list:check-version($version1, $version2, function($v1, $v2) { $v1 <= $v2 })
};

declare function list:version-to-number($version as xs:string) as xs:int {
let $ana := analyze-string($version, "(\d+)\.(\d+)\.(\d+)-?(.*)")
return
sum(($ana//fn:group[@nr="1"] * 1000000, $ana//fn:group[@nr="2"] * 1000, $ana//fn:group[@nr="3"]))
};

declare function list:check-version($version1 as xs:string, $version2 as xs:string, $check as function(*)) {
$check(list:version-to-number($version1), list:version-to-number($version2))
semver:le($version1, $version2, true())
};

declare function list:get-app($app as element(), $version as xs:string) {
Expand Down
68 changes: 34 additions & 34 deletions modules/scan.xql
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
xquery version "3.0";
xquery version "3.1";

module namespace scanrepo="http://exist-db.org/xquery/admin/scanrepo";

import module namespace config = "http://exist-db.org/xquery/apps/config" at "config.xqm";
import module namespace crypto = "http://expath.org/ns/crypto";
import module namespace semver = "http://exist-db.org/xquery/semver";
import module namespace util = "http://exist-db.org/xquery/util";

declare namespace repo="http://exist-db.org/xquery/repo";
declare namespace expath="http://expath.org/ns/pkg";

declare function scanrepo:is-newer-or-same($version1 as xs:string, $version2 as xs:string?) {
empty($version2) or
scanrepo:check-version($version1, $version2, function($v1, $v2) { $v1 >= $v2 })
semver:ge($version1, $version2, true())
};

declare function scanrepo:is-older-or-same($version1 as xs:string, $version2 as xs:string?) {
empty($version2) or
scanrepo:check-version($version1, $version2, function($v1, $v2) { $v1 <= $v2 })
};

declare %private function scanrepo:version-to-number($version as xs:string) as xs:int {
let $ana := analyze-string($version, "(\d+)\.(\d+)\.(\d+)-?(.*)")
return
sum(($ana//fn:group[@nr="1"] * 1000000, $ana//fn:group[@nr="2"] * 1000, $ana//fn:group[@nr="3"]))
};

declare %private function scanrepo:check-version($version1 as xs:string, $version2 as xs:string, $check as function(*)) {
$check(scanrepo:version-to-number($version1), scanrepo:version-to-number($version2))
semver:le($version1, $version2, true())
};

declare function scanrepo:process($apps as element(app)*) {
for $app in $apps
order by $app/title
group by $name := $app/name
return
let $newest := scanrepo:find-newest($app, (), ())
(: Identify newest version of the package; sort previous versions newest to oldest; use SemVer 2.0 rules, coercing where needed :)
let $versions := $app/version
let $version-maps :=
$versions ! map:merge((
map:entry("semver", semver:coerce(.) => semver:serialize()),
map:entry("version", .)
))
let $sorted-versions :=
for $version in $version-maps
order by semver:sort($version?semver) descending
return $version?version/..
let $newest-version := $sorted-versions => head()
let $older-versions := $sorted-versions => tail()
let $abbrevs := distinct-values($app/abbrev)
return
<app>
{
$newest/@*,
$newest/*,
$abbrevs[not(. = $newest/abbrev)] ! element abbrev { attribute type { "legacy" }, . }
$newest-version/@*,
$newest-version/*,
$abbrevs[not(. = $newest-version/abbrev)] ! element abbrev { attribute type { "legacy" }, . }
}
<other>
{
reverse(
for $older in $app[version != $newest/version]
let $xar := concat($config:public, "/", $older/@path)
let $hash := crypto:hash(
util:binary-doc($xar),
"sha256",
"hex"
)
let $n := tokenize($older/version, "\.") ! xs:int((analyze-string(., "(\d+)")//fn:group)[1])
order by $n[1], $n[2], $n[3]
return
<version version="{$older/version}">{
$older/@path,
attribute size { xmldb:size($config:public, $older/@path) },
attribute sha256 { $hash },
$older/requires
}</version>
for $older in $older-versions
let $xar := concat($config:public, "/", $older/@path)
let $hash := crypto:hash(
util:binary-doc($xar),
"sha256",
"hex"
)
return
<version version="{$older/version}">{
$older/@path,
attribute size { xmldb:size($config:public, $older/@path) },
attribute sha256 { $hash },
$older/requires
}</version>
}
</other>
</app>
Expand Down
6 changes: 6 additions & 0 deletions repo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
<finish>post-install.xql</finish>
<permissions xmlns:repo="http://exist-db.org/xquery/repo" password="repo" user="repo" group="repo" mode="rw-rw-r--"/>
<changelog>
<change version="1.0.0">
<ul xmlns="http://www.w3.org/1999/xhtml">
<li>New: Full SemVer 2.0 compliance, backward compatible with most previous package version strings</li>
<li>Breaking: New dependency on semver.xq library</li>
</ul>
</change>
<change version="0.8.4">
<ul xmlns="http://www.w3.org/1999/xhtml">
<li>Fixed: Handling for semantic versioning strings with prerelease and build metadata fragments containing numbers</li>
Expand Down

0 comments on commit 4db0abd

Please sign in to comment.