Run jobs with 'set -e' so that they exit on error.
[whenjobs.git] / lib / whenutils.ml
index fd066b4..aa59f18 100644 (file)
@@ -133,18 +133,19 @@ type job_private = {
   (* The result of the previous evaluation.  This is used for
    * implementing edge-triggering, since we only trigger the job to run
    * when the state changes from false -> true.
+   *
+   * [None] means there has been no previous evaluation.
    *)
-  job_prev_eval_state : bool;
+  job_prev_eval_state : bool option;
 
   (* When the job {i ran} last time, we take a copy of the variables.
    * This allows us to implement the 'changes' operator.
+   *
+   * [None] means there has been no previous run.
    *)
-  job_prev_variables : variables;
+  job_prev_variables : variables option;
 }
 
-let no_job_private =
-  { job_prev_eval_state = false; job_prev_variables = StringMap.empty }
-
 type job_cond =
   | When_job of whenexpr
   | Every_job of periodexpr
@@ -157,6 +158,18 @@ type job = {
   job_private : job_private;
 }
 
+let make_when_job _loc name e sh =
+  { job_loc = _loc; job_name = name;
+    job_cond = When_job e; job_script = sh;
+    job_private = { job_prev_eval_state = None;
+                    job_prev_variables = None } }
+
+let make_every_job _loc name e sh =
+  { job_loc = _loc; job_name = name;
+    job_cond = Every_job e; job_script = sh;
+    job_private = { job_prev_eval_state = None;
+                    job_prev_variables = None } }
+
 let rec expr_of_ast _loc ast =
   expr_of_iexpr _loc (iexpr_of_ast _loc ast)
 
@@ -371,7 +384,7 @@ let rec eval_whenexpr job variables onload = function
   | Expr_float f -> T_float f
 
   | Expr_var v ->
-    (try StringMap.find v variables with Not_found -> T_string "")
+    get_variable variables v
 
   | Expr_and (e1, e2) ->
     if eval_whenexpr_as_bool job variables onload e1 &&
@@ -467,34 +480,40 @@ let rec eval_whenexpr job variables onload = function
 
   | Expr_increases v ->
     let prev_value, curr_value = get_prev_curr_value job variables v in
-    if compare_values prev_value curr_value > 0 then
+    if compare_values prev_value curr_value < 0 then
       T_bool true
     else
       T_bool false
 
   | Expr_decreases v ->
     let prev_value, curr_value = get_prev_curr_value job variables v in
-    if compare_values prev_value curr_value < 0 then
+    if compare_values prev_value curr_value > 0 then
       T_bool true
     else
       T_bool false
 
   | Expr_prev v ->
-    (try StringMap.find v job.job_private.job_prev_variables
-     with Not_found -> T_string "")
+    get_prev_variable job v
 
   | Expr_reloaded ->
     T_bool onload
 
 and get_prev_curr_value job variables v =
-  let prev_value =
-    try StringMap.find v job.job_private.job_prev_variables
-    with Not_found -> T_string "" in
-  let curr_value =
-    try StringMap.find v variables
-    with Not_found -> T_string "" in
+  let prev_value = get_prev_variable job v in
+  let curr_value = get_variable variables v in
   prev_value, curr_value
 
+and get_variable variables v =
+  try StringMap.find v variables with Not_found -> T_string ""
+
+and get_prev_variable job v =
+  match job.job_private.job_prev_variables with
+  | None ->
+    (* Job has never run.  XXX Should do better here. *)
+    T_string ""
+  | Some prev_variables ->
+    get_variable prev_variables v
+
 (* Call {!eval_whenexpr} and cast the result to a boolean. *)
 and eval_whenexpr_as_bool job variables onload expr =
   match eval_whenexpr job variables onload expr with
@@ -514,6 +533,7 @@ and compare_values value1 value2 =
   | T_string s1, T_string s2 -> compare s1 s2
   | T_int i1, T_int i2 -> compare_big_int i1 i2
   | T_float f1, T_float f2 -> compare f1 f2
+    (* XXX BUG: int should be promoted to float in mixed numeric comparison *)
   | _ ->
     let value1 = string_of_variable value1
     and value2 = string_of_variable value2 in
@@ -605,16 +625,18 @@ let job_evaluate job variables onload =
      * case where the evaluation state changes from false -> true.
      *)
     match job.job_private.job_prev_eval_state, state with
-    | false, false
-    | true, true
-    | true, false ->
-      let jobp = { job.job_private with job_prev_eval_state = state } in
+    | None, false
+    | Some false, false
+    | Some true, true
+    | Some true, false ->
+      let jobp = { job.job_private with job_prev_eval_state = Some state } in
       let job = { job with job_private = jobp } in
       false, job
 
-    | false, true ->
-      let jobp = { job_prev_eval_state = true;
-                   job_prev_variables = variables } in
+    | None, true
+    | Some false, true ->
+      let jobp = { job_prev_eval_state = Some true;
+                   job_prev_variables = Some variables } in
       let job = { job with job_private = jobp } in
       true, job