fish: Implement progress bars in guestfish.
[libguestfs.git] / fish / fish.c
index c535e06..9696545 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <locale.h>
+#include <langinfo.h>
 #include <termios.h>
 
 #ifdef HAVE_LIBREADLINE
@@ -69,6 +70,7 @@ struct mp {
   char *mountpoint;
 };
 
+static void set_up_terminal (void);
 static char add_drives (struct drv *drv, char next_drive);
 static void prepare_drives (struct drv *drv);
 static void mount_mps (struct mp *mp);
@@ -83,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;
 
@@ -96,6 +100,9 @@ int command_num = 0;
 int keys_from_stdin = 0;
 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)
@@ -133,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"
@@ -159,6 +168,8 @@ main (int argc, char *argv[])
   bindtextdomain (PACKAGE, LOCALEBASEDIR);
   textdomain (PACKAGE);
 
+  set_up_terminal ();
+
   enum { HELP_OPTION = CHAR_MAX + 1 };
 
   static const char *options = "a:c:d:Df:h::im:nN:rv?Vx";
@@ -176,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 },
@@ -261,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);
@@ -494,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))
@@ -509,6 +535,35 @@ main (int argc, char *argv[])
   exit (EXIT_SUCCESS);
 }
 
+/* The <term.h> header file which defines this has "issues". */
+extern int tgetent (char *, const char *);
+
+static void
+set_up_terminal (void)
+{
+  /* http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate */
+  utf8_mode = STREQ (nl_langinfo (CODESET), "UTF-8");
+
+  char *term = getenv ("TERM");
+  if (term == NULL) {
+    //fprintf (stderr, _("guestfish: TERM (terminal type) not defined.\n"));
+    return;
+  }
+
+  int r = tgetent (NULL, term);
+  if (r == -1) {
+    fprintf (stderr, _("guestfish: could not access termcap or terminfo database.\n"));
+    return;
+  }
+  if (r == 0) {
+    fprintf (stderr, _("guestfish: terminal type \"%s\" not defined.\n"),
+             term);
+    return;
+  }
+
+  have_terminfo = 1;
+}
+
 void
 pod2text (const char *name, const char *shortdesc, const char *str)
 {
@@ -928,6 +983,8 @@ issue_command (const char *cmd, char *argv[], const char *pipecmd)
   int pid = 0;
   int i, r;
 
+  reset_progress_bar ();
+
   /* This counts the commands issued, starting at 1. */
   command_num++;