package dose3-extra

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

Source file packages.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
(******************************************************************************)
(*  This file is part of the Dose library http://www.irill.org/software/dose  *)
(*                                                                            *)
(*  Copyright (C) 2009-2015 Pietro Abate <pietro.abate@pps.jussieu.fr>        *)
(*                                                                            *)
(*  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.                       *)
(*                                                                            *)
(*  Work developed with the support of the Mancoosi Project                   *)
(*  http://www.mancoosi.org                                                   *)
(*                                                                            *)
(******************************************************************************)

open ExtLib
open Dose_common
open Dose_extra

include Util.Logging (struct
  let label = "dose_opam.packages"
end)

type options =
  Dose_pef.Packages_types.architecture
  * Dose_pef.Packages_types.architecture list
  * Dose_pef.Packages_types.buildprofile list

type request =
  { install : Dose_pef.Packages_types.vpkg list;
    remove : Dose_pef.Packages_types.vpkg list;
    upgrade : Dose_pef.Packages_types.vpkg list;
    dist_upgrade : bool;
    switch : string;
    switches : string list;
    profiles : string list;
    preferences : string
  }

let default_request =
  { install = [];
    remove = [];
    upgrade = [];
    dist_upgrade = false;
    switch = "";
    switches = [];
    profiles = [];
    preferences = ""
  }

let matchswitch switches = function
  | [] -> true
  | (true, _) :: _ as al -> List.exists (fun (_, a) -> List.mem a switches) al
  | (false, _) :: _ as al ->
      List.for_all (fun (_, a) -> not (List.mem a switches)) al

let matchos profiles = function
  | [] -> true
  | ll -> List.exists (List.for_all (fun (c, p) -> c = List.mem p profiles)) ll

let select (switch, switches, profiles) (v, al, pl) =
  if matchswitch (switch :: switches) al && matchos profiles pl then [v] else []

let vpkglist_filter options l = List.flatten (List.map (select options) l)

let vpkgformula_filter options ll =
  List.filter_map
    (fun l -> match vpkglist_filter options l with [] -> None | l -> Some l)
    ll

let parse_req =
  Dose_pef.Packages.lexbuf_wrapper Dose_pef.Packages_parser.vpkglist_top

let parse_request_stanza par =
  try
    { install = Dose_pef.Packages.parse_s ~default:[] parse_req "install" par;
      remove = Dose_pef.Packages.parse_s ~default:[] parse_req "remove" par;
      upgrade = Dose_pef.Packages.parse_s ~default:[] parse_req "upgrade" par;
      dist_upgrade =
        Dose_pef.Packages.parse_s
          ~default:false
          Dose_pef.Packages.parse_bool
          "dist_upgrade"
          par;
      switch =
        Dose_pef.Packages.parse_s
          ~required:true
          Dose_pef.Packages.parse_string
          "switch"
          par;
      switches =
        Dose_pef.Packages.parse_s
          ~default:[]
          Dose_pef.Packages.parse_string_list
          "switches"
          par;
      profiles =
        Dose_pef.Packages.parse_s
          ~default:[]
          Dose_pef.Packages.parse_string_list
          "profiles"
          par;
      preferences =
        Dose_pef.Packages.parse_s
          ~default:""
          Dose_pef.Packages.parse_string
          "preferences"
          par
    }
  with Format822.ParseError (cl, f, err) ->
    let c = "Parser Error in Preamble" in
    raise (Format822.ParseError (c :: cl, f, err))

class package ?(name = ("package", None)) ?(version = ("version", None))
  ?(depends = ("depends", None)) ?(conflicts = ("conflicts", None))
  ?(provides = ("provides", None)) ?(depopts = ("depopts", None))
  ?(switch = ("switches", None)) ?(installedlist = ("installed", None))
  ?(pinnedlist = ("pinned", None)) ?(baselist = ("base", None))
  ?(extras = ([], None)) par =
  object
    inherit
      Dose_pef.Packages.package
        ~name
        ~version
        ~depends
        ~conflicts
        ~provides
        ~recommends:depopts
        ~extras
        par

    val switch : string * string list =
      let p =
        Dose_pef.Packages.parse_string_list ~rex:Dose_pef.Packages.comma_regexp
      in
      let parse = Dose_pef.Packages.parse_s ~default:["all"] p in
      Dose_pef.Packages.get_field_value ~parse ~par ~field:switch

    val installedlist : string * string list =
      let p =
        Dose_pef.Packages.parse_string_list ~rex:Dose_pef.Packages.comma_regexp
      in
      let parse = Dose_pef.Packages.parse_s ~default:[] p in
      Dose_pef.Packages.get_field_value ~parse ~par ~field:installedlist

    val baselist : string * string list =
      let p =
        Dose_pef.Packages.parse_string_list ~rex:Dose_pef.Packages.comma_regexp
      in
      let parse = Dose_pef.Packages.parse_s ~default:[] p in
      Dose_pef.Packages.get_field_value ~parse ~par ~field:baselist

    val pinnedlist : string * string list =
      let p =
        Dose_pef.Packages.parse_string_list ~rex:Dose_pef.Packages.comma_regexp
      in
      let parse = Dose_pef.Packages.parse_s ~default:[] p in
      Dose_pef.Packages.get_field_value ~parse ~par ~field:pinnedlist

    method switch = snd switch

    method installedlist = snd installedlist

    method baselist = snd baselist

    method pinnedlist = snd pinnedlist

    method depopts = snd recommends

    method! pp oc =
      Dose_pef.Printer.pp_string_wl oc name ;
      Dose_pef.Printer.pp_string_wl oc version ;
      Dose_pef.Printer.pp_string_list_wl oc switch ;
      Dose_pef.Printer.pp_string_list_wl oc installedlist ;
      Dose_pef.Printer.pp_string_list_wl oc pinnedlist ;
      Dose_pef.Printer.pp_string_list_wl oc baselist ;
      Dose_pef.Printer.pp_vpkglist_wl oc provides ;
      Dose_pef.Printer.pp_vpkgformula_wl oc depends ;
      Dose_pef.Printer.pp_vpkgformula_wl oc recommends ;
      Dose_pef.Printer.pp_vpkglist_wl oc conflicts ;
      Printf.fprintf oc "\n"
  end

(* a stanza is not considered if the intersection between the
   active switch and the not available switches for a package is
   empty *)
let parse_package_stanza ((switch, switches, _profiles) as options)
    ?(extras = []) par =
  try
    let pkg_switch =
      let p =
        Dose_pef.Packages.parse_string_list ~rex:Dose_pef.Packages.comma_regexp
      in
      let f = Dose_pef.Packages.parse_s ~default:["all"] p in
      f "switches" par
    in
    if
      not
        (List.mem "all" pkg_switch
        || List.exists (fun s -> List.mem s pkg_switch) (switch :: switches))
    then
      raise
        (Dose_pef.Packages.IgnorePackage
           (Printf.sprintf
              "None of the active switches [%s] are available [%s]"
              (ExtString.String.join "," (switch :: switches))
              (ExtString.String.join "," pkg_switch)))
    else
      let pkg =
        let depends =
          let f =
            Dose_pef.Packages.parse_s
              ~default:[]
              Dose_pef.Packages.parse_builddepsformula
          in
          ("depends", Some (vpkgformula_filter options (f "depends" par)))
        in
        let depopts =
          let f =
            Dose_pef.Packages.parse_s
              ~default:[]
              Dose_pef.Packages.parse_builddepsformula
          in
          ("depopts", Some (vpkgformula_filter options (f "depopts" par)))
        in
        let conflicts =
          let f =
            Dose_pef.Packages.parse_s
              ~default:[]
              Dose_pef.Packages.parse_builddepslist
          in
          ("conflicts", Some (vpkglist_filter options (f "conflicts" par)))
        in
        let provides =
          let f =
            Dose_pef.Packages.parse_s
              ~default:[]
              Dose_pef.Packages.parse_builddepslist
          in
          ("provides", Some (vpkglist_filter options (f "provides" par)))
        in
        (* let extras = List.map (fun (f,v) -> (f,(Format822.dummy_loc,v))) extras in *)
        new package
          ~depends
          ~conflicts
          ~provides
          ~depopts
          ~extras:(extras, None)
          par
      in
      Some pkg
  with
  | Dose_pef.Packages.IgnorePackage s ->
      let n =
        Dose_pef.Packages.parse_s
          ~default:"?"
          Dose_pef.Packages.parse_name
          "package"
          par
      in
      let v =
        Dose_pef.Packages.parse_s
          ~default:"?"
          Dose_pef.Packages.parse_version
          "version"
          par
      in
      warning "Ignoring Package (%s,%s) : %s" n v s ;
      None
  | Format822.ParseError (cl, f, err) ->
      let n =
        Dose_pef.Packages.parse_s
          ~default:"?"
          Dose_pef.Packages.parse_name
          "package"
          par
      in
      let v =
        Dose_pef.Packages.parse_s
          ~default:"?"
          Dose_pef.Packages.parse_version
          "version"
          par
      in
      let c = Printf.sprintf "Parser Error in Package (%s,%s)" n v in
      raise (Format822.ParseError (c :: cl, f, err))

(* parse the entire file while filtering out unwanted stanzas.
 * Depopts is alsways false while parsing opam files *)
let rec packages_parser ?(request = false) (req, acc) p =
  let options = (req.switch, req.switches, req.profiles) in
  match
    Format822_parser.stanza_822 Format822_lexer.token_822 p.Format822.lexbuf
  with
  | None -> (req, acc) (* end of file *)
  | Some stanza when request = true ->
      let req = parse_request_stanza stanza in
      packages_parser (req, acc) p
  | Some stanza -> (
      match parse_package_stanza options stanza with
      | None -> packages_parser (req, acc) p
      | Some st -> packages_parser (req, st :: acc) p)

(* this function raise Format822.ParseError *)
let input_raw_in ic =
  Format822.parse_from_ch
    (packages_parser ~request:true (default_request, []))
    ic

let input_raw file =
  try
    let ch =
      match file with
      | "-" -> IO.input_channel stdin
      | _ -> Input.open_file file
    in
    let l = input_raw_in ch in
    let _ = Input.close_ch ch in
    l
  with
  | Input.File_empty -> (default_request, [])
  | Format822.ParseError (cl, field, errmsg) ->
      fatal
        "Filename %s\n %s\n %s : %s"
        file
        (String.concat "\n " cl)
        field
        errmsg
OCaml

Innovation. Community. Security.