package dose3

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

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
(**************************************************************************************)
(*  Copyright (C) 2009-2015 Pietro Abate <pietro.abate@pps.univ-paris-diderot.fr>     *)
(*  Copyright (C) 2009 Mancoosi Project                                               *)
(*                                                                                    *)
(*  This library is free software: you can redistribute it and/or modify              *)
(*  it under the terms of the GNU Lesser General Public License as                    *)
(*  published by the Free Software Foundation, either version 3 of the                *)
(*  License, or (at your option) any later version.  A special linking                *)
(*  exception to the GNU Lesser General Public License applies to this                *)
(*  library, see the COPYING file for more information.                               *)
(**************************************************************************************)

(** 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) =
  (* if x = "" then this is intepreted as a partial version and converted to 0 *)
  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*"
   (* optional version identifier *)
   ^ "([0-9]+|[xX*])(\\.([0-9]+|[xX*])?(\\.([0-9]+|[xX*])?)?)?"
    (* 3-dotted notation *)
    ^ "(?:-((?:[a-zA-Z0-9]+|[a-zA-Z0-9-])(?:\\.[a-zA-Z0-9]+|[a-zA-Z0-9-])*))?"
    ^ (* pre release *)
    "(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?\\s*$" (* build indentifier *)
    )

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))

(*Compare  two elements of the prerelease part of a 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

(* 1. Not having a prerelease is > that having one
   2. We compare each pre-release, the one with with less elements win or the
      one with a hight element. *)
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
OCaml

Innovation. Community. Security.