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
|
(**************************************************************************)
(* Copyright © 2009 Stéphane Glondu <steph@glondu.net> *)
(* *)
(* This program is free software: you can redistribute it and/or modify *)
(* it under the terms of the GNU Affero General Public License as *)
(* published by the Free Software Foundation, either version 3 of the *)
(* License, or (at your option) any later version, with the additional *)
(* exemption that compiling, linking, and/or using OpenSSL is allowed. *)
(* *)
(* This program is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *)
(* Affero General Public License for more details. *)
(* *)
(* You should have received a copy of the GNU Affero General Public *)
(* License along with this program. If not, see *)
(* <http://www.gnu.org/licenses/>. *)
(**************************************************************************)
open Printf
open Benl_error
open Benl_types
open Benl_base
type t = Benl_types.expr
let rec simplify query = match query with
| EMatch (field, EString package) ->
begin match (Benl_core.simple_split '|' package) with
| package::[] -> query
| packages ->
let packages = List.map Re_pcre.quote packages in
let r_string = String.concat "|" packages in
let rex = Re_pcre.regexp (Printf.sprintf "\b(%s)\b" r_string) in
EMatch (field, ERegexp (package, rex))
end
| EMatch (_, (EDep _ | ERegexp _)) -> query
| Etrue | Efalse | ESource | EVersion _ | EString _ | ERegexp _ | EDep _ -> query
| EMatch (f, e) -> EMatch (f, simplify e)
| EList l -> begin match l with
| [] -> Etrue
| h::[] -> simplify h
| _::_ -> EList (List.map simplify l)
end
| ENot e -> begin match (simplify e) with
| Etrue -> Efalse
| Efalse -> Etrue
| e -> ENot e
end
| EOr (e1, e2) -> begin match (simplify e1, simplify e2) with
| Efalse, e | e, Efalse -> e
| Etrue, _ | _, Etrue -> Etrue
| e1, e2 -> EOr (e1, e2)
end
| EAnd (e1, e2) -> begin match (simplify e1, simplify e2) with
| Efalse, e | e, Efalse -> Efalse
| Etrue, e | e, Etrue -> e
| e1, e2 -> EAnd (e1, e2)
end
let of_expr x = simplify x
let of_string s =
let lexbuf = Lexing.from_string s in
simplify (Benl_parser.full_expr Benl_lexer.token lexbuf)
let parens show expr =
if show
then sprintf "(%s)" expr
else expr
let rec to_string_b ?(escape = true) last_op = function
| EMatch (f, ERegexp r) ->
sprintf ".%s ~ %s" f (string_of_regexp r)
| ENot e ->
sprintf "!%s" (to_string_b "!" e)
| Etrue -> sprintf "true"
| Efalse -> sprintf "false"
| EAnd (e1, e2) ->
parens
(last_op <> "&" && last_op <> "")
(sprintf "%s & %s" (to_string_b "&" e1) (to_string_b "&" e2))
| EOr (e1, e2) ->
parens
(last_op <> "|" && last_op <> "")
(sprintf "%s | %s" (to_string_b "|" e1) (to_string_b "|" e2))
| EList xs ->
sprintf "[%s]" (String.concat "; " (List.map (to_string_b "") xs))
| ESource -> "source"
| EString x -> string_of_string escape x
| EVersion (cmp, x) ->
parens (last_op <> "") (sprintf ".%s \"%s\"" (string_of_cmp cmp) x)
| EMatch (field, EDep (package, cmp, ref_version)) ->
parens (last_op <> "") (sprintf ".%s ~ \"%s\" %s \"%s\""
field
package
(string_of_cmp cmp)
ref_version)
| EMatch (field, EString package) ->
parens (last_op <> "") (sprintf ".%s ~ \"%s\"" field package)
| x -> raise (Unexpected_expression "<unable to convert to string>")
let to_string ?(escape = true) = to_string_b ~escape ""
let rec eval kind pkg = function
| EMatch (field, ERegexp (r, rex)) ->
begin try
let value = Package.get field pkg in
ignore (Re_pcre.exec ~rex value);
true
with Not_found ->
false
end
| Etrue -> true
| Efalse -> false
| ESource ->
kind = `source
| EOr (e1, e2) ->
eval kind pkg e1 || eval kind pkg e2
| EAnd (e1, e2) ->
eval kind pkg e1 && eval kind pkg e2
| ENot e ->
not (eval kind pkg e)
| EVersion (cmp, ref_version) ->
let value = Package.get "version" pkg in
version_compare cmp value ref_version
| EMatch (field, EDep (package, cmp, refv)) ->
let deps = Package.dependencies field pkg in
List.exists
(fun x ->
x.Package.dep_name = package && begin
match x.Package.dep_version with
| None -> false
| Some (rcmp, rrefv) ->
match rcmp, cmp with
| Ge, Ge | Gt, Ge | Gt, Gt -> Version.compare rrefv refv >= 0
| Ge, Gt -> Version.compare rrefv refv > 0
| _, _ -> false (* FIXME: missing cases *)
end)
deps
| EMatch (field, EString package) ->
begin try
let deps = Package.dependencies field pkg in
List.exists
(fun x -> x.Package.dep_name = package)
deps
with Not_found ->
false
end
| x ->
raise (Unexpected_expression (to_string x))
let eval_source x = eval `source x
let eval_binary x = eval `binary x
let rec fields accu = function
| EMatch (f, _) ->
Fields.add f accu
| ENot e ->
fields accu e
| Etrue | Efalse -> accu
| EAnd (e1, e2) | EOr (e1, e2) ->
fields (fields accu e1) e2
| EList xs ->
List.fold_left fields accu xs
| ESource | EString _ | ERegexp _ | EDep _ ->
accu
| EVersion _ ->
Fields.add "version" accu
|