2 * Copyright (C) 2012 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 variables : variables;
29 (*--- below here is "internal" state ---*)
31 jobmap : job StringMap.t; (* job name -> job structure *)
33 (* Map variable names to jobs which depend on that variable. This
34 * gives us a quick way to tell which jobs might need to be reevaluated
35 * when a variable is set.
37 dependencies : string list StringMap.t; (* variable -> list of job names *)
39 (* For each job, if it has run, we store the previous variables
40 * at that time. This is used to implement {i previous}, {i changes} etc.
42 prev_variables : variables StringMap.t; (* job name -> variables *)
44 (* For each job, if it has been evaluated before (see {!job_evaluate})
45 * then we store the previous result of evaluation here. This is
46 * used to implement edge-triggering.
48 prev_eval_result : bool StringMap.t; (* job name -> bool *)
52 variables = StringMap.empty;
54 jobmap = StringMap.empty;
55 dependencies = StringMap.empty;
56 prev_variables = StringMap.empty;
57 prev_eval_result = StringMap.empty;
61 let deps = dependencies_of_job job in
62 let dependencies' = List.fold_left (
64 let names = try StringMap.find d map with Not_found -> [] in
65 StringMap.add d (job.job_name :: names) map
66 ) t.dependencies deps in
70 jobmap = StringMap.add job.job_name job t.jobmap;
71 dependencies = dependencies'
74 let set_variable t name value =
75 { t with variables = StringMap.add name value t.variables }
77 let copy_variables old t =
78 { t with variables = StringMap.fold StringMap.add old.variables t.variables }
80 let copy_prev_state old t =
81 let is_explicit jobname =
82 String.length jobname < 4 || String.sub jobname 0 4 <> "job$"
85 let prev_variables = StringMap.fold (
88 if not (is_explicit jobname) then raise Not_found;
89 (* See if we can find a job with the same name in the old state. *)
90 let old_vars = StringMap.find jobname old.prev_variables in
91 StringMap.add jobname old_vars map
94 ) t.jobmap t.prev_variables in
96 let prev_eval_result = StringMap.fold (
99 if not (is_explicit jobname) then raise Not_found;
100 (* See if we can find a job with the same name in the old state. *)
101 let old_result = StringMap.find jobname old.prev_eval_result in
102 StringMap.add jobname old_result map
105 ) t.jobmap t.prev_eval_result in
108 prev_variables = prev_variables; prev_eval_result = prev_eval_result }
110 let get_variable t name =
111 try StringMap.find name t.variables with Not_found -> T_string ""
113 let get_variables t =
116 if value <> T_string "" then (name, value) :: xs else xs
119 let get_variable_names t =
121 fun name value xs -> if value <> T_string "" then name :: xs else xs
124 let nr_jobs t = List.length t.jobs
126 let get_dependencies t names =
127 (* Get all job names that depend on these variables. *)
131 try StringMap.find name t.dependencies with Not_found -> []
134 (* Flatten the list and remove duplicates. *)
135 let set = List.fold_left (
136 fun set jn -> StringSet.add jn set
137 ) StringSet.empty (List.flatten jobnames) in
138 let jobnames = StringSet.elements set in
140 (* Convert job names to jobs. *)
143 let j = StringMap.find jn t.jobmap in
144 (* If this asserts false, then there is a bug in {!add_job}. *)
145 assert (match j.job_cond with When_job _ -> true | _ -> false);
148 (* This should never happen. It would indicate some bug in the
149 * {!add_job} function.
155 List.filter (function { job_cond = When_job _ } -> true | _ -> false) t.jobs
157 let get_everyjobs t =
158 List.filter (function { job_cond = Every_job _ } -> true | _ -> false) t.jobs
160 let get_job t jobname =
161 StringMap.find jobname t.jobmap
163 let get_job_names t =
164 List.map (function { job_name = name } -> name) t.jobs
166 let evaluate_whenjob ?(onload = false) t job =
168 | { job_cond = Every_job _ } -> assert false
169 | { job_cond = When_job whenexpr; job_name = jobname } ->
171 try Some (StringMap.find jobname t.prev_variables)
172 with Not_found -> None in
175 eval_whenexpr_as_bool t.variables prev_variables onload whenexpr in
177 let prev_eval_result =
178 try Some (StringMap.find jobname t.prev_eval_result)
179 with Not_found -> None in
181 let t = { t with prev_eval_result =
182 StringMap.add jobname result t.prev_eval_result } in
184 (* Because jobs are edge-triggered, we're only interested in the
185 * case where the evaluation state changes from false -> true.
187 match prev_eval_result, result with
191 | Some true, false ->
195 | Some false, true ->
196 let t = { t with prev_variables =
197 StringMap.add jobname t.variables t.prev_variables } in