From 550bd0df9a6c9067dd0e2f9e77ae650efdf62454 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 13 Mar 2012 17:58:52 +0000 Subject: [PATCH] Add 'whenjobs --whisper' which lets you set variables "quietly". No jobs resulting from the changed variables will run. --- daemon/daemon.ml | 31 ++++++++++++++++++++ lib/whenproto.x | 1 + tests/jobs/Makefile.am | 1 + tests/jobs/t103_whisper.ml | 56 +++++++++++++++++++++++++++++++++++++ tests/jobs/t103_whisper.ml.expected | 4 +++ tools/whenjobs.ml | 40 ++++++++++++++++++++++++-- tools/whenjobs.pod | 19 +++++++++++++ 7 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 tests/jobs/t103_whisper.ml create mode 100644 tests/jobs/t103_whisper.ml.expected diff --git a/daemon/daemon.ml b/daemon/daemon.ml index cf14188..e18574d 100644 --- a/daemon/daemon.ml +++ b/daemon/daemon.ml @@ -83,6 +83,7 @@ let rec init j d = ~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 @@ -259,6 +260,36 @@ and proc_test_variables vars = 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 diff --git a/lib/whenproto.x b/lib/whenproto.x index ff5edfb..ad44e65 100644 --- a/lib/whenproto.x +++ b/lib/whenproto.x @@ -103,5 +103,6 @@ program When { 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; diff --git a/tests/jobs/Makefile.am b/tests/jobs/Makefile.am index d80c09f..1ae468b 100644 --- a/tests/jobs/Makefile.am +++ b/tests/jobs/Makefile.am @@ -22,6 +22,7 @@ TESTS = \ t100_counter.ml \ t101_updown.ml \ t102_manyjobs.ml \ + t103_whisper.ml \ t200_ocaml_jobnames.ml \ t201_ocaml_set_variable.ml diff --git a/tests/jobs/t103_whisper.ml b/tests/jobs/t103_whisper.ml new file mode 100644 index 0000000..a6da8bb --- /dev/null +++ b/tests/jobs/t103_whisper.ml @@ -0,0 +1,56 @@ +(* 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 +>> diff --git a/tests/jobs/t103_whisper.ml.expected b/tests/jobs/t103_whisper.ml.expected new file mode 100644 index 0000000..1c046cd --- /dev/null +++ b/tests/jobs/t103_whisper.ml.expected @@ -0,0 +1,4 @@ +state A +state B +state C +state D diff --git a/tools/whenjobs.ml b/tools/whenjobs.ml index f77e825..1334aec 100644 --- a/tools/whenjobs.ml +++ b/tools/whenjobs.ml @@ -116,12 +116,13 @@ let rec main () = "--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 @@ -195,6 +196,10 @@ Options: 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"; @@ -374,7 +379,7 @@ and test_variables argtypes = 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 @@ -390,6 +395,35 @@ and test_variables argtypes = 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 diff --git a/tools/whenjobs.pod b/tools/whenjobs.pod index 14ca141..6d2a554 100644 --- a/tools/whenjobs.pod +++ b/tools/whenjobs.pod @@ -267,6 +267,25 @@ Display all the variables and their values, in the format C. 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 is changed using I<--whisper>, then the job will not run. + +But later on, if C 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 is found to have changed since the last run of +the job. + =back =head1 REFERENCE -- 1.8.3.1