From 1d8348d52e7d5b7f23c9c86841879afdf2aa5458 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sat, 10 Mar 2012 12:14:32 +0000 Subject: [PATCH] Change whenjobs --set syntax (NOTE: breaks compatibility). Change the whenjobs --set syntax to allow multiple variables to be set atomically. The new syntax looks like: whenjobs --set variable=value [variable=value ...] NOTE: This breaks compatibility with whenjobs <= 0.5. --- README | 6 +- lib/whenproto.x | 2 +- tests/jobs/t100_counter.ml | 4 +- tests/jobs/t101_updown.ml | 4 +- tests/jobs/t102_manyjobs.ml | 10 +-- tests/jobs/t200_ocaml_jobnames.ml | 2 +- tests/jobs/t201_ocaml_set_variable.ml | 2 +- tools/tutorial.ml | 2 +- tools/whenjobs.ml | 134 +++++++++++++++++++++------------- tools/whenjobs.pod | 31 ++++++-- 10 files changed, 122 insertions(+), 75 deletions(-) diff --git a/README b/README index f1c7596..9aa9207 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ language. Read the whenjobs(1) man page for full information. << cd /my/git/repo tag=`git-describe --tags` - whenjobs --set version $tag + whenjobs --set version=$tag >> (* When the 'version' variable changes (ie. a new release is @@ -34,14 +34,14 @@ language. Read the whenjobs(1) man page for full information. git reset --hard $version ./configure make clean all check dist - whenjobs --set successful_local_build $version + whenjobs --set successful_local_build=$version >> (* In parallel, build on a remote machine. *) when changes version : << ssh remote ./do_build $version - whenjobs --set successful_remote_build $version + whenjobs --set successful_remote_build=$version >> (* Only when the new release has been successfully built on local diff --git a/lib/whenproto.x b/lib/whenproto.x index f7ea513..a1407fb 100644 --- a/lib/whenproto.x +++ b/lib/whenproto.x @@ -89,7 +89,7 @@ typedef job job_list<>; program When { version V1 { status reload_file (void) = 1; - status set_variable (variable_name, variable) = 2; + status set_variable (variable_name, variable) = 2; /* obsolete */ variable get_variable (variable_name) = 3; variable_name_list get_variable_names (void) = 4; status exit_daemon (void) = 5; diff --git a/tests/jobs/t100_counter.ml b/tests/jobs/t100_counter.ml index 78471ec..b6ac29c 100644 --- a/tests/jobs/t100_counter.ml +++ b/tests/jobs/t100_counter.ml @@ -21,13 +21,13 @@ when reloaded () : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter 0 --type int + whenjobs --set --type int counter=0 >> every 2 seconds : << echo $JOBSERIAL $JOBNAME $counter >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> when counter = 3 : diff --git a/tests/jobs/t101_updown.ml b/tests/jobs/t101_updown.ml index 791a58b..6eb94c2 100644 --- a/tests/jobs/t101_updown.ml +++ b/tests/jobs/t101_updown.ml @@ -23,13 +23,13 @@ when reloaded () : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter 0 --type int + whenjobs --set --type int counter=0 >> every second : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> when counter < 5 && counter mod 2 == 0 : diff --git a/tests/jobs/t102_manyjobs.ml b/tests/jobs/t102_manyjobs.ml index a586345..41feb77 100644 --- a/tests/jobs/t102_manyjobs.ml +++ b/tests/jobs/t102_manyjobs.ml @@ -19,35 +19,35 @@ when reloaded () : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter 0 --type int + whenjobs --set --type int counter=0 >> job "counter 1" every second : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> job "counter 2" every second : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> job "counter 3" every second : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> job "counter 4" every second : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) --type int + whenjobs --set --type int counter=$(($counter+1)) >> when increases counter : diff --git a/tests/jobs/t200_ocaml_jobnames.ml b/tests/jobs/t200_ocaml_jobnames.ml index c003700..35d74d4 100644 --- a/tests/jobs/t200_ocaml_jobnames.ml +++ b/tests/jobs/t200_ocaml_jobnames.ml @@ -24,7 +24,7 @@ job (prefix ^ "job") every 2 seconds : << echo $JOBSERIAL $JOBNAME >\> $HOME/test_output - whenjobs --set counter 1 + whenjobs --set counter=1 >> job (prefix ^ "finished") diff --git a/tests/jobs/t201_ocaml_set_variable.ml b/tests/jobs/t201_ocaml_set_variable.ml index 50ee5ab..6d8dad4 100644 --- a/tests/jobs/t201_ocaml_set_variable.ml +++ b/tests/jobs/t201_ocaml_set_variable.ml @@ -24,7 +24,7 @@ let () = every second : << echo $JOBSERIAL $JOBNAME $counter >\> $HOME/test_output - whenjobs --set counter $(($counter+1)) + whenjobs --set --type int counter=$(($counter+1)) >> when counter > 100 : diff --git a/tools/tutorial.ml b/tools/tutorial.ml index b0df108..397b96f 100644 --- a/tools/tutorial.ml +++ b/tools/tutorial.ml @@ -31,7 +31,7 @@ every 10 minutes : # Get free blocks in /home free=`stat -f -c %b /home` # Set the variable 'free_space' - whenjobs --type int --set free_space $free + whenjobs --set --type int free_space=$free >> Use 'when : << >>' runs the shell script only when diff --git a/tools/whenjobs.ml b/tools/whenjobs.ml index ff166a6..cfef9d6 100644 --- a/tools/whenjobs.ml +++ b/tools/whenjobs.ml @@ -71,10 +71,23 @@ let jobsdir = let rec main () = (* Parse the command line arguments. *) let mode = ref None in - let typ = ref "string" in + let typ = ref `String in let set_mode m () = mode := Some m in + let set_type t = + typ := + match t with + | "bool"|"boolean" -> `Bool + | "string" -> `String + | "int" -> `Int + | "float"|"double" -> `Float + | "unit" -> `Unit + | _ -> + eprintf "whenjobs: --type: unknown type (%s)\n" t; + exit 1 + in + let display_version () = printf "%s %s\n" Config.package_name Config.package_version; exit 0 @@ -96,15 +109,20 @@ let rec main () = "--set", Arg.Unit (set_mode `Set), " Set the variable"; "--start", Arg.Unit (set_mode `Start), "name Start a job manually"; "--tail", Arg.Unit (set_mode `Tail), "serial Tail job output"; - "--type", Arg.Set_string typ, "bool|int|float|string|unit Set the variable type"; + "--type", Arg.String set_type, "bool|int|float|string|.. Set the variable type"; "--upload", Arg.Unit (set_mode `Upload), " Upload the script"; "--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"; ] in - let args = ref [] in - let anon_fun str = args := str :: !args 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 mode we need to record the type of each argument + * as well, so we keep that in a separate list (argtypes). + *) + let argtypes = ref [] in + let anon_fun str = argtypes := (str, !typ) :: !argtypes in let usage_msg = "\ Whenjobs is a powerful but simple cron replacement. @@ -118,7 +136,7 @@ Editing the script: Get and set variables: whenjobs --get variable - whenjobs --set variable value + whenjobs --set variable=value Start and stop the per-user daemon: @@ -132,17 +150,8 @@ Options: Arg.parse argspec anon_fun usage_msg; let mode = !mode in - let args = List.rev !args in - - let typ = match !typ with - | "bool"|"boolean" -> `Bool - | "string" -> `String - | "int" -> `Int - | "float"|"double" -> `Float - | "unit" -> `Unit - | t -> - eprintf "whenjobs: --type: unknown type (%s)\n" t; - exit 1 in + let argtypes = List.rev !argtypes in + let args = List.map fst argtypes in let nr_args = List.length args in let arg1 = match args with [] -> "" | a::_ -> a in @@ -166,13 +175,18 @@ Options: upload_file () | Some `Set -> - if List.length args != 2 then ( - eprintf "whenjobs --set variable value\n"; - eprintf "If 'value' contains spaces, you may need to quote it.\n"; + if nr_args = 2 && not (String.contains arg1 '=') then ( + eprintf "'whenjobs --set variable value' is the old whenjobs <= 0.5 syntax!\n"; + eprintf "You need to change this to:\n"; + eprintf " whenjobs --set variable=value\n"; suggest_help (); exit 1 ); - set_variable (List.hd args) (List.hd (List.tl args)) typ + (* Just ignore the case where no variables are defined, to make + * it easier to write shell scripts. + *) + if nr_args > 0 then + set_variables argtypes | Some `Get -> if nr_args != 1 then ( @@ -311,39 +325,27 @@ and upload_file () = ); stop_client client -and set_variable name value typ = - let value = match typ with - | `Bool -> - (match value with - | "true"|"t"|"yes"|"y"|"on"|"1" -> `bool_t true - | "false"|"f"|"no"|"n"|"off"|"0" -> `bool_t false - | _ -> - eprintf "whenjobs: variable does not have a boolean value\n"; - exit 1 - ) - | `String -> `string_t value - | `Int -> - (try ignore (big_int_of_string value) - with Failure _ -> - eprintf "whenjobs: variable is not an integer\n"; - exit 1 - ); - `int_t value (* the string is what we pass over the wire *) - | `Float -> - (try `float_t (float_of_string value) - with Failure _ -> - eprintf "whenjobs: variable is not a floating point number\n"; - exit 1 - ) - | `Unit -> - if value <> "" then ( - eprintf "whenjobs: unit variables must be empty strings\n"; - exit 1 - ); - `unit_t in +and set_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: set: 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.set_variable client (name, value) with + (match Whenproto_clnt.When.V1.set_variables client vars with | `ok -> () | `error msg -> eprintf "whenjobs: set: %s\n" msg; @@ -494,6 +496,36 @@ and string_of_variable = function | `int_t i -> i (* passed on the wire as a string *) | `float_t f -> string_of_float f +and value_of_string value = function + | `Bool -> + (match value with + | "true"|"t"|"yes"|"y"|"on"|"1" -> `bool_t true + | "false"|"f"|"no"|"n"|"off"|"0" -> `bool_t false + | _ -> + eprintf "whenjobs: variable does not have a boolean value\n"; + exit 1 + ) + | `String -> `string_t value + | `Int -> + (try ignore (big_int_of_string value) + with Failure _ -> + eprintf "whenjobs: variable is not an integer\n"; + exit 1 + ); + `int_t value (* the string is what we pass over the wire *) + | `Float -> + (try `float_t (float_of_string value) + with Failure _ -> + eprintf "whenjobs: variable is not a floating point number\n"; + exit 1 + ) + | `Unit -> + if value <> "" then ( + eprintf "whenjobs: unit variables must be empty strings\n"; + exit 1 + ); + `unit_t + let () = try main () with diff --git a/tools/whenjobs.pod b/tools/whenjobs.pod index 466bdb1..5750646 100644 --- a/tools/whenjobs.pod +++ b/tools/whenjobs.pod @@ -14,7 +14,7 @@ Editing the jobs script: Get and set variables: whenjobs --get variable - whenjobs --set variable value [--type bool|int|float|string] + whenjobs --set variable=value [variable=value ...] whenjobs --variables Start and stop the per-user daemon: @@ -43,7 +43,7 @@ Periodic jobs are written like this: << # Get the current load average. load=`awk '{print $1}' /proc/loadavg` - whenjobs --set load $load --type float + whenjobs --set --type float load=$load >> When-statements let you create jobs that run based on variables set @@ -80,7 +80,7 @@ command line tool to examine and set variables: $ whenjobs --variables load=0.9 - $ whenjobs --set cat sushi + $ whenjobs --set cat=sushi $ whenjobs --get cat sushi @@ -150,7 +150,7 @@ source, eg: whenjobs --lib $builddir/lib -e -=item B<--set> variable value +=item B<--set> variable=value [variable=value ...] =item B<--type> bool|int|float|string|unit @@ -158,18 +158,33 @@ I<--set> sets the variable named C to the new C. The variable is created if it does not already exist. Note that setting a variable can cause jobs to run immediately. -To unset a variable, set it to the empty string: +To unset a variable, set it to the empty string like this: - whenjobs --set var "" + whenjobs --set var= By default variables are strings. You can also set the type of a -variable when setting it by adding the optional I<--type> parameter: +variable when setting it by adding the optional I<--type> parameter. +The I<--type> parameter should come I the variable +declaration, like this: - whenjobs --set free_space 10000 --type int + whenjobs --set --type int free_space=10000 See the discussion of variable types in the L section below. +You can set multiple variables. When setting multiple variables in a +single command, the values are all changed in a single atomic +operation. + + whenjobs --set cat=sushi food=fish + +When using I<--type> and multiple variables, the type changes the +remaining command line parameters until the next I<--type>, eg: + + whenjobs --set cat=sushi --type float weight=3.5 --type string food=fish + +(C and C are strings, and C is a float). + =item B<--start> "job name" Start the job immediately and unconditionally. -- 1.8.3.1