[Libguestfs] [PATCH 4/4] fish: Implement progress bars in guestfish.

Richard W.M. Jones rjones at redhat.com
Sat Aug 28 12:04:31 UTC 2010


ZX81-stylie graphics.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines.  Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
-------------- next part --------------
>From 7151628d09985d4156c2684118beedbf339c953b Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
Date: Sat, 28 Aug 2010 12:49:55 +0100
Subject: [PATCH 4/4] fish: Implement progress bars in guestfish.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The output you get will look something like this:

><fs> copy-size /large /large2 2G
 50% ?????????????????????????????????????????????????????

The progress bar is updated once per second, and is not displayed
at all for operations which take less than one second.

You can disable progress bars by using the flag --no-progress-bars,
and you can enable progress bars in non-interactive sessions with
the flag --progress-bars.

A good way to test this is to use the following command:

guestfish --progress-bars \
          -N fs:ext4:10G \
          -m /dev/sda1 \
          fallocate64 /test 2G : \
          copy-size /test /test2 2G
---
 fish/Makefile.am   |    1 +
 fish/fish.c        |   20 ++++++++++++
 fish/fish.h        |    2 +
 fish/guestfish.pod |   11 +++++++
 fish/progress.c    |   86 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 fish/reopen.c      |    3 ++
 po/POTFILES.in     |    1 +
 7 files changed, 124 insertions(+), 0 deletions(-)
 create mode 100644 fish/progress.c

diff --git a/fish/Makefile.am b/fish/Makefile.am
index 4060f1f..7b1826c 100644
--- a/fish/Makefile.am
+++ b/fish/Makefile.am
@@ -49,6 +49,7 @@ guestfish_SOURCES = \
 	man.c \
 	more.c \
 	prep.c \
+	progress.c \
 	rc.c \
 	reopen.c \
 	supported.c \
diff --git a/fish/fish.c b/fish/fish.c
index c4ade8c..7d26d4b 100644
--- a/fish/fish.c
+++ b/fish/fish.c
@@ -85,6 +85,8 @@ static void cleanup_readline (void);
 static void add_history_line (const char *);
 #endif
 
+static int override_progress_bars = -1;
+
 /* Currently open libguestfs handle. */
 guestfs_h *g;
 
@@ -100,6 +102,7 @@ const char *libvirt_uri = NULL;
 int inspector = 0;
 int utf8_mode = 0;
 int have_terminfo = 0;
+int progress_bars = 0;
 
 static void __attribute__((noreturn))
 usage (int status)
@@ -137,6 +140,8 @@ usage (int status)
              "  -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
              "  -n|--no-sync         Don't autosync\n"
              "  -N|--new type        Create prepared disk (test1.img, ...)\n"
+             "  --progress-bars      Enable progress bars even when not interactive\n"
+             "  --no-progress-bars   Disable progress bars\n"
              "  --remote[=pid]       Send commands to remote %s\n"
              "  -r|--ro              Mount read-only\n"
              "  --selinux            Enable SELinux support\n"
@@ -182,6 +187,8 @@ main (int argc, char *argv[])
     { "new", 1, 0, 'N' },
     { "no-dest-paths", 0, 0, 'D' },
     { "no-sync", 0, 0, 'n' },
+    { "progress-bars", 0, 0, 0 },
+    { "no-progress-bars", 0, 0, 0 },
     { "remote", 2, 0, 0 },
     { "ro", 0, 0, 'r' },
     { "selinux", 0, 0, 0 },
@@ -267,6 +274,10 @@ main (int argc, char *argv[])
         guestfs_set_selinux (g, 1);
       } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
         keys_from_stdin = 1;
+      } else if (STREQ (long_options[option_index].name, "progress-bars")) {
+        override_progress_bars = 1;
+      } else if (STREQ (long_options[option_index].name, "no-progress-bars")) {
+        override_progress_bars = 0;
       } else {
         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
                  program_name, long_options[option_index].name, option_index);
@@ -500,6 +511,15 @@ main (int argc, char *argv[])
     }
   }
 
+  /* Decide if we display progress bars. */
+  progress_bars =
+    override_progress_bars >= 0
+    ? override_progress_bars
+    : (optind >= argc && isatty (0));
+
+  if (progress_bars)
+    guestfs_set_progress_callback (g, progress_callback, NULL);
+
   /* Interactive, shell script, or command(s) on the command line? */
   if (optind >= argc) {
     if (isatty (0))
diff --git a/fish/fish.h b/fish/fish.h
index 8106610..37966c1 100644
--- a/fish/fish.h
+++ b/fish/fish.h
@@ -55,6 +55,7 @@ extern int verbose;
 extern int command_num;
 extern int utf8_mode;
 extern int have_terminfo;
+extern int progress_bars;
 extern const char *libvirt_uri;
 extern int issue_command (const char *cmd, char *argv[], const char *pipe);
 extern void pod2text (const char *name, const char *shortdesc, const char *body);
@@ -73,6 +74,7 @@ extern void free_file_in (char *s);
 extern char *file_out (const char *arg);
 extern void extended_help_message (void);
 extern char *read_key (const char *param);
+extern void progress_callback (guestfs_h *g, void *data, int proc_nr, int serial, uint64_t position, uint64_t total);
 
 /* in cmds.c (auto-generated) */
 extern void list_commands (void);
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index cf1140a..162488d 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -232,6 +232,17 @@ alternative to the I<-a> option: whereas I<-a> adds an existing disk,
 I<-N> creates a preformatted disk with a filesystem and adds it.
 See L</PREPARED DISK IMAGES> below.
 
+=item B<--progress-bars>
+
+Enable progress bars, even when guestfish is used non-interactively.
+
+Progress bars are enabled by default when guestfish is used as an
+interactive shell.
+
+=item B<--no-progress-bars>
+
+Disable progress bars.
+
 =item B<--remote[=pid]>
 
 Send remote commands to C<$GUESTFISH_PID> or C<pid>.  See section
diff --git a/fish/progress.c b/fish/progress.c
new file mode 100644
index 0000000..2f9d9cb
--- /dev/null
+++ b/fish/progress.c
@@ -0,0 +1,86 @@
+/* guestfish - the filesystem interactive shell
+ * Copyright (C) 2010 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <guestfs.h>
+
+#include "fish.h"
+
+/* Include these last since they redefine symbols such as 'lines'
+ * which seriously breaks other headers.
+ */
+#include <term.h>
+#include <curses.h>
+
+/* Provided by termcap or terminfo emulation, but not defined
+ * in any header file.
+ */
+extern const char *UP;
+
+/* Callback which displays a progress bar. */
+void
+progress_callback (guestfs_h *g, void *data,
+                   int proc_nr, int serial,
+                   uint64_t position, uint64_t total)
+{
+  if (have_terminfo == 0) {
+  dumb:
+    printf ("%" PRIu64 "/%" PRIu64 "\n", position, total);
+  } else {
+    int cols = tgetnum ((char *) "co");
+    if (cols < 8) goto dumb;
+
+    /* Update an existing progress bar just printed? */
+    static int last_serial = 0;
+    if (serial == last_serial)
+      tputs (UP, 2, putchar);
+    last_serial = serial;
+
+    double ratio = (double) position / total;
+    if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1;
+
+    int percent = 100.0 * ratio;
+    printf ("%3d%% ", percent);
+
+    int dots = ratio * (double) (cols - 8);
+
+    if (utf8_mode) {
+      printf ("\u27e6");
+      int i;
+      for (i = 0; i < dots; ++i)
+        printf ("\u2593");
+      for (i = dots; i < cols-8; ++i)
+        printf ("\u2591");
+      printf ("\u27e7");
+    } else {
+      printf ("[");
+      int i;
+      for (i = 0; i < dots; ++i)
+        printf ("#");
+      for (i = dots; i < cols-8; ++i)
+        printf ("-");
+      printf ("]");
+    }
+    putchar ('\n');
+  }
+}
diff --git a/fish/reopen.c b/fish/reopen.c
index 2dfc8db..9e19018 100644
--- a/fish/reopen.c
+++ b/fish/reopen.c
@@ -66,6 +66,9 @@ do_reopen (const char *cmd, int argc, char *argv[])
   if (p)
     guestfs_set_path (g2, p);
 
+  if (progress_bars)
+    guestfs_set_progress_callback (g2, progress_callback, NULL);
+
   /* Close the original handle. */
   guestfs_close (g);
   g = g2;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e5fb857..3faa1fb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -81,6 +81,7 @@ fish/lcd.c
 fish/man.c
 fish/more.c
 fish/prep.c
+fish/progress.c
 fish/rc.c
 fish/reopen.c
 fish/supported.c
-- 
1.7.1



More information about the Libguestfs mailing list