Source file semverNode.ml
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
(** this functions follow the semantic versioning specification http://semver.org/
* and node's https://docs.npmjs.com/misc/semver.
* *)
module Pcre = Re_pcre
open Dose_common
include Util.Logging (struct
let label = "dose_versioning.semverNode"
end)
type raw_version = string * string * string * string list * string list
type ident = S of string | N of int
type version =
{ major : int;
minor : int;
patch : int;
pre : ident list;
build : string list
}
let compose_raw (major, minor, patch, pre, build) =
let str =
match (major, minor, patch) with
| ("", "", "") -> Printf.sprintf "*"
| (_, "", "") -> Printf.sprintf "%s" major
| (_, _, "") -> Printf.sprintf "%s.%s" major minor
| (_, _, _) -> Printf.sprintf "%s.%s.%s" major minor patch
in
let str_pre l = String.concat "." l in
let str_build l = String.concat "." l in
match (pre, build) with
| ([], []) -> str
| (l, []) -> Printf.sprintf "%s-%s" str (str_pre l)
| ([], l) -> Printf.sprintf "%s+%s" str (str_build l)
| (lp, lb) -> Printf.sprintf "%s-%s+%s" str (str_pre lp) (str_build lb)
let convert ((major, minor, patch, pre, build) as raw) =
let c_int = function
| "" -> 0
| "x" | "X" ->
let composed = compose_raw raw in
raise
(Invalid_argument
(Printf.sprintf
"'%s': Conversion Error: 'X' or 'x' cannot be converted to an \
integer"
composed))
| s -> (
try int_of_string s
with Failure _ ->
let composed = compose_raw raw in
raise
(Invalid_argument
(Printf.sprintf
"%s: Conversion Error: \"%s\" cannot be converted to an \
integer"
composed
s)))
in
let c_pre x = try N (int_of_string x) with Failure _ -> S x in
{ major = c_int major;
minor = c_int minor;
patch = c_int patch;
pre = List.map c_pre pre;
build
}
let compose v =
let str = Printf.sprintf "%d.%d.%d" v.major v.minor v.patch in
let str_pre l =
String.concat
"."
(List.map (function N i -> string_of_int i | S s -> s) l)
in
let str_build l = String.concat "." l in
match (v.pre, v.build) with
| ([], []) -> str
| (l, []) -> Printf.sprintf "%s-%s" str (str_pre l)
| ([], l) -> Printf.sprintf "%s+%s" str (str_build l)
| (lp, lb) -> Printf.sprintf "%s-%s+%s" str (str_pre lp) (str_build lb)
let rex =
Pcre.regexp
("^\\s*[v=]*\\s*"
^ "([0-9]+|[xX*])(\\.([0-9]+|[xX*])?(\\.([0-9]+|[xX*])?)?)?"
^ "(?:-((?:[a-zA-Z0-9]+|[a-zA-Z0-9-])(?:\\.[a-zA-Z0-9]+|[a-zA-Z0-9-])*))?"
^
"(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?\\s*$"
)
let sep_re = Pcre.regexp "\\."
let parse_raw_version version =
try
let parsed = Pcre.extract ~rex version in
let pre = Pcre.split ~rex:sep_re parsed.(6) in
let build = Pcre.split ~rex:sep_re parsed.(7) in
(parsed.(1), parsed.(3), parsed.(5), pre, build)
with Not_found ->
raise
(Invalid_argument
(Printf.sprintf "%s: Parsing Error. Invalid Version" version))
let parse_version version =
try convert (parse_raw_version version)
with Invalid_argument _ ->
raise
(Invalid_argument
(Printf.sprintf "%s: Conversion Error. Invalid Version" version))
let compare_pre = function
| (N x1, N y1) -> Stdlib.compare x1 y1
| (S _, N _) -> 1
| (N _, S _) -> -1
| (S s1, S s2) -> String.compare s1 s2
let compare_pre (l1, l2) =
let lenl1 = List.length l1 in
let lenl2 = List.length l2 in
if lenl1 = 0 && lenl2 = 0 then 0
else if lenl1 <> 0 && lenl2 = 0 then -1
else if lenl1 = 0 && lenl2 <> 0 then 1
else if lenl1 = 0 && lenl2 = 0 then 0
else
let rec check acc = function
| ([], []) -> acc
| (_ :: l1, [_]) when l1 <> [] -> 1
| ([_], _ :: l2) when l2 <> [] -> -1
| (x1 :: l1, x2 :: l2) when x1 = x2 -> check 0 (l1, l2)
| (x1 :: _, x2 :: _) -> compare_pre (x1, x2)
| (_, _) -> assert false
in
check 0 (l1, l2)
let compare_version x y =
let res x = if x = 0 then 0 else if x < 0 then -1 else 1 in
let c1 = Stdlib.compare x.major y.major in
if c1 <> 0 then res c1
else
let c2 = Stdlib.compare x.minor y.minor in
if c2 <> 0 then res c2
else
let c3 = Stdlib.compare x.patch y.patch in
if c3 <> 0 then res c3 else compare_pre (x.pre, y.pre)
let parse_and_compare x y =
if x = y then 0
else
let v1 = parse_version x in
let v2 = parse_version y in
compare_version v1 v2
let compare x y = parse_and_compare x y
let equal x y = compare x y = 0