Skip to content

Commit

Permalink
Add enabled_if to aliases/tests
Browse files Browse the repository at this point in the history
This field controls whether the alias/test will be run or not. Boolean
expressions are defined using the Blang.t type. This type represents simple
boolean expressions that become useful when we allow to interpolate variables
into them.

Signed-off-by: Rudi Grinberg <rudi.grinberg@gmail.com>
  • Loading branch information
rgrinberg committed Jul 31, 2018
1 parent e59feac commit 3d9612f
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 48 deletions.
34 changes: 34 additions & 0 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,10 @@ The syntax is as follows:
- ``(locks (<lock-names>))`` specify that the action must be run while
holding the following locks. See the `Locks`_ section for more details.

- ``(enabled_if <blang expression>)`` specifies the boolean condition that must
be true for the tests to run. The condition is specified using the blang_, and
the field allows for variables_ to appear in the expressions.

The typical use of the ``alias`` stanza is to define tests:

.. code:: scheme
Expand Down Expand Up @@ -824,6 +828,36 @@ doesn't start by `-`, you can simply quote it: ``("x" y z)``.
Most fields using the ordered set language also support `Variables expansion`_.
Variables are expanded after the set language is interpreted.

.. _blang:

Boolean Language
----------------

The boolean language allows the user to define simple boolean expressions that
dune can evaluate. Here's a semi formal specification of the language:

.. code::
op := '=' | '<' | '>' | '<>' | '>=' | '<='
expr := (and <expr>+)
| (or <expr>+)
| (<op> <template> <template>)
| <template>
After an expression is evaluated, it must be exactly the string ``true`` or
``false`` to be considered as a boolean. Any other value will be treated as an
error.

Here's a simple example of a condition that expresses running on OSX and having
an flambda compiler with the help of variable expansion:

.. code:: scheme
(and %{ocamlc-config:flambda} (= %{ocamlc-config:system} macosx))
.. _variables:

Variables expansion
-------------------

Expand Down
45 changes: 45 additions & 0 deletions src/blang.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
open! Stdune

module Op = struct
type t =
| Eq
| Gt
| Gte
| Lte
| Lt
| Neq

let eval t (x : Ordering.t) =
match t, x with
| (Eq | Gte | Lte) , Eq
| (Lt | Lte) , Lt
| (Gt | Gte) , Gt -> true
| _, _ -> false
end

type 'a t =
| Expr of 'a
| And of 'a t list
| Or of 'a t list
| Compare of Op.t * 'a * 'a

type 'a expander =
{ f : 'value. mode:'value String_with_vars.Mode.t
-> 'a
-> Loc.t * 'value
}

let rec eval_bool t ~dir ~(f : 'a expander) =
match t with
| Expr a ->
begin match f.f ~mode:Single a with
| _, String "true" -> true
| _, String "false" -> false
| loc, _ -> Loc.fail loc "This value must be either true or false"
end
| And xs -> List.for_all ~f:(eval_bool ~f ~dir) xs
| Or xs -> List.exists ~f:(eval_bool ~f ~dir) xs
| Compare (op, x, y) ->
let ((_, x), (_, y)) = (f.f ~mode:Many x, f.f ~mode:Many y) in
Value.L.compare_vals ~dir x y
|> Op.eval op
25 changes: 25 additions & 0 deletions src/blang.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
open Stdune

module Op : sig
type t =
| Eq
| Gt
| Gte
| Lte
| Lt
| Neq
end

type 'a t =
| Expr of 'a
| And of 'a t list
| Or of 'a t list
| Compare of Op.t * 'a * 'a

type 'a expander =
{ f : 'value. mode:'value String_with_vars.Mode.t
-> 'a
-> Loc.t * 'value
}

val eval_bool : 'a t -> dir:Path.t -> f:'a expander -> bool
1 change: 1 addition & 0 deletions src/gen_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ module Gen(P : Install_rules.Params) = struct
; package = t.package
; deps = t.deps
; action = None
; enabled_if = t.enabled_if
} in
match test_kind (loc, s) with
| `Regular ->
Expand Down
73 changes: 59 additions & 14 deletions src/jbuild.ml
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ module Dep_conf = struct
; "universe" , return Universe
; "files_recursively_in",
(let%map () =
Syntax.renamed_in Stanza.syntax (1, 0) ~to_:"source_tree"
Syntax.renamed_in Stanza.syntax (1, 0) ~to_:"source_tree"
and x = sw in
Source_tree x)
; "source_tree",
Expand Down Expand Up @@ -378,6 +378,45 @@ module Preprocess = struct
| _ -> []
end

module Blang = struct
type 'a t = 'a Blang.t

open Blang
let ops =
[ "=", Op.Eq
; ">=", Gte
; "<=", Lt
; ">", Gt
; "<", Lt
; "<>", Neq
]

let t =
let ops =
List.map ops ~f:(fun (name, op) ->
( name
, (let%map x = String_with_vars.t
and y = String_with_vars.t
in
Compare (op, x, y))))
in
let t =
fix begin fun (t : String_with_vars.t Blang.t Sexp.Of_sexp.t) ->
if_list
~then_:(
[ "or", repeat t >>| (fun x -> Or x)
; "and", repeat t >>| (fun x -> And x)
] @ ops
|> sum)
~else_:(String_with_vars.t >>| fun v -> Expr v)
end
in
let%map () = Syntax.since Stanza.syntax (1, 1)
and t = t
in
t
end

module Per_module = struct
include Per_item.Make(Module.Name)

Expand Down Expand Up @@ -1336,15 +1375,15 @@ module Rule = struct
let dune_syntax =
peek_exn >>= function
| List (_, Atom (loc, A s) :: _) -> begin
match String.Map.find atom_table s with
| None ->
of_sexp_errorf loc ~hint:{ on = s
; candidates = String.Map.keys atom_table
}
"Unknown action or rule field."
| Some Field -> fields long_form
| Some Action -> short_form
end
match String.Map.find atom_table s with
| None ->
of_sexp_errorf loc ~hint:{ on = s
; candidates = String.Map.keys atom_table
}
"Unknown action or rule field."
| Some Field -> fields long_form
| Some Action -> short_form
end
| sexp ->
of_sexp_errorf (Sexp.Ast.loc sexp)
"S-expression of the form (<atom> ...) expected"
Expand Down Expand Up @@ -1500,6 +1539,7 @@ module Alias_conf = struct
; action : (Loc.t * Action.Unexpanded.t) option
; locks : String_with_vars.t list
; package : Package.t option
; enabled_if : String_with_vars.t Blang.t option
}

let alias_name =
Expand All @@ -1516,21 +1556,24 @@ module Alias_conf = struct
and action = field_o "action" (located Action.Unexpanded.t)
and locks = field "locks" (list String_with_vars.t) ~default:[]
and deps = field "deps" (Bindings.t Dep_conf.t) ~default:Bindings.empty
and enabled_if = field_o "enabled_if" Blang.t
in
{ name
; deps
; action
; package
; locks
; enabled_if
})
end

module Tests = struct
type t =
{ exes : Executables.t
; locks : String_with_vars.t list
; package : Package.t option
; deps : Dep_conf.t Bindings.t
{ exes : Executables.t
; locks : String_with_vars.t list
; package : Package.t option
; deps : Dep_conf.t Bindings.t
; enabled_if : String_with_vars.t Blang.t option
}

let gen_parse names =
Expand All @@ -1543,6 +1586,7 @@ module Tests = struct
and modes = field "modes" Executables.Link_mode.Set.t
~default:Executables.Link_mode.Set.default
and deps = field "deps" (Bindings.t Dep_conf.t) ~default:Bindings.empty
and enabled_if = field_o "enabled_if" Blang.t
in
{ exes =
{ Executables.
Expand All @@ -1555,6 +1599,7 @@ module Tests = struct
; locks
; package
; deps
; enabled_if
})

let multi = gen_parse (field "names" (list (located string)))
Expand Down
10 changes: 6 additions & 4 deletions src/jbuild.mli
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ module Alias_conf : sig
; action : (Loc.t * Action.Unexpanded.t) option
; locks : String_with_vars.t list
; package : Package.t option
; enabled_if : String_with_vars.t Blang.t option
}
end

Expand All @@ -355,10 +356,11 @@ end

module Tests : sig
type t =
{ exes : Executables.t
; locks : String_with_vars.t list
; package : Package.t option
; deps : Dep_conf.t Bindings.t
{ exes : Executables.t
; locks : String_with_vars.t list
; package : Package.t option
; deps : Dep_conf.t Bindings.t
; enabled_if : String_with_vars.t Blang.t option
}
end

Expand Down
69 changes: 41 additions & 28 deletions src/simple_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -70,32 +70,45 @@ let add_alias sctx ~dir ~name ~stamp ?(locks=[]) build =
SC.add_alias_action sctx alias ~locks ~stamp build

let alias sctx ~dir ~scope (alias_conf : Alias_conf.t) =
let stamp =
let module S = Sexp.To_sexp in
Sexp.List
[ Sexp.unsafe_atom_of_string "user-alias"
; Jbuild.Bindings.sexp_of_t Jbuild.Dep_conf.sexp_of_t alias_conf.deps
; S.option Action.Unexpanded.sexp_of_t
(Option.map alias_conf.action ~f:snd)
]
let enabled =
match alias_conf.enabled_if with
| None -> true
| Some blang ->
let f : String_with_vars.t Blang.expander =
{ f = fun ~mode sw ->
( String_with_vars.loc sw
, Super_context.expand_vars sctx ~scope ~mode ~dir sw
)
} in
Blang.eval_bool blang ~dir ~f
in
add_alias sctx
~dir
~name:alias_conf.name
~stamp
~locks:(interpret_locks sctx ~dir ~scope alias_conf.locks)
(SC.Deps.interpret_named sctx ~scope ~dir alias_conf.deps
>>>
match alias_conf.action with
| None -> Build.progn []
| Some (loc, action) ->
SC.Action.run
sctx
action
~loc
~dir
~dep_kind:Required
~bindings:(Pform.Map.of_bindings alias_conf.deps)
~targets:Alias
~targets_dir:dir
~scope)
if enabled then
let stamp =
let module S = Sexp.To_sexp in
Sexp.List
[ Sexp.unsafe_atom_of_string "user-alias"
; Jbuild.Bindings.sexp_of_t Jbuild.Dep_conf.sexp_of_t alias_conf.deps
; S.option Action.Unexpanded.sexp_of_t
(Option.map alias_conf.action ~f:snd)
]
in
add_alias sctx
~dir
~name:alias_conf.name
~stamp
~locks:(interpret_locks sctx ~dir ~scope alias_conf.locks)
(SC.Deps.interpret_named sctx ~scope ~dir alias_conf.deps
>>>
match alias_conf.action with
| None -> Build.progn []
| Some (loc, action) ->
SC.Action.run
sctx
action
~loc
~dir
~dep_kind:Required
~bindings:(Pform.Map.of_bindings alias_conf.deps)
~targets:Alias
~targets_dir:dir
~scope)
10 changes: 10 additions & 0 deletions src/stdune/bool.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type t = bool

let compare x y =
match x, y with
| true, true
| false, false -> Ordering.Eq
| true, false -> Gt
| false, true -> Lt

let to_string = string_of_bool
5 changes: 5 additions & 0 deletions src/stdune/bool.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type t = bool

val compare : t -> t -> Ordering.t

val to_string : t -> string
1 change: 0 additions & 1 deletion src/stdune/sexp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,6 @@ module Of_sexp = struct
String.Map.iteri map ~f:(Hashtbl.add tbl);
tbl


let find_cstr cstrs loc name ctx values =
match List.assoc cstrs name with
| Some t ->
Expand Down
1 change: 1 addition & 0 deletions src/stdune/stdune.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Set = Set
module Staged = Staged
module String = String
module Char = Char
module Bool = Bool
module Sexp = Sexp
module Path = Path
module Fmt = Fmt
Expand Down
Loading

0 comments on commit 3d9612f

Please sign in to comment.