From 16bd3feeb15684fa729012b419e9722904907bab Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sat, 18 Jun 2016 10:40:09 +0100 Subject: [PATCH] p2v: Use virt-v2v --colours option, support colour in the run dialog (RHBZ#1314244). (cherry picked from commit 5e8f820494e70766a48fee38bc617c37b0c61a48) --- p2v/conversion.c | 5 +- p2v/gui.c | 179 +++++++++++++++++++++++++++++++++++++++++++++---------- p2v/main.c | 1 + p2v/p2v.h | 3 + p2v/ssh.c | 24 ++++++-- 5 files changed, 172 insertions(+), 40 deletions(-) diff --git a/p2v/conversion.c b/p2v/conversion.c index f221f84..5265a76 100644 --- a/p2v/conversion.c +++ b/p2v/conversion.c @@ -320,9 +320,10 @@ start_conversion (struct config *config, /* Build the virt-v2v command up in pieces to make the quoting * slightly more sane. */ - if (mexp_printf (control_h, "( %s virt-v2v%s -i libvirtxml", + if (mexp_printf (control_h, "( %s virt-v2v%s%s -i libvirtxml", config->sudo ? "sudo -n " : "", - config->verbose ? " -v -x" : "") == -1) { + config->verbose ? " -v -x" : "", + feature_colours_option ? " --colours" : "") == -1) { printf_fail: set_conversion_error ("mexp_printf: virt-v2v command: %m"); goto out; diff --git a/p2v/gui.c b/p2v/gui.c index 142d2eb..a3b4af9 100644 --- a/p2v/gui.c +++ b/p2v/gui.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,9 @@ static GtkWidget *run_dlg, *v2v_output_sw, *v2v_output, *log_label, *status_label, *cancel_button, *reboot_button; +/* Colour tags used in the v2v_output GtkTextBuffer. */ +static GtkTextTag *v2v_output_tags[16]; + /* The entry point from the main program. * Note that gtk_init etc have already been called in main. */ @@ -1407,7 +1411,6 @@ get_memory_from_conv_dlg (void) static void set_log_dir (const char *remote_dir); static void set_status (const char *msg); static void add_v2v_output (const char *msg); -static void add_v2v_output_2 (const char *msg, size_t len); static void *start_conversion_thread (void *data); static void cancel_conversion_dialog (GtkWidget *w, gpointer data); static void reboot_clicked (GtkWidget *w, gpointer data); @@ -1416,6 +1419,12 @@ static gboolean close_running_dialog (GtkWidget *w, GdkEvent *event, gpointer da static void create_running_dialog (void) { + size_t i; + static const char *tags[16] = + { "black", "maroon", "green", "olive", "navy", "purple", "teal", "silver", + "gray", "red", "lime", "yellow", "blue", "fuchsia", "cyan", "white" }; + GtkTextBuffer *buf; + run_dlg = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (run_dlg), guestfs_int_program_name); gtk_window_set_resizable (GTK_WINDOW (run_dlg), FALSE); @@ -1428,6 +1437,17 @@ create_running_dialog (void) gtk_text_view_set_editable (GTK_TEXT_VIEW (v2v_output), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (v2v_output), GTK_WRAP_CHAR); gtk_widget_set_size_request (v2v_output, 700, 400); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); + for (i = 0; i < 16; ++i) { + CLEANUP_FREE char *tag_name; + + if (asprintf (&tag_name, "tag_%s", tags[i]) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + v2v_output_tags[i] = + gtk_text_buffer_create_tag (buf, tag_name, "foreground", tags[i], NULL); + } + log_label = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (log_label), 0., 0.5); gtk_misc_set_padding (GTK_MISC (log_label), 10, 10); @@ -1510,38 +1530,133 @@ set_status (const char *msg) static void add_v2v_output (const char *msg) { + const char *p; static size_t linelen = 0; - const char *p0, *p; - - /* Gtk2 (in ~ Fedora 23) has a regression where it takes much - * longer to display long lines, to the point where the virt-p2v - * UI would still be slowly display kernel modules while the - * conversion had finished. For this reason, arbitrarily break - * long lines. - */ - for (p0 = p = msg; *p; ++p) { - linelen++; - if (*p == '\n' || linelen > 1024) { - add_v2v_output_2 (p0, p-p0+1); - if (*p != '\n') - add_v2v_output_2 ("\n", 1); - linelen = 0; - p0 = p+1; - } - } - add_v2v_output_2 (p0, p-p0); -} - -static void -add_v2v_output_2 (const char *msg, size_t len) -{ - GtkTextBuffer *buf; - GtkTextIter iter; - - /* Insert it at the end. */ - buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); - gtk_text_buffer_get_end_iter (buf, &iter); - gtk_text_buffer_insert (buf, &iter, msg, len); + static enum { + state_normal, + state_escape1, /* seen ESC, expecting [ */ + state_escape2, /* seen ESC [, expecting 0 or 1 */ + state_escape3, /* seen ESC [ 0/1, expecting ; or m */ + state_escape4, /* seen ESC [ 0/1 ;, expecting 3 */ + state_escape5, /* seen ESC [ 0/1 ; 3, expecting 1/2/4/5 */ + state_escape6, /* seen ESC [ 0/1 ; 3 1/2/5/5, expecting m */ + state_cr, /* seen CR */ + state_truncating, /* truncating line until next \n */ + } state = state_normal; + static int colour = 0; + static GtkTextTag *tag = NULL; + GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (v2v_output)); + GtkTextIter iter, iter2; + const char *dots = " [...]"; + + for (p = msg; *p != '\0'; ++p) { + char c = *p; + + switch (state) { + case state_normal: + if (c == '\r') /* Start of possible CRLF sequence. */ + state = state_cr; + else if (c == '\x1b') { /* Start of an escape sequence. */ + state = state_escape1; + colour = 0; + } + else if (c != '\n' && linelen >= 256) { + /* Gtk2 (in ~ Fedora 23) has a regression where it takes much + * longer to display long lines, to the point where the + * virt-p2v UI would still be slowly displaying kernel modules + * while the conversion had finished. For this reason, + * arbitrarily truncate very long lines. + */ + gtk_text_buffer_get_end_iter (buf, &iter); + gtk_text_buffer_insert_with_tags (buf, &iter, + dots, strlen (dots), tag, NULL); + state = state_truncating; + colour = 0; + tag = NULL; + } + else { /* Treat everything else as a normal char. */ + if (c != '\n') linelen++; else linelen = 0; + gtk_text_buffer_get_end_iter (buf, &iter); + gtk_text_buffer_insert_with_tags (buf, &iter, &c, 1, tag, NULL); + } + break; + + case state_escape1: + if (c == '[') + state = state_escape2; + else + state = state_normal; + break; + + case state_escape2: + if (c == '0') + state = state_escape3; + else if (c == '1') { + state = state_escape3; + colour += 8; + } + else + state = state_normal; + break; + + case state_escape3: + if (c == ';') + state = state_escape4; + else if (c == 'm') { + tag = NULL; /* restore text colour */ + state = state_normal; + } + else + state = state_normal; + break; + + case state_escape4: + if (c == '3') + state = state_escape5; + else + state = state_normal; + break; + + case state_escape5: + if (c >= '0' && c <= '7') { + state = state_escape6; + colour += c - '0'; + } + else + state = state_normal; + break; + + case state_escape6: + if (c == 'm') { + assert (colour >= 0 && colour <= 15); + tag = v2v_output_tags[colour]; /* set colour tag */ + } + state = state_normal; + break; + + case state_cr: + if (c == '\n') + /* Process CRLF as single a newline character. */ + p--; + else { /* Delete current (== last) line. */ + linelen = 0; + gtk_text_buffer_get_end_iter (buf, &iter); + iter2 = iter; + gtk_text_iter_set_line_offset (&iter, 0); + /* Delete from iter..iter2 */ + gtk_text_buffer_delete (buf, &iter, &iter2); + } + state = state_normal; + break; + + case state_truncating: + if (c == '\n') { + p--; + state = state_normal; + } + break; + } /* switch (state) */ + } /* for */ /* Scroll to the end of the buffer. */ gtk_text_buffer_get_end_iter (buf, &iter); diff --git a/p2v/main.c b/p2v/main.c index 99da3e4..99d0011 100644 --- a/p2v/main.c +++ b/p2v/main.c @@ -42,6 +42,7 @@ char **all_disks; char **all_removable; char **all_interfaces; int is_iso_environment = 0; +int feature_colours_option = 0; static void udevadm_settle (void); static void set_config_defaults (struct config *config); diff --git a/p2v/p2v.h b/p2v/p2v.h index 9ccaf0f..12dd210 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -58,6 +58,9 @@ extern char **all_interfaces; */ extern int is_iso_environment; +/* True if virt-v2v supports the --colours option. */ +extern int feature_colours_option; + /* config.c */ struct config { int verbose; diff --git a/p2v/ssh.c b/p2v/ssh.c index d9210f3..266c236 100644 --- a/p2v/ssh.c +++ b/p2v/ssh.c @@ -101,6 +101,7 @@ static pcre *ssh_message_re; static pcre *prompt_re; static pcre *version_re; static pcre *feature_libguestfs_rewrite_re; +static pcre *feature_colours_option_re; static pcre *feature_input_re; static pcre *feature_output_re; static pcre *portfwd_re; @@ -149,6 +150,7 @@ compile_regexps (void) "virt-v2v ([1-9].*)", 0); COMPILE (feature_libguestfs_rewrite_re, "libguestfs-rewrite", 0); + COMPILE (feature_colours_option_re, "colours-option", 0); COMPILE (feature_input_re, "input:((?:\\w)*)", 0); COMPILE (feature_output_re, "output:((?:\\w)*)", 0); COMPILE (portfwd_re, "Allocated port ((?:\\d)+) for remote forward", 0); @@ -162,6 +164,7 @@ free_regexps (void) pcre_free (prompt_re); pcre_free (version_re); pcre_free (feature_libguestfs_rewrite_re); + pcre_free (feature_colours_option_re); pcre_free (feature_input_re); pcre_free (feature_output_re); pcre_free (portfwd_re); @@ -613,28 +616,37 @@ test_connection (struct config *config) switch (mexp_expect (h, (mexp_regexp[]) { { 100, .re = feature_libguestfs_rewrite_re }, - { 101, .re = feature_input_re }, - { 102, .re = feature_output_re }, - { 103, .re = prompt_re }, + { 101, .re = feature_colours_option_re }, + { 102, .re = feature_input_re }, + { 103, .re = feature_output_re }, + { 104, .re = prompt_re }, { 0 } }, ovector, ovecsize)) { case 100: /* libguestfs-rewrite. */ feature_libguestfs_rewrite = 1; break; - case 101: + case 101: /* virt-v2v supports --colours option */ +#if DEBUG_STDERR + fprintf (stderr, "%s: remote virt-v2v supports --colours option\n", + guestfs_int_program_name); +#endif + feature_colours_option = 1; + break; + + case 102: /* input: corresponds to an -i option in virt-v2v. */ add_input_driver (&h->buffer[ovector[2]], (size_t) (ovector[3]-ovector[2])); break; - case 102: + case 103: /* output: corresponds to an -o option in virt-v2v. */ add_output_driver (&h->buffer[ovector[2]], (size_t) (ovector[3]-ovector[2])); break; - case 103: /* Got prompt, so end of output. */ + case 104: /* Got prompt, so end of output. */ goto end_of_machine_readable; case MEXP_EOF: -- 1.8.3.1