From: Richard W.M. Jones Date: Sun, 4 Sep 2011 13:21:53 +0000 (+0100) Subject: Add status bar, progress bar, command line. X-Git-Url: http://git.annexia.org/?p=virt-resize-ui.git;a=commitdiff_plain;h=d8fa4424dfb3ed53a7282fc2551d2293d0f5d42b;hp=ec0cd9b799e2cf0686f11df45f296d00e09760de Add status bar, progress bar, command line. --- diff --git a/.depend b/.depend index 7cd1b72..93e710b 100644 --- a/.depend +++ b/.depend @@ -1,3 +1,6 @@ +cmdline.cmi: +cmdline.cmo: utils.cmi config.cmi cmdline.cmi +cmdline.cmx: utils.cmx config.cmx cmdline.cmi config.cmi: config.cmo: config.cmi config.cmx: config.cmi @@ -7,8 +10,8 @@ destination_tab.cmx: destination_tab.cmi logvols_tab.cmi: logvols_tab.cmo: logvols_tab.cmi logvols_tab.cmx: logvols_tab.cmi -main.cmo: window.cmi slave.cmi -main.cmx: window.cmx slave.cmx +main.cmo: window.cmi utils.cmi slave.cmi config.cmi cmdline.cmi +main.cmx: window.cmx utils.cmx slave.cmx config.cmx cmdline.cmx partitions_tab.cmi: partitions_tab.cmo: partitions_tab.cmi partitions_tab.cmx: partitions_tab.cmi @@ -18,12 +21,12 @@ slave.cmx: utils.cmx slave_types.cmx slave.cmi slave_types.cmi: slave_types.cmo: slave_types.cmi slave_types.cmx: slave_types.cmi -source_tab.cmi: -source_tab.cmo: utils.cmi slave_types.cmi slave.cmi source_tab.cmi -source_tab.cmx: utils.cmx slave_types.cmx slave.cmx source_tab.cmi +source_tab.cmi: cmdline.cmi +source_tab.cmo: utils.cmi slave_types.cmi slave.cmi cmdline.cmi source_tab.cmi +source_tab.cmx: utils.cmx slave_types.cmx slave.cmx cmdline.cmx source_tab.cmi utils.cmi: utils.cmo: config.cmi utils.cmi utils.cmx: config.cmx utils.cmi -window.cmi: -window.cmo: source_tab.cmi partitions_tab.cmi logvols_tab.cmi destination_tab.cmi window.cmi -window.cmx: source_tab.cmx partitions_tab.cmx logvols_tab.cmx destination_tab.cmx window.cmi +window.cmi: source_tab.cmi +window.cmo: utils.cmi source_tab.cmi partitions_tab.cmi logvols_tab.cmi destination_tab.cmi window.cmi +window.cmx: utils.cmx source_tab.cmx partitions_tab.cmx logvols_tab.cmx destination_tab.cmx window.cmi diff --git a/Makefile.am b/Makefile.am index 8962540..5fe6bce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,8 @@ CLEANFILES = *.cmi *.cmo *.cmx *.cmxa *.o virt-resize-ui *~ # These are listed here in alphabetical order. SOURCES = \ + cmdline.mli \ + cmdline.ml \ config.mli \ destination_tab.mli \ destination_tab.ml \ @@ -55,6 +57,7 @@ BUILT_SOURCES = \ OBJECTS = \ config.cmo \ utils.cmo \ + cmdline.cmo \ slave_types.cmo \ slave.cmo \ source_tab.cmo \ diff --git a/cmdline.ml b/cmdline.ml new file mode 100644 index 0000000..22e8d0b --- /dev/null +++ b/cmdline.ml @@ -0,0 +1,99 @@ +(* Virt resize UI. + * Copyright (C) 2011 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. + *) + +open Printf + +open Utils + +type cli_request = + | Empty_window + | Open_guest of string + | Open_images of (string * string option) list + +let display_version () = + printf "%s %s\n" Config.package Config.version; + exit 0 + +let format = ref None +let images = ref [] +let guests = ref [] + +let set_connect = function + | "" -> set_connect_uri None + | uri -> set_connect_uri (Some uri) +let set_format = function + | "" -> format := None + | f -> format := Some f +let add_image image = + images := (image, !format) :: !images +let add_guest guest = + guests := guest :: !guests + +(* Parse command line arguments. *) +let argspec = Arg.align [ + "-a", Arg.String add_image, "image Open disk image"; + "--add", Arg.String add_image, "image Open disk image"; + "-c", Arg.String set_connect, "uri Connect to libvirt URI"; + "--connect", Arg.String set_connect, "uri Connect to libvirt URI"; + "-d", Arg.String add_guest, "guest Open libvirt guest"; + "--domain", Arg.String add_guest, "guest Open libvirt guest"; + "--format", Arg.String set_format, "format Set format"; + "-v", Arg.Unit set_verbose_flag, " Enable debugging messages"; + "--verbose", Arg.Unit set_verbose_flag, " Enable debugging messages"; + "-V", Arg.Unit display_version, " Display version and exit"; + "--version", Arg.Unit display_version, " Display version and exit"; + "-x", Arg.Unit set_trace_flag, " Enable tracing of libguestfs calls"; +] + +let prog = Filename.basename Sys.executable_name + +let anon_fun _ = + raise (Arg.Bad "unknown argument") + +let usage_msg = + sprintf "\ +%s: graphical guest filesystem browser + +Usage: + %s + Open the program with an empty window. + + %s -a disk.img [-a disk.img [...]] + Start with a guest from a disk image file. + + %s -d guest + Start with the named libvirt guest. + +Options:" + prog prog prog prog + +let command_line () = + Arg.parse argspec anon_fun usage_msg; + + (* Verify number of -a and -d options given on the command line. *) + let images = List.rev !images in + let guests = List.rev !guests in + + match images, guests with + | [], [] -> Empty_window + | _, [] -> Open_images images + | [], [guest] -> Open_guest guest + | [], _ -> + failwith "cannot use -d option more than once" + | _, _ -> + failwith "cannot mix -a and -d options" diff --git a/cmdline.mli b/cmdline.mli new file mode 100644 index 0000000..3ad75c2 --- /dev/null +++ b/cmdline.mli @@ -0,0 +1,34 @@ +(* Virt resize UI. + * Copyright (C) 2011 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. + *) + +(** Handle the command line arguments. *) + +type cli_request = + | Empty_window + | Open_guest of string + | Open_images of (string * string option) list + (** The initial action requested by the user on the command line. + + [Empty_window] means nothing was requested on the command line. + + [Open_guest] means to open a guest (-d option). + + [Open_images] means to open a list of disk images (-a option). *) + +val command_line : unit -> cli_request + (** Read the command line and return {!cli_request}. *) diff --git a/main.ml b/main.ml index 775f006..1a3e8db 100644 --- a/main.ml +++ b/main.ml @@ -16,7 +16,37 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) +open Utils + let () = - ignore (new Window.window); + let cli_request = Cmdline.command_line () in + + (* If we're in verbose mode, print some debug information which + could be useful in bug reports. *) + if verbose () then ( + debug "%s %s" Config.package Config.version; + debug "libguestfs %s" (libguestfs_version_string ()); + debug "libvirt %s" (libvirt_version_string ()); + ); + + (* Create the main window. *) + let w = new Window.window in + + (* Wire up hooks that carry messages from the slave thread + * to the main thread. + *) +(* + Slave.set_failure_hook w#failure; + Slave.set_busy_hook w#throbber_busy; + Slave.set_idle_hook w#throbber_idle; +*) + Slave.set_status_hook w#set_statusbar; + Slave.set_progress_hook w#progress; + + (* What did the user request on the command line? *) + w#source_tab#run_cli_request cli_request; + + (* Run the main display thread. When this returns, the application + has been closed so force the slave thread to exit. *) GtkThread.main (); Slave.exit_thread () diff --git a/source_tab.ml b/source_tab.ml index f791e80..797ba4a 100644 --- a/source_tab.ml +++ b/source_tab.ml @@ -68,36 +68,54 @@ object (self) method private opened inspection_data = (* We expect that there are some filesystems in the image, otherwise fail. *) - if inspection_data.insp_all_filesystems = [] then - inspection.inspection_label#set_text - "error: no filesystems were found in the selected disk image or guest" + let nr_filesystems = List.length inspection_data.insp_all_filesystems in + if nr_filesystems = 0 then + inspection.inspection_label#set_label + "error: no filesystems were found in the selected disk image or guest" else ( (match inspection_data.insp_oses with | [] -> (* no OS, but there were filesystems *) - inspection.inspection_label#set_text - "warning: no operating systems were recognized in this disk image or guest" - - | [ os ] -> - let label = - sprintf "%s %s %d.%d" - os.insp_type os.insp_distro - os.insp_major_version os.insp_minor_version in - let label = - if os.insp_product_name <> "" then - label ^ " (" ^ os.insp_product_name ^ ")" + let markup = + sprintf "%d filesystem(s) found\nwarning: no operating systems were recognized in this disk image or guest" + nr_filesystems in + inspection.inspection_label#set_label markup + + | os :: oses -> + let markup = + if os.insp_product_name = "" then + sprintf "%s %s %d.%d\n" + os.insp_type os.insp_distro + os.insp_major_version os.insp_minor_version else - label in - inspection.inspection_label#set_text label + sprintf "%s\n" (markup_escape os.insp_product_name) in + let markup = + markup ^ sprintf "with %d filesystem(s)\n" nr_filesystems in - | _ -> - inspection.inspection_label#set_text - "warning: resizing multi-boot virtual machines may not be successful" + let markup = + if oses <> [] then + markup ^ "warning: resizing multi-boot virtual machines may not be successful" + else markup in + + inspection.inspection_label#set_label markup ); (* Raise the ready signal. *) ready_signal#call () ) + method run_cli_request = function + | Cmdline.Empty_window -> () + | Cmdline.Open_images images -> + let msg = Slave.Open_images (images, self#opened) in + Slave.send_message msg + | Cmdline.Open_guest guest -> +(* + (* Open libvirt connection, and in the callback open the guest. *) + let uri = connect_uri () in + Slave.connect uri (self#when_connected_cli_request guest) +*) + assert false (* XXX not implemented *) + initializer (* Set the inputs to be sensitive according to the state of the top level radio buttons. *) @@ -206,6 +224,7 @@ let tab () = let inspection = let label = GMisc.label ~packing:(tbl#attach ~top:7 ~left:0 ~right:2) () in + label#set_use_markup true; { inspection_label = label } in (* Return the object. *) diff --git a/source_tab.mli b/source_tab.mli index 7da62ad..f492088 100644 --- a/source_tab.mli +++ b/source_tab.mli @@ -39,6 +39,11 @@ object ('a) information requested, and the source disk image or guest has been opened successfully. *) method ready : callback:(unit -> unit) -> GtkSignal.id + + (** This function performs the {!Cmdline.cli_request} operation. + The actual operation happens asynchronously after this function + has returned. *) + method run_cli_request : Cmdline.cli_request -> unit end val tab : unit -> tab diff --git a/window.ml b/window.ml index b00c6b0..a42f1a1 100644 --- a/window.ml +++ b/window.ml @@ -16,6 +16,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) +open Printf + +open Utils + type file_menu = { quit_item : GMenu.menu_item; } @@ -41,6 +45,34 @@ type buttons = { class window = let title = "Resize a virtual machine - virt-resize-ui" in object (self) + val mutable tabs = None + val mutable statusbar_context = None + val mutable progress_bar : GRange.progress_bar option = None + + method source_tab = (Option.get tabs).source_tab + + method set_statusbar msg = + Option.may ( + fun c -> + c#pop (); + ignore (c#push msg) + ) statusbar_context + + method progress (position, total) = + Option.may ( + fun pb -> + if position = 0L && total = 1L then + pb#pulse () + else ( + let frac = Int64.to_float position /. Int64.to_float total in + if frac < 0. || frac > 1. then + eprintf "warning: progress bar out of range: %Ld / %Ld (%g)\n" + position total frac; + let frac = if frac < 0. then 0. else if frac > 1. then 1. else frac in + pb#set_fraction frac + ) + ) progress_bar + initializer (* Window. *) let window = GWindow.window ~width:700 ~height:700 ~title () in @@ -63,8 +95,10 @@ object (self) let about = factory#add_item "About virt-resize-ui ..." in { about_item = about } in + ignore help_menu; + (* Tabbed notebook for main part of the display. *) - let tabs = + tabs <- ( let nb = GPack.notebook ~packing:(vbox#pack ~expand:true ~fill:true) () in let src = Source_tab.tab () in @@ -85,8 +119,15 @@ object (self) (GMisc.label ~text:"Expand logical volumes" () :> GObj.widget) in ignore (nb#append_page ~tab_label (lvs :> GObj.widget)); - { source_tab = src; destination_tab = dest; - partitions_tab = parts; logvols_tab = lvs } in + Some { source_tab = src; destination_tab = dest; + partitions_tab = parts; logvols_tab = lvs }); + + (* Status bar and progress bar. *) + let hbox = GPack.hbox ~spacing:4 ~packing:vbox#pack () in + progress_bar <- Some (GRange.progress_bar ~packing:hbox#pack ()); + let statusbar = GMisc.statusbar ~packing:(hbox#pack ~expand:true) () in + statusbar_context <- Some (statusbar#new_context ~name:"Standard"); + ignore ((Option.get statusbar_context)#push title); (* Buttons. *) let buttons = @@ -104,9 +145,6 @@ object (self) { prev_button = prev; next_button = next; go_button = go; exit_button = ex } in - ignore help_menu; - ignore tabs; - (* Quit button. *) let quit _ = GMain.quit (); false in ignore (window#connect#destroy ~callback:GMain.quit); diff --git a/window.mli b/window.mli index f8eadac..0a42362 100644 --- a/window.mli +++ b/window.mli @@ -20,5 +20,13 @@ class window : object - (* empty, for now *) + (** Return the source tab. *) + method source_tab : Source_tab.tab + + (** Set the statusbar text. *) + method set_statusbar : string -> unit + + (** Move the progress bar. *) + method progress : (int64 * int64) -> unit + end