resize: Add --machine-readable option for machine friendly output.
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 26 Aug 2011 21:34:49 +0000 (22:34 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 26 Aug 2011 21:34:49 +0000 (22:34 +0100)
resize/progress.ml
resize/progress.mli
resize/progress_c.c
resize/resize.ml
resize/virt-resize.pod

index 0018172..0ae72a3 100644 (file)
@@ -23,30 +23,32 @@ open Utils
 module G = Guestfs
 
 type progress_bar
 module G = Guestfs
 
 type progress_bar
-external progress_bar_init : unit -> progress_bar
+external progress_bar_init : machine_readable:bool -> progress_bar
   = "virt_resize_progress_bar_init"
 external progress_bar_reset : progress_bar -> unit
   = "virt_resize_progress_bar_reset"
 external progress_bar_set : progress_bar -> int64 -> int64 -> unit
   = "virt_resize_progress_bar_set"
 
   = "virt_resize_progress_bar_init"
 external progress_bar_reset : progress_bar -> unit
   = "virt_resize_progress_bar_reset"
 external progress_bar_set : progress_bar -> int64 -> int64 -> unit
   = "virt_resize_progress_bar_set"
 
-(* Initialize the C mini library. *)
-let bar = progress_bar_init ()
+let set_up_progress_bar ?(machine_readable = false) (g : Guestfs.guestfs) =
+  (* Initialize the C mini library. *)
+  let bar = progress_bar_init ~machine_readable in
 
 
-(* Reset the progress bar before every libguestfs function. *)
-let enter_callback g event evh buf array =
-  if event = G.EVENT_ENTER then
-    progress_bar_reset bar
+  (* Reset the progress bar before every libguestfs function. *)
+  let enter_callback g event evh buf array =
+    if event = G.EVENT_ENTER then
+      progress_bar_reset bar
+  in
 
 
-(* A progress event: move the progress bar. *)
-let progress_callback g event evh buf array =
-  if event = G.EVENT_PROGRESS && Array.length array >= 4 then (
-    let position = array.(2)
-    and total = array.(3) in
+  (* A progress event: move the progress bar. *)
+  let progress_callback g event evh buf array =
+    if event = G.EVENT_PROGRESS && Array.length array >= 4 then (
+      let position = array.(2)
+      and total = array.(3) in
 
 
-    progress_bar_set bar position total
-  )
+      progress_bar_set bar position total
+    )
+  in
 
 
-let set_up_progress_bar (g : Guestfs.guestfs) =
   ignore (g#set_event_callback enter_callback [G.EVENT_ENTER]);
   ignore (g#set_event_callback progress_callback [G.EVENT_PROGRESS])
   ignore (g#set_event_callback enter_callback [G.EVENT_ENTER]);
   ignore (g#set_event_callback progress_callback [G.EVENT_PROGRESS])
index 31deb09..cd20e21 100644 (file)
@@ -16,4 +16,4 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *)
 
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *)
 
-val set_up_progress_bar : Guestfs.guestfs -> unit
+val set_up_progress_bar : ?machine_readable:bool -> Guestfs.guestfs -> unit
index dddf787..52e653b 100644 (file)
@@ -53,18 +53,22 @@ static struct custom_operations progress_bar_custom_operations = {
 };
 
 value
 };
 
 value
-virt_resize_progress_bar_init (value unitv)
+virt_resize_progress_bar_init (value machine_readablev)
 {
 {
-  CAMLparam1 (unitv);
+  CAMLparam1 (machine_readablev);
   CAMLlocal1 (barv);
   struct progress_bar *bar;
   CAMLlocal1 (barv);
   struct progress_bar *bar;
+  int machine_readable = Bool_val (machine_readablev);
+  unsigned flags = 0;
 
   /* XXX Have to do this to get nl_langinfo to work properly.  However
    * we should really only call this from main.
    */
   setlocale (LC_ALL, "");
 
 
   /* XXX Have to do this to get nl_langinfo to work properly.  However
    * we should really only call this from main.
    */
   setlocale (LC_ALL, "");
 
-  bar = progress_bar_init (0);
+  if (machine_readable)
+    flags |= PROGRESS_BAR_MACHINE_READABLE;
+  bar = progress_bar_init (flags);
   if (bar == NULL)
     caml_raise_out_of_memory ();
 
   if (bar == NULL)
     caml_raise_out_of_memory ();
 
index d4455eb..1bd9632 100644 (file)
@@ -30,7 +30,7 @@ let prog = Filename.basename Sys.executable_name
 
 let infile, outfile, copy_boot_loader, debug, deletes, dryrun,
   expand, expand_content, extra_partition, format, ignores,
 
 let infile, outfile, copy_boot_loader, debug, deletes, dryrun,
   expand, expand_content, extra_partition, format, ignores,
-  lv_expands, ntfsresize_force, output_format,
+  lv_expands, machine_readable, ntfsresize_force, output_format,
   quiet, resizes, resizes_force, shrink =
   let display_version () =
     let g = new G.guestfs () in
   quiet, resizes, resizes_force, shrink =
   let display_version () =
     let g = new G.guestfs () in
@@ -57,6 +57,7 @@ let infile, outfile, copy_boot_loader, debug, deletes, dryrun,
   let format = ref "" in
   let ignores = ref [] in
   let lv_expands = ref [] in
   let format = ref "" in
   let ignores = ref [] in
   let lv_expands = ref [] in
+  let machine_readable = ref false in
   let ntfsresize_force = ref false in
   let output_format = ref "" in
   let quiet = ref false in
   let ntfsresize_force = ref false in
   let output_format = ref "" in
   let quiet = ref false in
@@ -83,6 +84,7 @@ let infile, outfile, copy_boot_loader, debug, deletes, dryrun,
     "--LV-expand", Arg.String (add lv_expands), "lv -\"-";
     "--lvexpand", Arg.String (add lv_expands), "lv -\"-";
     "--LVexpand", Arg.String (add lv_expands), "lv -\"-";
     "--LV-expand", Arg.String (add lv_expands), "lv -\"-";
     "--lvexpand", Arg.String (add lv_expands), "lv -\"-";
     "--LVexpand", Arg.String (add lv_expands), "lv -\"-";
+    "--machine-readable", Arg.Set machine_readable, " Make output machine readable";
     "-n",        Arg.Set dryrun,            " Don't perform changes";
     "--dryrun",  Arg.Set dryrun,            " -\"-";
     "--dry-run", Arg.Set dryrun,            " -\"-";
     "-n",        Arg.Set dryrun,            " Don't perform changes";
     "--dryrun",  Arg.Set dryrun,            " -\"-";
     "--dry-run", Arg.Set dryrun,            " -\"-";
@@ -125,6 +127,7 @@ read the man page virt-resize(1).
   let format = match !format with "" -> None | str -> Some str in
   let ignores = List.rev !ignores in
   let lv_expands = List.rev !lv_expands in
   let format = match !format with "" -> None | str -> Some str in
   let ignores = List.rev !ignores in
   let lv_expands = List.rev !lv_expands in
+  let machine_readable = !machine_readable in
   let ntfsresize_force = !ntfsresize_force in
   let output_format = match !output_format with "" -> None | str -> Some str in
   let quiet = !quiet in
   let ntfsresize_force = !ntfsresize_force in
   let output_format = match !output_format with "" -> None | str -> Some str in
   let quiet = !quiet in
@@ -132,6 +135,25 @@ read the man page virt-resize(1).
   let resizes_force = List.rev !resizes_force in
   let shrink = match !shrink with "" -> None | str -> Some str in
 
   let resizes_force = List.rev !resizes_force in
   let shrink = match !shrink with "" -> None | str -> Some str in
 
+  (* No arguments and machine-readable mode?  Print out some facts
+   * about what this binary supports.  We only need to print out new
+   * things added since this option, or things which depend on features
+   * of the appliance.
+   *)
+  if !disks = [] && machine_readable then (
+    printf "virt-resize\n";
+    printf "ntfsresize-force\n";
+    printf "32bitok\n";
+    let g = new G.guestfs () in
+    g#add_drive_opts "/dev/null";
+    g#launch ();
+    if feature_available g [| "ntfsprogs"; "ntfs3g" |] then
+      printf "ntfs\n";
+    if feature_available g [| "btrfs" |] then
+      printf "btrfs\n";
+    exit 0
+  );
+
   (* Verify we got exactly 2 disks. *)
   let infile, outfile =
     match List.rev !disks with
   (* Verify we got exactly 2 disks. *)
   let infile, outfile =
     match List.rev !disks with
@@ -141,7 +163,7 @@ read the man page virt-resize(1).
 
   infile, outfile, copy_boot_loader, debug, deletes, dryrun,
   expand, expand_content, extra_partition, format, ignores,
 
   infile, outfile, copy_boot_loader, debug, deletes, dryrun,
   expand, expand_content, extra_partition, format, ignores,
-  lv_expands, ntfsresize_force, output_format,
+  lv_expands, machine_readable, ntfsresize_force, output_format,
   quiet, resizes, resizes_force, shrink
 
 (* Default to true, since NTFS and btrfs support are usually available. *)
   quiet, resizes, resizes_force, shrink
 
 (* Default to true, since NTFS and btrfs support are usually available. *)
@@ -154,7 +176,7 @@ let connect_both_disks () =
   if debug then g#set_trace true;
   g#add_drive_opts ?format ~readonly:true infile;
   g#add_drive_opts ?format:output_format ~readonly:false outfile;
   if debug then g#set_trace true;
   g#add_drive_opts ?format ~readonly:true infile;
   g#add_drive_opts ?format:output_format ~readonly:false outfile;
-  if not quiet then Progress.set_up_progress_bar g;
+  if not quiet then Progress.set_up_progress_bar ~machine_readable g;
   g#launch ();
 
   (* Set the filter to /dev/sda, in case there are any rogue
   g#launch ();
 
   (* Set the filter to /dev/sda, in case there are any rogue
@@ -910,7 +932,7 @@ let g =
     let g = new G.guestfs () in
     if debug then g#set_trace true;
     g#add_drive_opts ?format:output_format ~readonly:false outfile;
     let g = new G.guestfs () in
     if debug then g#set_trace true;
     g#add_drive_opts ?format:output_format ~readonly:false outfile;
-    if not quiet then Progress.set_up_progress_bar g;
+    if not quiet then Progress.set_up_progress_bar ~machine_readable g;
     g#launch ();
 
     g (* Return new handle. *)
     g#launch ();
 
     g (* Return new handle. *)
index 3a6af18..d03906c 100644 (file)
@@ -349,6 +349,12 @@ You can give this option multiple times, I<but> it doesn't
 make sense to do this unless the logical volumes you specify
 are all in different volume groups.
 
 make sense to do this unless the logical volumes you specify
 are all in different volume groups.
 
+=item B<--machine-readable>
+
+This option is used to make the output more machine friendly
+when being parsed by other programs.  See
+L</MACHINE READABLE OUTPUT> below.
+
 =item B<-n>
 
 =item B<--dryrun>
 =item B<-n>
 
 =item B<--dryrun>
@@ -483,6 +489,58 @@ Display version number and exit.
 
 =back
 
 
 =back
 
+=head1 MACHINE READABLE OUTPUT
+
+The I<--machine-readable> option can be used to make the output more
+machine friendly, which is useful when calling virt-resize from other
+programs, GUIs etc.
+
+There are two ways to use this option.
+
+Firstly use the option on its own to query the capabilities of the
+virt-resize binary.  Typical output looks like this:
+
+ $ virt-resize --machine-readable
+ virt-resize
+ ntfsresize-force
+ 32bitok
+ ntfs
+ btrfs
+
+A list of features is printed, one per line, and the program exits
+with status 0.
+
+Secondly use the option in conjunction with other options to make the
+regular program output more machine friendly.
+
+At the moment this means:
+
+=over 4
+
+=item 1.
+
+Progress bar messages can be parsed from stdout by looking for this
+regular expression:
+
+ ^[0-9]+/[0-9]+$
+
+=item 2.
+
+The calling program should treat messages sent to stdout (except for
+progress bar messages) as status messages.  They can be logged and/or
+displayed to the user.
+
+=item 3.
+
+The calling program should treat messages sent to stderr as error
+messages.  In addition, virt-resize exits with a non-zero status code
+if there was a fatal error.
+
+=back
+
+Versions of the program prior to 1.13.9 did not support the
+I<--machine-readable> option and will return an error.
+
 =head1 NOTES
 
 =head2 "Partition 1 does not end on cylinder boundary."
 =head1 NOTES
 
 =head2 "Partition 1 does not end on cylinder boundary."