Skip to content

Commit

Permalink
Implement semver in nix
Browse files Browse the repository at this point in the history
  • Loading branch information
adisbladis committed Jul 9, 2019
1 parent 7d886e4 commit 4f2b6c9
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 6 deletions.
74 changes: 74 additions & 0 deletions semver.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{ pkgs ? import <nixpkgs> {}
, lib ? pkgs.lib
}:

let
# Replace a list entry at defined index with set value
replaceIdx = idx: value: list: lib.sublist 0 idx list ++
[ value ] ++
lib.sublist (idx + 1) ((builtins.length) list + 1) list;

operators = let
matchWildCard = s: builtins.match "(.*)${re.wildcard}" s;
mkComparison = returns: version: v: builtins.elem (builtins.compareVersions version v) returns;
mkIdxComparison = idx: version: v: let
ver = builtins.splitVersion v;
minor = builtins.toString (lib.toInt (builtins.elemAt ver idx) + 1);
upper = builtins.concatStringsSep "." (replaceIdx idx minor ver);
in operators.">=" version v && operators."<" version upper;
# For most operations it's sufficient to drop precision for wildcard matches
dropWildcardPrecision = f: version: constraint: let
m = matchWildCard constraint;
hasWildcard = m != null;
c = if hasWildcard then (builtins.elemAt m 0) else constraint;
v =
if hasWildcard then (builtins.substring 0 (builtins.stringLength c) version)
else version;
in f v c;
in {
# Prefix operators
"==" = dropWildcardPrecision (mkComparison [ 0 ]);
">" = dropWildcardPrecision (mkComparison [ 1 ]);
"<" = dropWildcardPrecision (mkComparison [ (-1) ]);
"!=" = v: c: ! operators."==" v c;
">=" = v: c: operators."==" v c || operators.">" v c;
"<=" = v: c: operators."==" v c || operators."<" v c;
# Special prefix operators (expands to other operations)
"~" = mkIdxComparison 1;
"^" = mkIdxComparison 0;
# Infix operators
"-" = version: v: operators.">=" version v.vl && operators."<=" version v.vu;
};

# Reusable regex components
re = {
operators = "([=><!~\^]+)";
version = "([0-9\.\*x]+)";
wildcard = "(\.[x\*])";
};

parseConstraint = constraintStr: let
# The common prefix operators
mPre = builtins.match "${re.operators} *${re.version}" constraintStr;
# There is also an infix operator to match ranges
mIn = builtins.match "${re.version} *(-) *${re.version}" constraintStr;
in (
if mPre != null then {
op = builtins.elemAt mPre 0;
v = builtins.elemAt mPre 1;
}
# Infix operators are range matches
else if mIn != null then {
op = builtins.elemAt mIn 1;
v = {
vl = (builtins.elemAt mIn 0);
vu = (builtins.elemAt mIn 2);
};
}
else throw "Constraint \"${constraintStr}\" could not be parsed");

satisfies = version: constraint: let
inherit (parseConstraint constraint) op v;
in operators."${op}" version v;

in { inherit satisfies; }
8 changes: 2 additions & 6 deletions shrinkwrap.nix
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,7 @@ let
else (_indexOf elem list (idx+1));
in (elem: list: _indexOf elem list 0);

# TODO: Reimplement semver parsing in nix
satisfiesSemver = version: versionSpec: (lib.importJSON ((pkgs.runCommandNoCC "semver" {} ''
env NODE_PATH=${nodePackages.semver}/lib/node_modules ${nodejs}/bin/node -e 'console.log(require("semver").satisfies("${version}", "${versionSpec}"))' > $out
'').outPath));
versionSpecMatches = (version: versionSpec: satisfiesSemver version versionSpec);
semver = import ./semver.nix { inherit pkgs; };

# Extract further required info from attrsets:
# resolution
Expand Down Expand Up @@ -106,7 +102,7 @@ let
resolve = pname: versionSpec: with builtins; let
nameMatches = lib.filterAttrs (n: v: v.pname == pname) packageSet;
matches = lib.filterAttrs (n: v:
versionSpecMatches v.version versionSpec) nameMatches;
semver.satisfies v.version versionSpec) nameMatches;
matchPairs = lib.mapAttrsToList (name: value:
{inherit name; version = value.version;}) matches;
sorted = builtins.sort (a: b:
Expand Down

0 comments on commit 4f2b6c9

Please sign in to comment.