Move UI out of debuginfod-support and into ui-out and subclasses.

This commit is contained in:
Aaron Merey
2022-01-19 12:43:30 -05:00
parent 922e534d4d
commit b7b7f1cef5
6 changed files with 178 additions and 85 deletions

View File

@@ -280,15 +280,14 @@ void
cli_ui_out::do_progress_start (const std::string &name, bool should_print)
{
struct ui_file *stream = m_streams.back ();
cli_progress_info meter;
cli_progress_info info;
meter.last_value = 0;
meter.name = name;
info.name = name;
if (!stream->isatty ())
{
fprintf_unfiltered (stream, "%s...", meter.name.c_str ());
fprintf_unfiltered (stream, "%s...", info.name.c_str ());
gdb_flush (stream);
meter.printing = WORKING;
info.state = progress_report::WORKING;
}
else
{
@@ -296,74 +295,120 @@ cli_ui_out::do_progress_start (const std::string &name, bool should_print)
of progress. This makes it so a second progress message can
be started before the first one has been notified, without
messy output. */
meter.printing = should_print ? START : NO_PRINT;
info.state = should_print ? progress_report::START
: progress_report::NO_PRINT;
}
m_meters.push_back (std::move (meter));
m_progress_info.push_back (std::move (info));
}
void
cli_ui_out::do_progress_notify (double howmuch)
{
struct ui_file *stream = m_streams.back ();
cli_progress_info &meter (m_meters.back ());
cli_progress_info &info (m_progress_info.back ());
if (meter.printing == NO_PRINT)
if (info.state == progress_report::NO_PRINT)
return;
if (meter.printing == START)
int chars_per_line = get_chars_per_line ();
if (info.state == progress_report::START && chars_per_line <= 0)
{
fprintf_unfiltered (stream, "%s\n", meter.name.c_str ());
fprintf_unfiltered (stream, "%s\n", info.name.c_str ());
gdb_flush (stream);
meter.printing = WORKING;
info.state = progress_report::WORKING;
}
if (meter.printing == WORKING && howmuch >= 1.0)
if (info.state == progress_report::WORKING && howmuch >= 1.0)
return;
if (!stream->isatty ())
return;
int chars_per_line = get_chars_per_line ();
if (chars_per_line > 0)
if (chars_per_line <= 0)
return;
if (howmuch <= 0.0)
{
using namespace std::chrono;
seconds diff = duration_cast<seconds>
(steady_clock::now () - info.last_update);
if (diff.count () >= 1.0)
{
static int spin = 0;
fprintf_unfiltered (stream, "\r%s %c\b", info.name.c_str (),
"-\\|/"[spin++ % 4]);
gdb_flush (stream);
info.last_update = steady_clock::now ();
}
info.state = progress_report::SPIN;
}
else
{
/* Pick a reasonable limit for the progress bar length. */
if (chars_per_line > 3840)
chars_per_line = 3840;
int i, max;
int width = chars_per_line - 3;
max = width * howmuch;
if (info.state == progress_report::SPIN)
{
/* Ensure the progress bar prints on its own line so that
progress updates don't erase name. */
fprintf_unfiltered (stream, "\r%s\n", info.name.c_str ());
gdb_flush (stream);
}
fprintf_unfiltered (stream, "\r[");
for (i = 0; i < width; ++i)
fprintf_unfiltered (stream, i < max ? "#" : " ");
fprintf_unfiltered (stream, "]");
gdb_flush (stream);
meter.printing = PROGRESS;
info.state = progress_report::BAR;
}
}
void
cli_ui_out::update_progress_name (const std::string &name)
{
cli_progress_info &info = m_progress_info.back ();
info.name = name;
}
cli_ui_out::progress_report::state
cli_ui_out::get_progress_state ()
{
cli_progress_info &info = m_progress_info.back ();
return info.state;
}
void
cli_ui_out::do_progress_end ()
{
struct ui_file *stream = m_streams.back ();
cli_progress_info &meter = m_meters.back ();
cli_progress_info &info = m_progress_info.back ();
if (!stream->isatty ())
{
fprintf_unfiltered (stream, "\n");
gdb_flush (stream);
}
else if (meter.printing == PROGRESS)
if (!stream->isatty () || info.state == progress_report::SPIN)
fprintf_unfiltered (stream, " \n");
else if (info.state == progress_report::BAR)
{
int i;
int width = get_chars_per_line () - 3;
this->do_progress_notify (1.0);
fprintf_unfiltered (stream, "\r");
for (i = 0; i < width + 2; ++i)
fprintf_unfiltered (stream, " ");
fprintf_unfiltered (stream, "\r");
gdb_flush (stream);
}
m_meters.pop_back ();
gdb_flush (stream);
m_progress_info.pop_back ();
}
/* local functions */

View File

@@ -21,6 +21,7 @@
#define CLI_OUT_H
#include "ui-out.h"
#include <chrono>
#include <vector>
class cli_ui_out : public ui_out
@@ -74,6 +75,8 @@ protected:
virtual void do_progress_start (const std::string &, bool) override;
virtual void do_progress_notify (double) override;
virtual void do_progress_end () override;
virtual void update_progress_name (const std::string &) override;
virtual progress_report::state get_progress_state () override;
bool suppress_output ()
{ return m_suppress_output; }
@@ -85,32 +88,19 @@ private:
std::vector<ui_file *> m_streams;
bool m_suppress_output;
/* Represents the printing state of a progress meter. */
enum meter_state
{
/* Printing will start with the next output. */
START,
/* Printing has already started. */
WORKING,
/* Progress printing has already started. */
PROGRESS,
/* Printing should not be done. */
NO_PRINT
};
/* The state of a recent progress meter. */
/* The state of a recent progress report. */
struct cli_progress_info
{
/* The current state. */
enum meter_state printing;
progress_report::state state;
/* The name to print. */
std::string name;
/* The last notification value. */
double last_value;
/* Time of last spinner update. */
std::chrono::steady_clock::time_point last_update;
};
/* Stack of progress meters. */
std::vector<cli_progress_info> m_meters;
/* Stack of progress info. */
std::vector<cli_progress_info> m_progress_info;
};
extern cli_ui_out *cli_out_new (struct ui_file *stream);

View File

@@ -23,6 +23,7 @@
#include "gdbsupport/gdb_optional.h"
#include "cli/cli-cmds.h"
#include "cli/cli-style.h"
#include "cli-out.h"
#include "target.h"
/* Set/show debuginfod commands. */
@@ -82,8 +83,7 @@ struct user_data
const char * const desc;
const char * const fname;
gdb::optional<ui_out::progress_meter> meter;
bool printed_spin = false;
gdb::optional<ui_out::progress_report> report;
};
/* Deleter for a debuginfod_client. */
@@ -102,12 +102,14 @@ using debuginfod_client_up
static int
progressfn (debuginfod_client *c, long cur, long total)
{
static int spin = 0;
user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
gdb_assert (data != nullptr);
if (check_quit_flag ())
{
if (data->report.has_value ())
data->report.reset ();
printf_filtered ("Cancelling download of %s %ps...\n",
data->desc,
styled_string (file_name_style.style (), data->fname));
@@ -122,41 +124,44 @@ progressfn (debuginfod_client *c, long cur, long total)
if (total > 0)
{
if (!data->meter.has_value ())
/* Transfer size is known, so print it along with the rest of the
progress update. */
if (!data->report.has_value ()
|| data->report->get_state () == ui_out::progress_report::SPIN)
{
double size = 1.0f * total / 1024;
std::string unit = "KB";
/* Switch to MB if size greater than 0.01 MB. */
/* Switch unit to MB if size is greater than 0.01 MB. */
if (size > 10.24)
{
size /= 1024;
unit = "MB";
}
/* Overwrite an existing progress update line with no download
size information. */
if (data->printed_spin)
{
current_uiout->message ("\r");
data->printed_spin = false;
}
std::string message = string_printf ("Downloading %.2f %s %s %s",
size, unit.c_str (),
data->desc,
styled_filename.c_str ());
data->meter.emplace (current_uiout, message, 1);
if (!data->report.has_value ())
data->report.emplace (current_uiout, message, 1);
else
data->report->update_name (message);
}
current_uiout->progress ((double)cur / (double)total);
current_uiout->update_progress ((double)cur / (double)total);
}
else
{
current_uiout->message (_("\rDownloading %s %s %c"), data->desc,
styled_filename.c_str (), "-/|\\"[spin++ % 4]);
current_uiout->flush ();
data->printed_spin = true;
if (!data->report.has_value ())
{
std::string message = string_printf ("Downloading %s %s", data->desc,
styled_filename.c_str ());
data->report.emplace (current_uiout, message, 1);
}
current_uiout->update_progress (-1);
}
return 0;
@@ -230,6 +235,7 @@ debuginfod_source_query (const unsigned char *build_id,
if (c == nullptr)
return scoped_fd (-ENOMEM);
char *dname = nullptr;
user_data data ("source file", srcpath);
debuginfod_set_user_data (c, &data);
@@ -244,9 +250,7 @@ debuginfod_source_query (const unsigned char *build_id,
build_id,
build_id_len,
srcpath,
nullptr));
if (data.printed_spin)
current_uiout->message ("\b \n");
&dname));
debuginfod_set_user_data (c, nullptr);
@@ -256,7 +260,7 @@ debuginfod_source_query (const unsigned char *build_id,
styled_string (file_name_style.style (), srcpath));
if (fd.get () >= 0)
*destname = make_unique_xstrdup (srcpath);
destname->reset (dname);
return fd;
}
@@ -290,9 +294,6 @@ debuginfod_debuginfo_query (const unsigned char *build_id,
scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
&dname));
if (data.printed_spin)
current_uiout->message ("\b \n");
debuginfod_set_user_data (c, nullptr);
if (debuginfod_verbose > 0 && fd.get () < 0 && fd.get () != -ENOENT)

View File

@@ -258,6 +258,25 @@ mi_ui_out::main_stream ()
return (string_file *) m_streams.back ();
}
void
mi_ui_out::do_progress_start (const std::string &name, bool should_print)
{
struct ui_file *stream = gdb_stdout;
mi_progress_info info;
fprintf_unfiltered (stream, "%s...\n", name.c_str ());
gdb_flush (stream);
info.state = progress_report::WORKING;
m_progress_info.push_back (std::move (info));
}
mi_ui_out::progress_report::state
mi_ui_out::get_progress_state ()
{
mi_progress_info &info = m_progress_info.back ();
return info.state;
}
/* Clear the buffer. */
void

View File

@@ -25,7 +25,6 @@
struct ui_out;
struct ui_file;
class mi_ui_out : public ui_out
{
public:
@@ -83,9 +82,8 @@ protected:
virtual bool do_is_mi_like_p () const override
{ return true; }
virtual void do_progress_start (const std::string &, bool) override
{
}
virtual void do_progress_start (const std::string &, bool) override;
virtual progress_report::state get_progress_state () override;
virtual void do_progress_notify (double) override
{
@@ -95,12 +93,26 @@ protected:
{
}
virtual void update_progress_name (const std::string &) override
{
}
private:
void field_separator ();
void open (const char *name, ui_out_type type);
void close (ui_out_type type);
/* The state of a recent progress_report. */
struct mi_progress_info
{
/* The current state. */
progress_report::state state;
};
/* Stack of progress info. */
std::vector<mi_progress_info> m_progress_info;
/* Convenience method that returns the MI out's string stream cast
to its appropriate type. Assumes/asserts that output was not
redirected. */

View File

@@ -280,26 +280,50 @@ class ui_out
escapes. */
virtual bool can_emit_style_escape () const = 0;
/* An object that starts and finishes a progress meter. */
class progress_meter
/* An object that starts and finishes progress reporting. */
class progress_report
{
public:
/* Represents the printing state of a progress report. */
enum state
{
/* Printing will start with the next output. */
START,
/* Printing has already started. */
WORKING,
/* Progress bar printing has already started. */
BAR,
/* Spinner printing has already started. */
SPIN,
/* Printing should not be done. */
NO_PRINT
};
/* SHOULD_PRINT indicates whether something should be printed for a tty. */
progress_meter (struct ui_out *uiout, const std::string &name,
bool should_print)
progress_report (struct ui_out *uiout, const std::string &name,
bool should_print)
: m_uiout (uiout)
{
m_uiout->do_progress_start (name, should_print);
}
~progress_meter ()
~progress_report ()
{
m_uiout->do_progress_notify (1.0);
m_uiout->do_progress_end ();
}
progress_meter (const progress_meter &) = delete;
progress_meter &operator= (const progress_meter &) = delete;
void update_name (std::string &name)
{
m_uiout->update_progress_name (name);
}
state get_state ()
{
return m_uiout->get_progress_state ();
}
progress_report (const progress_report &) = delete;
progress_report &operator= (const progress_report &) = delete;
private:
@@ -307,8 +331,8 @@ class ui_out
};
/* Emit some progress corresponding to the most recently created
progress meter. HOWMUCH may range from 0.0 to 1.0. */
void progress (double howmuch)
progress_report object. */
void update_progress (double howmuch)
{
do_progress_notify (howmuch);
}
@@ -350,6 +374,8 @@ class ui_out
virtual void do_progress_start (const std::string &, bool) = 0;
virtual void do_progress_notify (double) = 0;
virtual void do_progress_end () = 0;
virtual void update_progress_name (const std::string &) = 0;
virtual progress_report::state get_progress_state () = 0;
/* Set as not MI-like by default. It is overridden in subclasses if
necessary. */