Copy previous variables / eval result across file reloads.
authorRichard W.M. Jones <rjones@redhat.com>
Wed, 29 Feb 2012 14:58:57 +0000 (14:58 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 29 Feb 2012 14:58:57 +0000 (14:58 +0000)
This makes functions like prev(), changes() etc behave
more predictably when the file is reloaded.

daemon/daemon.ml
lib/whenstate.ml
lib/whenstate.mli
tools/whenjobs.pod

index ac0f1ff..925ad7e 100644 (file)
@@ -192,6 +192,7 @@ and reload_file () =
     | exn ->
       failwith (Printexc.to_string exn) in
 
+  let s = Whenstate.copy_prev_state !state s in
   state := s;
 
   (* Re-evaluate all when jobs. *)
index fe53a16..e3aad07 100644 (file)
@@ -77,6 +77,36 @@ let set_variable t name value =
 let copy_variables old t =
   { t with variables = StringMap.fold StringMap.add old.variables t.variables }
 
+let copy_prev_state old t =
+  let is_explicit jobname =
+    String.length jobname < 4 || String.sub jobname 0 4 <> "job$"
+  in
+
+  let prev_variables = StringMap.fold (
+    fun jobname _ map ->
+      try
+        if not (is_explicit jobname) then raise Not_found;
+        (* See if we can find a job with the same name in the old state. *)
+        let old_vars = StringMap.find jobname old.prev_variables in
+        StringMap.add jobname old_vars map
+      with
+        Not_found -> map
+  ) t.jobmap t.prev_variables in
+
+  let prev_eval_result = StringMap.fold (
+    fun jobname _ map ->
+      try
+        if not (is_explicit jobname) then  raise Not_found;
+        (* See if we can find a job with the same name in the old state. *)
+        let old_result = StringMap.find jobname old.prev_eval_result in
+        StringMap.add jobname old_result map
+      with
+        Not_found -> map
+  ) t.jobmap t.prev_eval_result in
+
+  { t with
+    prev_variables = prev_variables; prev_eval_result = prev_eval_result }
+
 let get_variable t name =
   try StringMap.find name t.variables with Not_found -> T_string ""
 
index 084cd49..15df0c1 100644 (file)
@@ -47,6 +47,17 @@ val copy_variables : t -> t -> t
     the variables from [old_state], adding them to [current_state],
     returning a new state.  Note the order of arguments. *)
 
+val copy_prev_state : t -> t -> t
+(** [copy_prev_state old_state current_state -> new_state] is an
+    obscure function used to make the [prev] function work predictably
+    across file reloads.  Since a file reload creates a new state
+    object, it would normally "forget" that jobs had run previously,
+    so any job that used [prev], [changes] etc would run again
+    unnecessarily.  This function copies the prev state, allowing us
+    to remember which jobs ran previously and the state of the
+    variables at that time, making these functions work predictably.
+    State is only copied for jobs that have explicit names. *)
+
 val get_variable : t -> string -> Whenexpr.variable
 (** Return the value of a variable, when unknown variables defaulting
     to empty string. *)
index fe3041b..0f777d4 100644 (file)
@@ -403,6 +403,11 @@ that it had last time this when-job ran.
 
 If the when-job has not run yet, then this returns C<"">.
 
+Job state is preserved across file reloads, but I<only> for jobs that
+are explicitly named.  If you find that jobs using C<prev>, C<changes>
+etc are running unnecessarily when the jobs file is edited or
+uploaded, try giving the jobs an explicit name.
+
 =item B<changes> I<variable>
 
 If the named variable has changed since this job last ran, then this