summary refs log tree commit diff
path: root/pkgs/development/tools/poetry2nix/poetry2nix/semver.nix
blob: 07dcbbc5eacb3a5a92963cb835a15165f8a3e2bf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{ lib, ireplace }:
let
  inherit (builtins) elemAt match;

  operators = let
    matchWildCard = s: match "([^\*])(\.[\*])" s;
    mkComparison = ret: version: v: builtins.compareVersions version v == ret;
    mkIdxComparison = idx: version: v:
      let
        ver = builtins.splitVersion v;
        minor = builtins.toString (lib.toInt (elemAt ver idx) + 1);
        upper = builtins.concatStringsSep "." (ireplace idx minor ver);
      in
        operators.">=" version v && operators."<" version upper;
    dropWildcardPrecision = f: version: constraint:
      let
        m = matchWildCard constraint;
        hasWildcard = m != null;
        c = if hasWildcard then (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;
      # Semver specific operators
      "~" = mkIdxComparison 1;
      "^" = mkIdxComparison 0;
      "~=" = v: c:
        let
          # Prune constraint
          parts = builtins.splitVersion c;
          pruned = lib.take ((builtins.length parts) - 1) parts;
          upper = builtins.toString (
            (lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1
          );
          upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned);
        in
          operators.">=" v c && operators."<" v upperConstraint;
      # Infix operators
      "-" = version: v: operators.">=" version v.vl && operators."<=" version v.vu;
      # Arbitrary equality clause, just run simple comparison
      "===" = v: c: v == c;
      #
    };

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

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

  satisfiesSemver = version: constraint:
    let
      inherit (parseConstraint constraint) op v;
    in
      if constraint == "*" then true else operators."${op}" version v;
in
{ inherit satisfiesSemver; }