File: evolution.ml

package info (click to toggle)
dose3 3.3~beta1-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,936 kB
  • ctags: 2,055
  • sloc: ml: 12,421; ansic: 433; makefile: 332; python: 164; perl: 139; sh: 43
file content (192 lines) | stat: -rw-r--r-- 6,464 bytes parent folder | download | duplicates (2)
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
(**************************************************************************************)
(*  Copyright (C) 2011 Pietro Abate                                                   *)
(*  Copyright (C) 2011 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.                               *)
(**************************************************************************************)

open ExtLib
open Common

type range = [
    `Hi of string
  | `In of (string * string)
  | `Lo of string 
  | `Eq of string
]

let string_of_range = function
  |`Hi v -> Printf.sprintf "%s < ." v
  |`Lo v -> Printf.sprintf ". < %s" v
  |`Eq v -> Printf.sprintf "= %s" v
  |`In (v1,v2) -> Printf.sprintf "%s < . < %s" v1 v2
;;

(* returns a list of ranges w.r.t. the list of versions vl *)
(* the range is a [ ... [ kind of interval *)
let range ?(bottom=false) vl =
  let l = List.sort ~cmp:(fun v1 v2 -> Version.compare v2 v1) vl in
  let rec aux acc = function
    |(None,[]) -> acc
    |(None,a::t) -> aux ((`Hi a)::acc) (Some a,t)
    |(Some b,a::t) -> aux ((`In (a,b))::(`Eq b)::acc) (Some a,t)
    |(Some b,[]) when bottom = false -> (`Eq b)::acc 
    |(Some b,[]) -> (`Lo b)::(`Eq b)::acc 
  in
  aux [] (None,l)
;;

(** [discriminants ?bottom ?ascending evalsel vl constraints]
   returns the discriminants of the versions [vl] w.r.t.
   the [constraints], using [evalsel] to determine whether a
   a version satisfy a constraint.
   For each discriminant, a canonical representative is given,
   as well as the list of all other equivalent versions.
   @param bottom set to true includes a version strictly smaller than all [vl] 
   @param highest chooses the highest version as representative, if set to true,
                      and the lowest otherwise.
 *)
let discriminant ?(bottom=false) ?(highest=true) evalsel vl constraints =
  let eval_constr = Hashtbl.create 17 in
  let constr_eval = Hashtbl.create 17 in
  let candidates = range ~bottom vl in
  List.iter (fun target ->
    let eval = List.map (evalsel target) constraints in
    try
      let v_rep = Hashtbl.find eval_constr eval in
      let l = Hashtbl.find constr_eval v_rep in
      Hashtbl.replace constr_eval v_rep (target::l)
    with Not_found -> begin
      Hashtbl.add eval_constr eval target;
      Hashtbl.add constr_eval target []
    end
  ) (if highest then List.rev candidates else candidates) ;
  (Hashtbl.fold (fun k v acc -> (k,v)::acc) constr_eval [])
;;

let add_unique h k v =
  try
    let vh = Hashtbl.find h k in
    if not (Hashtbl.mem vh v) then
      Hashtbl.add vh v ()
  with Not_found -> begin
    let vh = Hashtbl.create 17 in
    Hashtbl.add vh v ();
    Hashtbl.add h k vh
  end

(* collect dependency information *)
let conj_iter t l =
  List.iter (fun ((name,_),sel) ->
    match CudfAdd.cudfop sel with
    |None -> add_unique t name None
    |Some(c,v) -> add_unique t name (Some(c,v))
  ) l
let cnf_iter t ll = List.iter (conj_iter t) ll

(** [constraints universe] returns a map between package names
    and an ordered list of constraints where the package name is
    mentioned *)
let constraints packagelist =
  let constraints_table = Hashtbl.create (List.length packagelist) in
  List.iter (fun pkg ->
    (* add_unique constraints_table pkg.Packages.name None; *)
    conj_iter constraints_table pkg.Packages.conflicts ;
    conj_iter constraints_table pkg.Packages.breaks ;
    conj_iter constraints_table pkg.Packages.provides ;
    cnf_iter constraints_table pkg.Packages.depends;
    cnf_iter constraints_table pkg.Packages.pre_depends
  ) packagelist
  ;
  let h = Hashtbl.create (List.length packagelist) in
  let elements hv =
    let cmp (_,v1) (_,v2) = Version.compare v2 v1 in
    List.sort ~cmp (
      Hashtbl.fold (fun k _ acc ->
        match k with
        |None -> acc 
        |Some k -> k::acc
      ) hv []
    )
  in
  Hashtbl.iter (fun n hv -> Hashtbl.add h n (elements hv)) constraints_table;
  h
;;

let all_constraints table pkgname =
  try (Hashtbl.find table pkgname)
  with Not_found -> []
;;

(* return a new target rebased accordingly to the epoch of the base version *)
let align version target =
  match Version.split version  with
  |("",_,_,_) -> target
  |(pe,_,_,_) ->
    let rebase v =
      let (_,u,r,b) = Version.split v in
      Version.concat (pe,u,r,b)
    in
    match target with
    |`Eq v -> `Eq (rebase v)
    |`Hi v -> `Hi (rebase v)
    |`Lo v -> `Lo (rebase v)
    |`In (v,w) -> `In (rebase v,rebase w)
;;

(* all versions mentioned in a list of constraints *)
let all_versions constr = Util.list_unique (List.map (snd) constr) ;;

let migrate packagelist target =
  List.map (fun pkg -> ((pkg,target),(align pkg.Packages.version target))) packagelist
;;

let extract_epochs vl =
  Util.list_unique (
    List.fold_left (fun acc v ->
      let (e,_,_,_) = Version.split v in
      e :: acc
    ) [] vl
  )
;;

let add_normalize vl =
  List.fold_left (fun acc v ->
    let (e,u,r,b) = Version.split v in
    let n1 = Version.concat ("",u,r,"") in
    let n2 = Version.concat ("",u,r,b) in
    n1::n2::v::acc
  ) [] vl
;;

let add_epochs el vl =
  List.fold_left (fun acc1 e ->
    List.fold_left (fun acc2 v ->
      match Version.split v with
      |("",u,r,b) -> (Version.concat (e,u,r,b))::v::acc2
      |_ -> v::acc2
    ) acc1 vl
  ) [] el
;;

let all_ver_constr constraints_table cluster =
  let (versionlist, constr) =
    List.fold_left (fun (_vl,_cl) pkg ->
      let pn = pkg.Packages.name in
      let pv = pkg.Packages.version in
      let constr = all_constraints constraints_table pn in
      let vl = pv::(all_versions constr) in
      (vl @ _vl,constr @ _cl)
    ) ([],[]) cluster
  in
  let all_epochs = extract_epochs versionlist in
  let all_norm = add_normalize versionlist in
  let versionlist = add_epochs all_epochs all_norm in
  (Util.list_unique versionlist,Util.list_unique constr)
;;