No jobs resulting from the changed variables will run.
~proc_get_job_names
~proc_test_variables
~proc_ping_daemon
+ ~proc_whisper_variables
(Rpc_server.Unix addr)
Rpc.Tcp (* not TCP, this is the same as SOCK_STREAM *)
Rpc.Socket
and proc_ping_daemon () = `ok
+and proc_whisper_variables vars =
+ try
+ let vars = Array.map (
+ fun { Whenproto_aux.sv_name = name; sv_value = value } ->
+ name, variable_of_rpc value
+ ) vars in
+ let vars = Array.to_list vars in
+
+ if !debug then
+ Syslog.notice "remote call: whisper_variables (%s)"
+ (String.concat " "
+ (List.map (
+ fun (name, value) ->
+ sprintf "%s=%s" name (string_of_variable value)
+ ) vars));
+
+ List.iter (fun (name, _) -> check_valid_variable_name name) vars;
+
+ (* Update all the variables atomically. *)
+ let s = List.fold_left (
+ fun s (name, value) -> Whenstate.set_variable s name value
+ ) !state vars in
+ state := s;
+
+ (* .. but don't reevaluate or run jobs. *)
+
+ `ok
+ with
+ Failure msg -> `error msg
+
(* Reload the jobs file. *)
and reload_file () =
let file = sprintf "%s/jobs.cmo" !jobsdir in
job_name_list get_job_names (void) = 11;
job_name_list test_variables (set_variable_list) = 12;
status ping_daemon (void) = 13;
+ status whisper_variables (set_variable_list) = 14;
} = 1;
} = 0x20008081;
t100_counter.ml \
t101_updown.ml \
t102_manyjobs.ml \
+ t103_whisper.ml \
t200_ocaml_jobnames.ml \
t201_ocaml_set_variable.ml
--- /dev/null
+(* whenjobs
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+when state == "" :
+<<
+ whenjobs --set state=A
+>>
+
+when state == "A" :
+<<
+ echo state A >\> $HOME/test_output
+ sleep 1
+ whenjobs --set state=B
+>>
+
+when state == "B" :
+<<
+ echo state B >\> $HOME/test_output
+ sleep 1
+ # This shouldn't cause state A to run:
+ whenjobs --whisper state=A
+ sleep 1
+ whenjobs --set state=C
+>>
+
+when state == "C":
+<<
+ echo state C >\> $HOME/test_output
+ sleep 1
+ # This shouldn't cause state B to run:
+ whenjobs --whisper state=B
+ sleep 1
+ whenjobs --set state=D
+>>
+
+when state == "D":
+<<
+ echo state D >\> $HOME/test_output
+ sleep 1
+ whenjobs --daemon-stop
+>>
--- /dev/null
+state A
+state B
+state C
+state D
"--variables", Arg.Unit (set_mode `Variables), " Display all variables and values";
"-V", Arg.Unit display_version, " Display version number and exit";
"--version", Arg.Unit display_version, " Display version number and exit";
+ "--whisper", Arg.Unit (set_mode `Whisper), " Set the variable, quietly";
] in
(* anon_fun normally just collects up the anonymous arguments as
* strings, and most modes just use 'args' as a list of strings.
- * However for `Set and `Test modes we need to record the type of
- * each argument as well, so we keep that in a separate list
+ * However for `Set, `Test and `Whisper modes we need to record the
+ * type of each argument as well, so we keep that in a separate list
* (argtypes).
*)
let argtypes = ref [] in
if nr_args > 0 then
test_variables argtypes
+ | Some `Whisper ->
+ if nr_args > 0 then
+ whisper_variables argtypes
+
| Some `Get ->
if nr_args != 1 then (
eprintf "whenjobs --get variable\n";
let i =
try String.index def '='
with Not_found ->
- eprintf "whenjobs: set: missing = sign in variable definition\n";
+ eprintf "whenjobs: test: missing = sign in variable definition\n";
suggest_help ();
exit 1 in
let name = String.sub def 0 i in
Array.iter print_endline jobnames
+and whisper_variables argtypes =
+ let vars = List.map (
+ fun (def, typ) ->
+ (* 'def' should have the form "name=value". The value part may
+ * be missing, but the equals sign is required.
+ *)
+ let i =
+ try String.index def '='
+ with Not_found ->
+ eprintf "whenjobs: whisper: missing = sign in variable definition\n";
+ suggest_help ();
+ exit 1 in
+ let name = String.sub def 0 i in
+ let value = String.sub def (i+1) (String.length def - (i+1)) in
+ let value = value_of_string value typ in
+ { Whenproto_aux.sv_name = name; sv_value = value }
+ ) argtypes in
+ let vars = Array.of_list vars in
+
+ let client = start_client () in
+ (match Whenproto_clnt.When.V1.whisper_variables client vars with
+ | `ok -> ()
+ | `error msg ->
+ eprintf "whenjobs: whisper: %s\n" msg;
+ suggest_check_server_logs ();
+ exit 1
+ );
+ stop_client client
+
and get_variable name =
let client = start_client () in
let value = Whenproto_clnt.When.V1.get_variable client name in
Display the name and version of the program and exit.
+=item B<--whisper> variable=value [variable=value ...]
+
+This works the same way as the I<--set> option, but with the
+difference that jobs' when clauses are not reevaluated. In other
+words, the variables are set, but "quietly" so as not to trigger any
+jobs to run.
+
+Note that this can lead to some unexpected results: one case is a
+when job such as:
+
+ when changed a || changed b : << ... >>
+
+If C<a> is changed using I<--whisper>, then the job will not run.
+
+But later on, if C<b> is set but to the same value that it already has
+(ie. not changed), the job will run because the whole when-clause is
+reevaluated and C<a> is found to have changed since the last run of
+the job.
+
=back
=head1 REFERENCE