diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2010-09-18 09:38:05 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2010-09-18 09:38:05 +0100 |
commit | 0003ea2c3dbaa7e22f4f616539136821d80694b8 (patch) | |
tree | 1a5bcededb436fb9f1a0e8e046599fdd0d5ae7f1 /generator | |
parent | 585fceb3350c17a3d6ed7f2daffd5e2b3e5fc3e1 (diff) | |
download | libguestfs-0003ea2c3dbaa7e22f4f616539136821d80694b8.tar.gz libguestfs-0003ea2c3dbaa7e22f4f616539136821d80694b8.tar.xz libguestfs-0003ea2c3dbaa7e22f4f616539136821d80694b8.zip |
generator: Generate guestfish-only commands.
The guestfish-only commands such as 'alloc' and 'edit' are
now generated from one place in the generator instead of being
spread around ad-hoc in the C code.
Diffstat (limited to 'generator')
-rw-r--r-- | generator/generator_actions.ml | 159 | ||||
-rw-r--r-- | generator/generator_actions.mli | 3 | ||||
-rw-r--r-- | generator/generator_checks.ml | 6 | ||||
-rw-r--r-- | generator/generator_fish.ml | 106 | ||||
-rw-r--r-- | generator/generator_main.ml | 1 | ||||
-rw-r--r-- | generator/generator_utils.ml | 2 | ||||
-rw-r--r-- | generator/generator_utils.mli | 3 |
7 files changed, 246 insertions, 34 deletions
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 2e015070..d01871f2 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -5124,9 +5124,7 @@ let all_functions = non_daemon_functions @ daemon_functions (* In some places we want the functions to be displayed sorted * alphabetically, so this is useful: *) -let all_functions_sorted = - List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) -> - compare n1 n2) all_functions +let all_functions_sorted = List.sort action_compare all_functions (* This is used to generate the src/MAX_PROC_NR file which * contains the maximum procedure number, a surrogate for the @@ -5137,3 +5135,158 @@ let max_proc_nr = fun (_, _, proc_nr, _, _, _, _) -> proc_nr ) daemon_functions in List.fold_left max 0 proc_nrs + +(* Non-API meta-commands available only in guestfish. + * + * Note (1): args/return value, proc_nr and tests fields are all + * meaningless. The only fields which are actually used are the + * shortname, FishAlias flags, shortdesc and longdesc. + * + * Note (2): to refer to other commands, use L</shortname>. + * + * Note (3): keep this list sorted by shortname. + *) +let fish_commands = [ + ("alloc", (RErr,[]), -1, [FishAlias "allocate"], [], + "allocate and add a disk file", + " alloc filename size + +This creates an empty (zeroed) file of the given size, and then adds +so it can be further examined. + +For more advanced image creation, see L<qemu-img(1)> utility. + +Size can be specified using standard suffixes, eg. C<1M>. + +To create a sparse file, use L</sparse> instead. To create a +prepared disk image, see L</PREPARED DISK IMAGES>."); + + ("copy_in", (RErr,[]), -1, [], [], + "copy local files or directories into an image", + " copy-in local [local ...] /remotedir + +C<copy-in> copies local files or directories recursively into the disk +image, placing them in the directory called C</remotedir> (which must +exist). This guestfish meta-command turns into a sequence of +L</tar-in> and other commands as necessary. + +Multiple local files and directories can be specified, but the last +parameter must always be a remote directory. Wildcards cannot be +used."); + + ("copy_out", (RErr,[]), -1, [], [], + "copy remote files or directories out of an image", + " copy-out remote [remote ...] localdir + +C<copy-out> copies remote files or directories recursively out of the +disk image, placing them on the host disk in a local directory called +C<localdir> (which must exist). This guestfish meta-command turns +into a sequence of L</download>, L</tar-out> and other commands as +necessary. + +Multiple remote files and directories can be specified, but the last +parameter must always be a local directory. To download to the +current directory, use C<.> as in: + + copy-out /home . + +Wildcards cannot be used in the ordinary command, but you can use +them with the help of L</glob> like this: + + glob copy-out /home/* ."); + + ("echo", (RErr,[]), -1, [], [], + "display a line of text", + " echo [params ...] + +This echos the parameters to the terminal."); + + ("edit", (RErr,[]), -1, [FishAlias "vi"; FishAlias "emacs"], [], + "edit a file", + " edit filename + +This is used to edit a file. It downloads the file, edits it +locally using your editor, then uploads the result. + +The editor is C<$EDITOR>. However if you use the alternate +commands C<vi> or C<emacs> you will get those corresponding +editors."); + + ("glob", (RErr,[]), -1, [], [], + "expand wildcards in command", + " glob command args... + +Expand wildcards in any paths in the args list, and run C<command> +repeatedly on each matching path. + +See L</WILDCARDS AND GLOBBING>."); + + ("lcd", (RErr,[]), -1, [], [], + "change working directory", + " lcd directory + +Change the local directory, ie. the current directory of guestfish +itself. + +Note that C<!cd> won't do what you might expect."); + + ("man", (RErr,[]), -1, [FishAlias "manual"], [], + "open the manual", + " man + +Opens the manual page for guestfish."); + + ("more", (RErr,[]), -1, [FishAlias "less"], [], + "view a file", + " more filename + + less filename + +This is used to view a file. + +The default viewer is C<$PAGER>. However if you use the alternate +command C<less> you will get the C<less> command specifically."); + + ("reopen", (RErr,[]), -1, [], [], + "close and reopen libguestfs handle", + " reopen + +Close and reopen the libguestfs handle. It is not necessary to use +this normally, because the handle is closed properly when guestfish +exits. However this is occasionally useful for testing."); + + ("sparse", (RErr,[]), -1, [], [], + "create a sparse disk image and add", + " sparse filename size + +This creates an empty sparse file of the given size, and then adds +so it can be further examined. + +In all respects it works the same as the L</alloc> command, except that +the image file is allocated sparsely, which means that disk blocks are +not assigned to the file until they are needed. Sparse disk files +only use space when written to, but they are slower and there is a +danger you could run out of real disk space during a write operation. + +For more advanced image creation, see L<qemu-img(1)> utility. + +Size can be specified using standard suffixes, eg. C<1M>."); + + ("supported", (RErr,[]), -1, [], [], + "list supported groups of commands", + " supported + +This command returns a list of the optional groups +known to the daemon, and indicates which ones are +supported by this build of the libguestfs appliance. + +See also L<guestfs(3)/AVAILABILITY>."); + + ("time", (RErr,[]), -1, [], [], + "print elapsed time taken to run a command", + " time command args... + +Run the command as usual, but print the elapsed time afterwards. This +can be useful for benchmarking operations."); + +] diff --git a/generator/generator_actions.mli b/generator/generator_actions.mli index 0ce6274f..711bf4fa 100644 --- a/generator/generator_actions.mli +++ b/generator/generator_actions.mli @@ -38,3 +38,6 @@ val test_functions : Generator_types.action list val max_proc_nr : int (** The largest procedure number used (also saved in [src/MAX_PROC_NR] and used as the minor version number of the shared library). *) + +val fish_commands : Generator_types.action list +(** Non-API meta-commands available only in guestfish. *) diff --git a/generator/generator_checks.ml b/generator/generator_checks.ml index f30a2868..98649e26 100644 --- a/generator/generator_checks.ml +++ b/generator/generator_checks.ml @@ -49,7 +49,7 @@ let () = if String.contains name '-' then failwithf "function name %s should not contain '-', use '_' instead." name - ) all_functions; + ) (all_functions @ fish_commands); (* Check function parameter/return names. *) List.iter ( @@ -120,14 +120,14 @@ let () = let c = shortdesc.[String.length shortdesc-1] in if c = '\n' || c = '.' then failwithf "short description of %s should not end with . or \\n." name - ) all_functions; + ) (all_functions @ fish_commands); (* Check long descriptions. *) List.iter ( fun (name, _, _, _, _, _, longdesc) -> if longdesc.[String.length longdesc-1] = '\n' then failwithf "long description of %s should not end with \\n." name - ) all_functions; + ) (all_functions @ fish_commands); (* Check proc_nrs. *) List.iter ( diff --git a/generator/generator_fish.ml b/generator/generator_fish.ml index ef675d35..930ef151 100644 --- a/generator/generator_fish.ml +++ b/generator/generator_fish.ml @@ -43,6 +43,9 @@ let generate_fish_cmds () = fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags) ) all_functions_sorted in + let all_functions_and_fish_commands_sorted = + List.sort action_compare (all_functions_sorted @ fish_commands) in + pr "#include <config.h>\n"; pr "\n"; pr "#include <stdio.h>\n"; @@ -70,7 +73,7 @@ let generate_fish_cmds () = let name = replace_char name '_' '-' in pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n" name shortdesc - ) all_functions_sorted; + ) all_functions_and_fish_commands_sorted; pr " printf (\" %%s\\n\","; pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n"; pr "}\n"; @@ -79,12 +82,41 @@ let generate_fish_cmds () = (* display_command function, which implements guestfish -h cmd *) pr "int display_command (const char *cmd)\n"; pr "{\n"; + + List.iter ( + fun (name, style, _, flags, _, shortdesc, longdesc) -> + let name2 = replace_char name '_' '-' in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in + let describe_alias = + if aliases <> [] then + sprintf "\n\nYou can use %s as an alias for this command." + (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases)) + else "" in + + pr " if ("; + pr "STRCASEEQ (cmd, \"%s\")" name; + if name <> name2 then + pr " || STRCASEEQ (cmd, \"%s\")" name2; + List.iter ( + fun alias -> + pr " || STRCASEEQ (cmd, \"%s\")" alias + ) aliases; + pr ") {\n"; + pr " pod2text (\"%s\", _(\"%s\"), %S);\n" + name2 shortdesc + ("=head1 DESCRIPTION\n\n" ^ + longdesc ^ describe_alias); + pr " return 0;\n"; + pr " }\n"; + pr " else\n" + ) fish_commands; + List.iter ( fun (name, style, _, flags, _, shortdesc, longdesc) -> let name2 = replace_char name '_' '-' in - let alias = - try find_map (function FishAlias n -> Some n | _ -> None) flags - with Not_found -> name in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in let longdesc = replace_str longdesc "C<guestfs_" "C<" in let synopsis = match snd style with @@ -123,16 +155,19 @@ Guestfish will prompt for these separately." | Some txt -> "\n\n" ^ txt in let describe_alias = - if name <> alias then - sprintf "\n\nYou can use '%s' as an alias for this command." alias + if aliases <> [] then + sprintf "\n\nYou can use %s as an alias for this command." + (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases)) else "" in pr " if ("; pr "STRCASEEQ (cmd, \"%s\")" name; if name <> name2 then pr " || STRCASEEQ (cmd, \"%s\")" name2; - if name <> alias then - pr " || STRCASEEQ (cmd, \"%s\")" alias; + List.iter ( + fun alias -> + pr " || STRCASEEQ (cmd, \"%s\")" alias + ) aliases; pr ") {\n"; pr " pod2text (\"%s\", _(\"%s\"), %S);\n" name2 shortdesc @@ -143,6 +178,7 @@ Guestfish will prompt for these separately." pr " }\n"; pr " else\n" ) all_functions; + pr " return display_builtin_command (cmd);\n"; pr "}\n"; pr "\n"; @@ -465,22 +501,25 @@ Guestfish will prompt for these separately." (* run_action function *) pr "int run_action (const char *cmd, int argc, char *argv[])\n"; pr "{\n"; + List.iter ( fun (name, _, _, flags, _, _, _) -> let name2 = replace_char name '_' '-' in - let alias = - try find_map (function FishAlias n -> Some n | _ -> None) flags - with Not_found -> name in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in pr " if ("; pr "STRCASEEQ (cmd, \"%s\")" name; if name <> name2 then pr " || STRCASEEQ (cmd, \"%s\")" name2; - if name <> alias then - pr " || STRCASEEQ (cmd, \"%s\")" alias; + List.iter ( + fun alias -> + pr " || STRCASEEQ (cmd, \"%s\")" alias; + ) aliases; pr ")\n"; pr " return run_%s (cmd, argc, argv);\n" name; pr " else\n"; - ) all_functions; + ) all_functions_and_fish_commands_sorted; + pr " {\n"; pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n"; pr " if (command_num == 1)\n"; @@ -526,12 +565,10 @@ static const char *const commands[] = { List.map ( fun (name, _, _, flags, _, _, _) -> let name2 = replace_char name '_' '-' in - let alias = - try find_map (function FishAlias n -> Some n | _ -> None) flags - with Not_found -> name in - - if name <> alias then [name2; alias] else [name2] - ) all_functions in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in + name2 :: aliases + ) (all_functions @ fish_commands) in let commands = List.flatten commands in List.iter (pr " \"%s\",\n") commands; @@ -611,15 +648,13 @@ and generate_fish_actions_pod () = "L</" ^ replace_char sub '_' '-' ^ ">" ) longdesc in let name = replace_char name '_' '-' in - let alias = - try find_map (function FishAlias n -> Some n | _ -> None) flags - with Not_found -> name in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in - pr "=head2 %s" name; - if name <> alias then - pr " | %s" alias; - pr "\n"; - pr "\n"; + List.iter ( + fun name -> + pr "=head2 %s\n\n" name + ) (name :: aliases); pr " %s" name; List.iter ( function @@ -657,6 +692,21 @@ Guestfish will prompt for these separately.\n\n"; | Some txt -> pr "%s\n\n" txt ) all_functions_sorted +(* Generate documentation for guestfish-only commands. *) +and generate_fish_commands_pod () = + List.iter ( + fun (name, style, _, flags, _, _, longdesc) -> + let name = replace_char name '_' '-' in + let aliases = + filter_map (function FishAlias n -> Some n | _ -> None) flags in + + List.iter ( + fun name -> + pr "=head2 %s\n\n" name + ) (name :: aliases); + pr "%s\n\n" longdesc; + ) fish_commands + and generate_fish_prep_options_h () = generate_header CStyle GPLv2plus; diff --git a/generator/generator_main.ml b/generator/generator_main.ml index cdf7773f..401ae605 100644 --- a/generator/generator_main.ml +++ b/generator/generator_main.ml @@ -90,6 +90,7 @@ Run it from the top source directory using the command output_to "capitests/tests.c" generate_tests; output_to "fish/cmds.c" generate_fish_cmds; output_to "fish/completion.c" generate_fish_completion; + output_to "fish/guestfish-commands.pod" generate_fish_commands_pod; output_to "fish/guestfish-actions.pod" generate_fish_actions_pod; output_to "fish/prepopts.c" generate_fish_prep_options_c; output_to "fish/prepopts.h" generate_fish_prep_options_h; diff --git a/generator/generator_utils.ml b/generator/generator_utils.ml index 2bdcc0d8..b7401db0 100644 --- a/generator/generator_utils.ml +++ b/generator/generator_utils.ml @@ -303,3 +303,5 @@ let pod2text ~width name longdesc = pod2text_memo_updated (); lines +(* Compare two actions (for sorting). *) +let action_compare (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) = compare n1 n2 diff --git a/generator/generator_utils.mli b/generator/generator_utils.mli index 7bc0dde1..f43a276d 100644 --- a/generator/generator_utils.mli +++ b/generator/generator_utils.mli @@ -96,3 +96,6 @@ val pod2text : width:int -> string -> string -> string list plain ASCII lines of text. This is the slowest part of autogeneration, so the results are memoized into a temporary file. *) + +val action_compare : Generator_types.action -> Generator_types.action -> int +(** Compare the names of two actions, for sorting. *) |