Split out the console handling to a new module

This simplifies a lot of confusion.
This commit is contained in:
Richard Hughes 2023-02-10 16:18:02 +00:00
parent b25e0f3a28
commit caaeb1ea16
13 changed files with 1489 additions and 1317 deletions

View File

@ -8,11 +8,11 @@ plugins/tpm/fu-tpm-eventlog.c
plugins/uefi-capsule/fu-uefi-capsule-plugin.c
plugins/uefi-capsule/fu-uefi-tool.c
plugins/uefi-dbx/fu-dbxtool.c
src/fu-console.c
src/fu-debug.c
src/fu-engine-helper.c
src/fu-main.c
src/fu-offline.c
src/fu-progressbar.c
src/fu-remote-list.c
src/fu-security-attr-common.c
src/fu-tool.c

779
src/fu-console.c Normal file
View File

@ -0,0 +1,779 @@
/*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuProgressBar"
#include "config.h"
#include <glib/gi18n.h>
#include <stdio.h>
#include "fu-console.h"
#ifdef _WIN32
#include <wchar.h>
#include <windows.h>
#endif
struct _FuConsole {
GObject parent_instance;
GMainContext *main_ctx;
FwupdStatus status;
gboolean spinner_count_up; /* width in visible chars */
guint spinner_idx; /* width in visible chars */
guint length_percentage; /* width in visible chars */
guint length_status; /* width in visible chars */
guint percentage;
GSource *timer_source;
gint64 last_animated; /* monotonic */
GTimer *time_elapsed;
gdouble last_estimate;
gboolean interactive;
gboolean contents_to_clear;
};
G_DEFINE_TYPE(FuConsole, fu_console, G_TYPE_OBJECT)
gboolean
fu_console_setup(FuConsole *self, GError **error)
{
#ifdef _WIN32
HANDLE hOut;
DWORD dwMode = 0;
/* enable VT sequences */
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to get stdout [%u]",
(guint)GetLastError());
return FALSE;
}
if (!GetConsoleMode(hOut, &dwMode)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to get mode [%u]",
(guint)GetLastError());
return FALSE;
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set mode [%u]",
(guint)GetLastError());
return FALSE;
}
if (!SetConsoleOutputCP(CP_UTF8)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set output UTF-8 [%u]",
(guint)GetLastError());
return FALSE;
}
if (!SetConsoleCP(CP_UTF8)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set UTF-8 [%u]",
(guint)GetLastError());
return FALSE;
}
#else
if (isatty(fileno(stdout)) == 0) {
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "not a TTY");
return FALSE;
}
#endif
/* success */
return TRUE;
}
static void
fu_console_erase_line(FuConsole *self)
{
if (!self->interactive)
return;
g_print("\033[G");
}
static void
fu_console_reset_line(FuConsole *self)
{
if (self->contents_to_clear) {
fu_console_erase_line(self);
g_print("\n");
self->contents_to_clear = FALSE;
}
}
void
fu_console_print_kv(FuConsole *self, const gchar *title, const gchar *msg)
{
gsize title_len;
g_auto(GStrv) lines = NULL;
if (msg == NULL)
return;
fu_console_reset_line(self);
g_print("%s:", title);
/* pad */
title_len = fu_strwidth(title) + 1;
lines = g_strsplit(msg, "\n", -1);
for (guint j = 0; lines[j] != NULL; j++) {
for (gsize i = title_len; i < 25; i++)
g_print(" ");
g_print("%s\n", lines[j]);
title_len = 0;
}
}
guint
fu_console_input_uint(FuConsole *self, guint maxnum)
{
gint retval;
guint answer = 0;
do {
char buffer[64];
/* swallow the \n at end of line too */
if (!fgets(buffer, sizeof(buffer), stdin))
break;
if (strlen(buffer) == sizeof(buffer) - 1)
continue;
/* get a number */
retval = sscanf(buffer, "%u", &answer);
/* positive */
if (retval == 1 && answer <= maxnum)
break;
/* TRANSLATORS: the user isn't reading the question */
fu_console_print_full(self,
FU_CONSOLE_PRINT_FLAG_NONE,
_("Please enter a number from 0 to %u: "),
maxnum);
} while (TRUE);
return answer;
}
gboolean
fu_console_input_bool(FuConsole *self, gboolean def, const gchar *format, ...)
{
va_list args;
g_autofree gchar *tmp = NULL;
g_autoptr(GString) str = g_string_new(NULL);
va_start(args, format);
tmp = g_strdup_vprintf(format, args);
va_end(args);
g_string_append_printf(str, "%s [%s]: ", tmp, def ? "Y|n" : "y|N");
fu_console_print_literal(self, str->str);
do {
char buffer[4];
if (!fgets(buffer, sizeof(buffer), stdin))
continue;
if (strlen(buffer) == sizeof(buffer) - 1)
continue;
if (g_strcmp0(buffer, "\n") == 0)
return def;
buffer[0] = g_ascii_toupper(buffer[0]);
if (g_strcmp0(buffer, "Y\n") == 0)
return TRUE;
if (g_strcmp0(buffer, "N\n") == 0)
return FALSE;
} while (TRUE);
return FALSE;
}
static GPtrArray *
fu_console_strsplit_words(const gchar *text, guint line_len)
{
g_auto(GStrv) tokens = NULL;
g_autoptr(GPtrArray) lines = g_ptr_array_new_with_free_func(g_free);
g_autoptr(GString) curline = g_string_new(NULL);
/* sanity check */
if (text == NULL || text[0] == '\0')
return NULL;
if (line_len == 0)
return NULL;
/* tokenize the string */
tokens = g_strsplit(text, " ", -1);
for (guint i = 0; tokens[i] != NULL; i++) {
/* current line plus new token is okay */
if (curline->len + fu_strwidth(tokens[i]) < line_len) {
g_string_append_printf(curline, "%s ", tokens[i]);
continue;
}
/* too long, so remove space, add newline and dump */
if (curline->len > 0)
g_string_truncate(curline, curline->len - 1);
g_ptr_array_add(lines, g_strdup(curline->str));
g_string_truncate(curline, 0);
g_string_append_printf(curline, "%s ", tokens[i]);
}
/* any incomplete line? */
if (curline->len > 0) {
g_string_truncate(curline, curline->len - 1);
g_ptr_array_add(lines, g_strdup(curline->str));
}
return g_steal_pointer(&lines);
}
static void
fu_console_box_line(const gchar *start,
const gchar *text,
const gchar *end,
const gchar *padding,
guint width)
{
guint offset = 0;
if (start != NULL) {
offset += fu_strwidth(start);
g_print("%s", start);
}
if (text != NULL) {
offset += fu_strwidth(text);
g_print("%s", text);
}
if (end != NULL)
offset += fu_strwidth(end);
for (guint i = offset; i < width; i++)
g_print("%s", padding);
if (end != NULL)
g_print("%s\n", end);
}
void
fu_console_line(FuConsole *self, guint width)
{
g_autoptr(GString) str = g_string_new_len(NULL, width);
for (guint i = 0; i < width; i++)
g_string_append(str, "");
fu_console_print_literal(self, str->str);
}
void
fu_console_box(FuConsole *self, const gchar *title, const gchar *body, guint width)
{
/* nothing to do */
if (title == NULL && body == NULL)
return;
/* header */
fu_console_reset_line(self);
fu_console_box_line("", NULL, "", "", width);
/* optional title */
if (title != NULL) {
g_autoptr(GPtrArray) lines = fu_console_strsplit_words(title, width - 4);
for (guint j = 0; j < lines->len; j++) {
const gchar *line = g_ptr_array_index(lines, j);
fu_console_box_line("", line, "", " ", width);
}
}
/* join */
if (title != NULL && body != NULL)
fu_console_box_line("", NULL, "", "", width);
/* optional body */
if (body != NULL) {
gboolean has_nonempty = FALSE;
g_auto(GStrv) split = g_strsplit(body, "\n", -1);
for (guint i = 0; split[i] != NULL; i++) {
g_autoptr(GPtrArray) lines = fu_console_strsplit_words(split[i], width - 4);
if (lines == NULL) {
if (has_nonempty) {
fu_console_box_line("", NULL, "", " ", width);
has_nonempty = FALSE;
}
continue;
}
for (guint j = 0; j < lines->len; j++) {
const gchar *line = g_ptr_array_index(lines, j);
fu_console_box_line("", line, "", " ", width);
}
has_nonempty = TRUE;
}
}
/* footer */
fu_console_box_line("", NULL, "", "", width);
}
static const gchar *
fu_console_status_to_string(FwupdStatus status)
{
switch (status) {
case FWUPD_STATUS_IDLE:
/* TRANSLATORS: daemon is inactive */
return _("Idle…");
break;
case FWUPD_STATUS_DECOMPRESSING:
/* TRANSLATORS: decompressing the firmware file */
return _("Decompressing…");
break;
case FWUPD_STATUS_LOADING:
/* TRANSLATORS: parsing the firmware information */
return _("Loading…");
break;
case FWUPD_STATUS_DEVICE_RESTART:
/* TRANSLATORS: restarting the device to pick up new F/W */
return _("Restarting device…");
break;
case FWUPD_STATUS_DEVICE_READ:
/* TRANSLATORS: reading from the flash chips */
return _("Reading…");
break;
case FWUPD_STATUS_DEVICE_WRITE:
/* TRANSLATORS: writing to the flash chips */
return _("Writing…");
break;
case FWUPD_STATUS_DEVICE_ERASE:
/* TRANSLATORS: erasing contents of the flash chips */
return _("Erasing…");
break;
case FWUPD_STATUS_DEVICE_VERIFY:
/* TRANSLATORS: verifying we wrote the firmware correctly */
return _("Verifying…");
break;
case FWUPD_STATUS_SCHEDULING:
/* TRANSLATORS: scheduling an update to be done on the next boot */
return _("Scheduling…");
break;
case FWUPD_STATUS_DOWNLOADING:
/* TRANSLATORS: downloading from a remote server */
return _("Downloading…");
break;
case FWUPD_STATUS_WAITING_FOR_AUTH:
/* TRANSLATORS: waiting for user to authenticate */
return _("Authenticating…");
break;
case FWUPD_STATUS_DEVICE_BUSY:
/* TRANSLATORS: waiting for device to do something */
return _("Waiting…");
break;
default:
break;
}
/* TRANSLATORS: current daemon status is unknown */
return _("Unknown");
}
static gboolean
_fu_status_is_predictable(FwupdStatus status)
{
if (status == FWUPD_STATUS_DEVICE_ERASE)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_VERIFY)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_READ)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_WRITE)
return TRUE;
if (status == FWUPD_STATUS_DOWNLOADING)
return TRUE;
return FALSE;
}
static gboolean
fu_console_estimate_ready(FuConsole *self, guint percentage)
{
gdouble old;
gdouble elapsed;
/* now invalid */
if (percentage == 0 || percentage == 100) {
g_timer_start(self->time_elapsed);
self->last_estimate = 0;
return FALSE;
}
/* allow-list things that make sense... */
if (!_fu_status_is_predictable(self->status))
return FALSE;
old = self->last_estimate;
elapsed = g_timer_elapsed(self->time_elapsed, NULL);
self->last_estimate = elapsed / percentage * (100 - percentage);
/* estimate is ready if we have decreased */
return old > self->last_estimate;
}
static gchar *
fu_console_time_remaining_str(FuConsole *self)
{
/* less than 5 seconds remaining */
if (self->last_estimate < 5)
return NULL;
/* less than 60 seconds remaining */
if (self->last_estimate < 60) {
/* TRANSLATORS: time remaining for completing firmware flash */
return g_strdup(_("Less than one minute remaining"));
}
return g_strdup_printf(
/* TRANSLATORS: more than a minute */
ngettext("%.0f minute remaining", "%.0f minutes remaining", self->last_estimate / 60),
self->last_estimate / 60);
}
static void
fu_console_refresh(FuConsole *self)
{
const gchar *title;
guint i;
g_autoptr(GString) str = g_string_new(NULL);
/* sanity check */
if (self->status == FWUPD_STATUS_IDLE || self->status == FWUPD_STATUS_UNKNOWN)
return;
/* erase previous line */
fu_console_erase_line(self);
/* add status */
title = fu_console_status_to_string(self->status);
g_string_append(str, title);
for (i = fu_strwidth(str->str); i < self->length_status; i++)
g_string_append_c(str, ' ');
/* add console */
g_string_append(str, "[");
if (self->percentage > 0) {
for (i = 0; i < (self->length_percentage - 1) * self->percentage / 100; i++)
g_string_append_c(str, '*');
for (i = i + 1; i < self->length_percentage; i++)
g_string_append_c(str, ' ');
} else {
const gchar chars[] = {
'-',
'\\',
'|',
'/',
};
for (i = 0; i < self->spinner_idx; i++)
g_string_append_c(str, ' ');
g_string_append_c(str, chars[i / 4 % G_N_ELEMENTS(chars)]);
for (i = i + 1; i < self->length_percentage - 1; i++)
g_string_append_c(str, ' ');
}
g_string_append_c(str, ']');
/* once we have good data show an estimate of time remaining */
if (fu_console_estimate_ready(self, self->percentage)) {
g_autofree gchar *remaining = fu_console_time_remaining_str(self);
if (remaining != NULL)
g_string_append_printf(str, " %s…", remaining);
}
/* dump to screen */
g_print("%s", str->str);
self->contents_to_clear = TRUE;
}
/**
* fu_console_print_full:
* @self: a #FuConsole
* @flags; a #FuConsolePrintFlags, e.g. %FU_CONSOLE_PRINT_FLAG_STDERR
* @text: string
*
* Clears the console, and prints the text.
**/
void
fu_console_print_full(FuConsole *self, FuConsolePrintFlags flags, const gchar *format, ...)
{
va_list args;
g_autoptr(GString) str = g_string_new(NULL);
va_start(args, format);
g_string_append_vprintf(str, format, args);
va_end(args);
if (flags & FU_CONSOLE_PRINT_FLAG_WARNING) {
/* TRANSLATORS: this is a prefix on the console */
g_autofree gchar *fmt = fu_console_color_format(_("WARNING"), FU_CONSOLE_COLOR_RED);
g_string_prepend(str, ": ");
g_string_prepend(str, fmt);
flags |= FU_CONSOLE_PRINT_FLAG_STDERR;
}
fu_console_reset_line(self);
if (flags & FU_CONSOLE_PRINT_FLAG_STDERR) {
g_printerr("%s", str->str);
} else {
g_print("%s", str->str);
}
}
void
fu_console_print_literal(FuConsole *self, const gchar *text)
{
fu_console_reset_line(self);
g_print("%s\n", text);
}
/**
* fu_console_print:
* @self: a #FuConsole
* @text: string
*
* Clears the console, prints the text and prints a newline.
**/
void
fu_console_print(FuConsole *self, const gchar *format, ...)
{
va_list args;
g_autofree gchar *tmp = NULL;
va_start(args, format);
tmp = g_strdup_vprintf(format, args);
va_end(args);
fu_console_print_literal(self, tmp);
}
/**
* fu_console_set_progress_title:
* @self: A #FuConsole
* @title: A string
*
* Sets console title
**/
void
fu_console_set_progress_title(FuConsole *self, const gchar *title)
{
fu_console_erase_line(self);
g_print("%s\n", title);
fu_console_refresh(self);
}
/**
* fu_console_set_main_context:
* @self: A #FuConsole
* @main_ctx: (nullable): main context
*
* Sets console main context to use for animations.
**/
void
fu_console_set_main_context(FuConsole *self, GMainContext *main_ctx)
{
self->main_ctx = g_main_context_ref(main_ctx);
}
static void
fu_console_spin_inc(FuConsole *self)
{
/* reset */
self->last_animated = g_get_monotonic_time();
/* up to down */
if (self->spinner_count_up) {
if (++self->spinner_idx > self->length_percentage - 3)
self->spinner_count_up = FALSE;
} else {
if (--self->spinner_idx == 0)
self->spinner_count_up = TRUE;
}
}
static gboolean
fu_console_spin_cb(gpointer user_data)
{
FuConsole *self = FU_CONSOLE(user_data);
/* move the spinner index up to down */
fu_console_spin_inc(self);
/* update the terminal */
fu_console_refresh(self);
return G_SOURCE_CONTINUE;
}
static void
fu_console_spin_end(FuConsole *self)
{
if (self->timer_source != NULL) {
g_source_destroy(self->timer_source);
self->timer_source = NULL;
/* reset when the spinner has been stopped */
g_timer_start(self->time_elapsed);
}
/* go back to the start when we next go into unknown percentage mode */
self->spinner_idx = 0;
self->spinner_count_up = TRUE;
}
static void
fu_console_spin_start(FuConsole *self)
{
if (self->timer_source != NULL)
g_source_destroy(self->timer_source);
self->timer_source = g_timeout_source_new(40);
g_source_set_callback(self->timer_source, fu_console_spin_cb, self, NULL);
g_source_attach(self->timer_source, self->main_ctx);
}
/**
* fu_console_set_progress:
* @self: A #FuConsole
* @status: A #FwupdStatus
* @percentage: unsigned integer
*
* Refreshes the progress bar with the new percentage and status.
**/
void
fu_console_set_progress(FuConsole *self, FwupdStatus status, guint percentage)
{
g_return_if_fail(FU_IS_CONSOLE(self));
/* not useful */
if (status == FWUPD_STATUS_UNKNOWN)
return;
/* ignore duplicates */
if (self->status == status && self->percentage == percentage)
return;
/* cache */
self->status = status;
self->percentage = percentage;
/* dumb */
if (!self->interactive) {
g_printerr("%s: %u%%\n", fu_console_status_to_string(status), percentage);
return;
}
/* if the main loop isn't spinning and we've not had a chance to
* execute the callback just do the refresh now manually */
if (percentage == 0 && status != FWUPD_STATUS_IDLE &&
self->status != FWUPD_STATUS_UNKNOWN) {
if ((g_get_monotonic_time() - self->last_animated) / 1000 > 40) {
fu_console_spin_inc(self);
fu_console_refresh(self);
}
}
/* enable or disable the spinner timeout */
if (percentage > 0) {
fu_console_spin_end(self);
} else {
fu_console_spin_start(self);
}
/* update the terminal */
fu_console_refresh(self);
}
/**
* fu_console_set_interactive:
* @self: A #FuConsole
* @interactive: #gboolean
*
* Marks the console as interactive or not
**/
void
fu_console_set_interactive(FuConsole *self, gboolean interactive)
{
g_return_if_fail(FU_IS_CONSOLE(self));
self->interactive = interactive;
}
/**
* fu_console_set_status_length:
* @self: A #FuConsole
* @len: unsigned integer
*
* Sets the width of the progressbar status, which must be greater that 3.
**/
void
fu_console_set_status_length(FuConsole *self, guint len)
{
g_return_if_fail(FU_IS_CONSOLE(self));
g_return_if_fail(len > 3);
self->length_status = len;
}
/**
* fu_console_set_percentage_length:
* @self: A #FuConsole
* @len: unsigned integer
*
* Sets the width of the progressbar percentage, which must be greater that 3.
**/
void
fu_console_set_percentage_length(FuConsole *self, guint len)
{
g_return_if_fail(FU_IS_CONSOLE(self));
g_return_if_fail(len > 3);
self->length_percentage = len;
}
static void
fu_console_init(FuConsole *self)
{
self->length_percentage = 40;
self->length_status = 25;
self->spinner_count_up = TRUE;
self->time_elapsed = g_timer_new();
self->interactive = TRUE;
}
static void
fu_console_finalize(GObject *obj)
{
FuConsole *self = FU_CONSOLE(obj);
fu_console_reset_line(self);
if (self->timer_source != 0)
g_source_destroy(self->timer_source);
if (self->main_ctx != NULL)
g_main_context_unref(self->main_ctx);
g_timer_destroy(self->time_elapsed);
G_OBJECT_CLASS(fu_console_parent_class)->finalize(obj);
}
static void
fu_console_class_init(FuConsoleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = fu_console_finalize;
}
/**
* fu_console_new:
*
* Creates a new #FuConsole
**/
FuConsole *
fu_console_new(void)
{
FuConsole *self;
self = g_object_new(FU_TYPE_CONSOLE, NULL);
return FU_CONSOLE(self);
}

69
src/fu-console.h Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <fwupdplugin.h>
#define FU_TYPE_CONSOLE (fu_console_get_type())
G_DECLARE_FINAL_TYPE(FuConsole, fu_console, FU, CONSOLE, GObject)
typedef enum {
FU_CONSOLE_COLOR_BLACK = 30,
FU_CONSOLE_COLOR_RED = 31,
FU_CONSOLE_COLOR_GREEN = 32,
FU_CONSOLE_COLOR_YELLOW = 33,
FU_CONSOLE_COLOR_BLUE = 34,
FU_CONSOLE_COLOR_MAGENTA = 35,
FU_CONSOLE_COLOR_CYAN = 36,
FU_CONSOLE_COLOR_WHITE = 37,
} FuConsoleColor;
typedef enum {
FU_CONSOLE_PRINT_FLAG_NONE = 0,
FU_CONSOLE_PRINT_FLAG_STDERR = 1 << 0,
FU_CONSOLE_PRINT_FLAG_WARNING = 1 << 1,
} FuConsolePrintFlags;
gchar *
fu_console_color_format(const gchar *text, FuConsoleColor fg_color);
FuConsole *
fu_console_new(void);
gboolean
fu_console_setup(FuConsole *self, GError **error);
guint
fu_console_input_uint(FuConsole *self, guint maxnum);
gboolean
fu_console_input_bool(FuConsole *self, gboolean def, const gchar *format, ...) G_GNUC_PRINTF(3, 4);
void
fu_console_print_full(FuConsole *self, FuConsolePrintFlags flags, const gchar *format, ...)
G_GNUC_PRINTF(3, 4);
void
fu_console_print(FuConsole *self, const gchar *format, ...) G_GNUC_PRINTF(2, 3);
void
fu_console_print_literal(FuConsole *self, const gchar *text);
void
fu_console_print_kv(FuConsole *self, const gchar *title, const gchar *msg);
void
fu_console_line(FuConsole *self, guint width);
void
fu_console_box(FuConsole *self, const gchar *title, const gchar *body, guint width);
void
fu_console_set_progress(FuConsole *self, FwupdStatus status, guint percentage);
void
fu_console_set_status_length(FuConsole *self, guint len);
void
fu_console_set_percentage_length(FuConsole *self, guint len);
void
fu_console_set_progress_title(FuConsole *self, const gchar *title);
void
fu_console_set_interactive(FuConsole *self, gboolean interactive);
void
fu_console_set_main_context(FuConsole *self, GMainContext *main_ctx);

View File

@ -1,475 +0,0 @@
/*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuProgressBar"
#include "config.h"
#include <glib/gi18n.h>
#include "fu-progressbar.h"
static void
fu_progressbar_finalize(GObject *obj);
struct _FuProgressbar {
GObject parent_instance;
GMainContext *main_ctx;
FwupdStatus status;
gboolean spinner_count_up; /* chars */
guint spinner_idx; /* chars */
guint length_percentage; /* chars */
guint length_status; /* chars */
guint percentage;
GSource *timer_source;
gint64 last_animated; /* monotonic */
GTimer *time_elapsed;
gdouble last_estimate;
gboolean interactive;
};
G_DEFINE_TYPE(FuProgressbar, fu_progressbar, G_TYPE_OBJECT)
static const gchar *
fu_progressbar_status_to_string(FwupdStatus status)
{
switch (status) {
case FWUPD_STATUS_IDLE:
/* TRANSLATORS: daemon is inactive */
return _("Idle…");
break;
case FWUPD_STATUS_DECOMPRESSING:
/* TRANSLATORS: decompressing the firmware file */
return _("Decompressing…");
break;
case FWUPD_STATUS_LOADING:
/* TRANSLATORS: parsing the firmware information */
return _("Loading…");
break;
case FWUPD_STATUS_DEVICE_RESTART:
/* TRANSLATORS: restarting the device to pick up new F/W */
return _("Restarting device…");
break;
case FWUPD_STATUS_DEVICE_READ:
/* TRANSLATORS: reading from the flash chips */
return _("Reading…");
break;
case FWUPD_STATUS_DEVICE_WRITE:
/* TRANSLATORS: writing to the flash chips */
return _("Writing…");
break;
case FWUPD_STATUS_DEVICE_ERASE:
/* TRANSLATORS: erasing contents of the flash chips */
return _("Erasing…");
break;
case FWUPD_STATUS_DEVICE_VERIFY:
/* TRANSLATORS: verifying we wrote the firmware correctly */
return _("Verifying…");
break;
case FWUPD_STATUS_SCHEDULING:
/* TRANSLATORS: scheduling an update to be done on the next boot */
return _("Scheduling…");
break;
case FWUPD_STATUS_DOWNLOADING:
/* TRANSLATORS: downloading from a remote server */
return _("Downloading…");
break;
case FWUPD_STATUS_WAITING_FOR_AUTH:
/* TRANSLATORS: waiting for user to authenticate */
return _("Authenticating…");
break;
case FWUPD_STATUS_DEVICE_BUSY:
/* TRANSLATORS: waiting for device to do something */
return _("Waiting…");
break;
default:
break;
}
/* TRANSLATORS: current daemon status is unknown */
return _("Unknown");
}
static void
fu_progressbar_erase_line(FuProgressbar *self)
{
if (!self->interactive)
return;
g_print("\033[G");
}
static gboolean
_fu_status_is_predictable(FwupdStatus status)
{
if (status == FWUPD_STATUS_DEVICE_ERASE)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_VERIFY)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_READ)
return TRUE;
if (status == FWUPD_STATUS_DEVICE_WRITE)
return TRUE;
if (status == FWUPD_STATUS_DOWNLOADING)
return TRUE;
return FALSE;
}
static gboolean
fu_progressbar_estimate_ready(FuProgressbar *self, guint percentage)
{
gdouble old;
gdouble elapsed;
/* now invalid */
if (percentage == 0 || percentage == 100) {
g_timer_start(self->time_elapsed);
self->last_estimate = 0;
return FALSE;
}
/* allow-list things that make sense... */
if (!_fu_status_is_predictable(self->status))
return FALSE;
old = self->last_estimate;
elapsed = g_timer_elapsed(self->time_elapsed, NULL);
self->last_estimate = elapsed / percentage * (100 - percentage);
/* estimate is ready if we have decreased */
return old > self->last_estimate;
}
static gchar *
fu_progressbar_time_remaining_str(FuProgressbar *self)
{
/* less than 5 seconds remaining */
if (self->last_estimate < 5)
return NULL;
/* less than 60 seconds remaining */
if (self->last_estimate < 60) {
/* TRANSLATORS: time remaining for completing firmware flash */
return g_strdup(_("Less than one minute remaining"));
}
return g_strdup_printf(
/* TRANSLATORS: more than a minute */
ngettext("%.0f minute remaining", "%.0f minutes remaining", self->last_estimate / 60),
self->last_estimate / 60);
}
static void
fu_progressbar_refresh(FuProgressbar *self, FwupdStatus status, guint percentage)
{
const gchar *title;
guint i;
gboolean is_idle_newline = FALSE;
g_autoptr(GString) str = g_string_new(NULL);
g_return_if_fail(percentage <= 100);
/* erase previous line */
fu_progressbar_erase_line(self);
/* add status */
if (status == FWUPD_STATUS_IDLE || status == FWUPD_STATUS_UNKNOWN) {
status = self->status;
is_idle_newline = TRUE;
}
if (percentage == 100)
is_idle_newline = TRUE;
title = fu_progressbar_status_to_string(status);
g_string_append(str, title);
for (i = fu_strwidth(str->str); i < self->length_status; i++)
g_string_append_c(str, ' ');
/* add progressbar */
g_string_append(str, "[");
if (percentage > 0) {
for (i = 0; i < (self->length_percentage - 1) * percentage / 100; i++)
g_string_append_c(str, '*');
for (i = i + 1; i < self->length_percentage; i++)
g_string_append_c(str, ' ');
} else {
const gchar chars[] = {
'-',
'\\',
'|',
'/',
};
for (i = 0; i < self->spinner_idx; i++)
g_string_append_c(str, ' ');
g_string_append_c(str, chars[i / 4 % G_N_ELEMENTS(chars)]);
for (i = i + 1; i < self->length_percentage - 1; i++)
g_string_append_c(str, ' ');
}
g_string_append_c(str, ']');
/* once we have good data show an estimate of time remaining */
if (fu_progressbar_estimate_ready(self, percentage)) {
g_autofree gchar *remaining = fu_progressbar_time_remaining_str(self);
if (remaining != NULL)
g_string_append_printf(str, " %s…", remaining);
}
/* dump to screen */
g_print("%s", str->str);
/* done */
if (is_idle_newline) {
g_print("\n");
return;
}
}
/**
* fu_progressbar_set_title:
* @self: A #FuProgressbar
* @title: A string
*
* Sets progressbar title
*
* Since: 0.9.7
**/
void
fu_progressbar_set_title(FuProgressbar *self, const gchar *title)
{
fu_progressbar_erase_line(self);
g_print("%s\n", title);
fu_progressbar_refresh(self, self->status, self->percentage);
}
/**
* fu_progressbar_set_main_context:
* @self: A #FuProgressbar
* @main_ctx: (nullable): main context
*
* Sets progressbar main context to use for animations.
*
* Since: 1.6.2
**/
void
fu_progressbar_set_main_context(FuProgressbar *self, GMainContext *main_ctx)
{
self->main_ctx = g_main_context_ref(main_ctx);
}
static void
fu_progressbar_spin_inc(FuProgressbar *self)
{
/* reset */
self->last_animated = g_get_monotonic_time();
/* up to down */
if (self->spinner_count_up) {
if (++self->spinner_idx > self->length_percentage - 3)
self->spinner_count_up = FALSE;
} else {
if (--self->spinner_idx == 0)
self->spinner_count_up = TRUE;
}
}
static gboolean
fu_progressbar_spin_cb(gpointer user_data)
{
FuProgressbar *self = FU_PROGRESSBAR(user_data);
/* ignore */
if (self->status == FWUPD_STATUS_IDLE || self->status == FWUPD_STATUS_UNKNOWN)
return G_SOURCE_CONTINUE;
/* move the spinner index up to down */
fu_progressbar_spin_inc(self);
/* update the terminal */
fu_progressbar_refresh(self, self->status, self->percentage);
return G_SOURCE_CONTINUE;
}
static void
fu_progressbar_spin_end(FuProgressbar *self)
{
if (self->timer_source != NULL) {
g_source_destroy(self->timer_source);
self->timer_source = NULL;
/* reset when the spinner has been stopped */
g_timer_start(self->time_elapsed);
}
/* go back to the start when we next go into unknown percentage mode */
self->spinner_idx = 0;
self->spinner_count_up = TRUE;
}
static void
fu_progressbar_spin_start(FuProgressbar *self)
{
if (self->timer_source != NULL)
g_source_destroy(self->timer_source);
self->timer_source = g_timeout_source_new(40);
g_source_set_callback(self->timer_source, fu_progressbar_spin_cb, self, NULL);
g_source_attach(self->timer_source, self->main_ctx);
}
/**
* fu_progressbar_update:
* @self: A #FuProgressbar
* @status: A #FwupdStatus
* @percentage: unsigned integer
*
* Refreshes a progressbar
*
* Since: 0.9.7
**/
void
fu_progressbar_update(FuProgressbar *self, FwupdStatus status, guint percentage)
{
g_return_if_fail(FU_IS_PROGRESSBAR(self));
/* not useful */
if (status == FWUPD_STATUS_UNKNOWN)
return;
/* ignore initial client connection */
if (self->status == FWUPD_STATUS_UNKNOWN && status == FWUPD_STATUS_IDLE) {
self->status = status;
return;
}
if (!self->interactive) {
g_print("%s: %u%%\n", fu_progressbar_status_to_string(status), percentage);
self->status = status;
self->percentage = percentage;
return;
}
/* if the main loop isn't spinning and we've not had a chance to
* execute the callback just do the refresh now manually */
if (percentage == 0 && status != FWUPD_STATUS_IDLE &&
self->status != FWUPD_STATUS_UNKNOWN) {
if ((g_get_monotonic_time() - self->last_animated) / 1000 > 40) {
fu_progressbar_spin_inc(self);
fu_progressbar_refresh(self, status, percentage);
}
}
/* ignore duplicates */
if (self->status == status && self->percentage == percentage)
return;
/* enable or disable the spinner timeout */
if (percentage > 0) {
fu_progressbar_spin_end(self);
} else {
fu_progressbar_spin_start(self);
}
/* update the terminal */
fu_progressbar_refresh(self, status, percentage);
/* cache */
self->status = status;
self->percentage = percentage;
}
/**
* fu_progressbar_set_interactive:
* @self: A #FuProgressbar
* @interactive: #gboolean
*
* Marks the progressbar as interactive or not
*
* Since: 0.9.7
**/
void
fu_progressbar_set_interactive(FuProgressbar *self, gboolean interactive)
{
g_return_if_fail(FU_IS_PROGRESSBAR(self));
self->interactive = interactive;
}
/**
* fu_progressbar_set_length_status:
* @self: A #FuProgressbar
* @len: unsigned integer
*
* Sets the length of the progressbar status
*
* Since: 0.9.7
**/
void
fu_progressbar_set_length_status(FuProgressbar *self, guint len)
{
g_return_if_fail(FU_IS_PROGRESSBAR(self));
g_return_if_fail(len > 3);
self->length_status = len;
}
/**
* fu_progressbar_set_length_percentage:
* @self: A #FuProgressbar
* @len: unsigned integer
*
* Sets the length of the progressba percentage
*
* Since: 0.9.7
**/
void
fu_progressbar_set_length_percentage(FuProgressbar *self, guint len)
{
g_return_if_fail(FU_IS_PROGRESSBAR(self));
g_return_if_fail(len > 3);
self->length_percentage = len;
}
static void
fu_progressbar_class_init(FuProgressbarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = fu_progressbar_finalize;
}
static void
fu_progressbar_init(FuProgressbar *self)
{
self->length_percentage = 40;
self->length_status = 25;
self->spinner_count_up = TRUE;
self->time_elapsed = g_timer_new();
self->interactive = TRUE;
}
static void
fu_progressbar_finalize(GObject *obj)
{
FuProgressbar *self = FU_PROGRESSBAR(obj);
if (self->timer_source != 0)
g_source_destroy(self->timer_source);
if (self->main_ctx != NULL)
g_main_context_unref(self->main_ctx);
g_timer_destroy(self->time_elapsed);
G_OBJECT_CLASS(fu_progressbar_parent_class)->finalize(obj);
}
/**
* fu_progressbar_new:
*
* Creates a new #FuProgressbar
*
* Since: 0.9.7
**/
FuProgressbar *
fu_progressbar_new(void)
{
FuProgressbar *self;
self = g_object_new(FU_TYPE_PROGRESSBAR, NULL);
return FU_PROGRESSBAR(self);
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <fwupdplugin.h>
#define FU_TYPE_PROGRESSBAR (fu_progressbar_get_type())
G_DECLARE_FINAL_TYPE(FuProgressbar, fu_progressbar, FU, PROGRESSBAR, GObject)
FuProgressbar *
fu_progressbar_new(void);
void
fu_progressbar_update(FuProgressbar *self, FwupdStatus status, guint percentage);
void
fu_progressbar_set_length_status(FuProgressbar *self, guint len);
void
fu_progressbar_set_length_percentage(FuProgressbar *self, guint len);
void
fu_progressbar_set_title(FuProgressbar *self, const gchar *title);
void
fu_progressbar_set_interactive(FuProgressbar *self, gboolean interactive);
void
fu_progressbar_set_main_context(FuProgressbar *self, GMainContext *main_ctx);

View File

@ -21,6 +21,7 @@
#include "fu-bios-settings-private.h"
#include "fu-cabinet-common.h"
#include "fu-config.h"
#include "fu-console.h"
#include "fu-context-private.h"
#include "fu-device-list.h"
#include "fu-device-private.h"
@ -28,7 +29,6 @@
#include "fu-history.h"
#include "fu-plugin-list.h"
#include "fu-plugin-private.h"
#include "fu-progressbar.h"
#include "fu-release-common.h"
#include "fu-security-attr-common.h"
#include "fu-smbios-private.h"
@ -4089,31 +4089,31 @@ fu_memcpy_func(gconstpointer user_data)
}
static void
fu_progressbar_func(gconstpointer user_data)
fu_console_func(gconstpointer user_data)
{
g_autoptr(FuProgressbar) progressbar = fu_progressbar_new();
g_autoptr(FuConsole) console = fu_console_new();
fu_progressbar_set_length_status(progressbar, 20);
fu_progressbar_set_length_percentage(progressbar, 50);
fu_console_set_status_length(console, 20);
fu_console_set_percentage_length(console, 50);
g_print("\n");
for (guint i = 0; i < 100; i++) {
fu_progressbar_update(progressbar, FWUPD_STATUS_DECOMPRESSING, i);
fu_console_set_progress(console, FWUPD_STATUS_DECOMPRESSING, i);
g_usleep(10000);
}
fu_progressbar_update(progressbar, FWUPD_STATUS_IDLE, 0);
fu_console_set_progress(console, FWUPD_STATUS_IDLE, 0);
for (guint i = 0; i < 100; i++) {
guint pc = (i > 25 && i < 75) ? 0 : i;
fu_progressbar_update(progressbar, FWUPD_STATUS_LOADING, pc);
fu_console_set_progress(console, FWUPD_STATUS_LOADING, pc);
g_usleep(10000);
}
fu_progressbar_update(progressbar, FWUPD_STATUS_IDLE, 0);
fu_console_set_progress(console, FWUPD_STATUS_IDLE, 0);
for (guint i = 0; i < 5000; i++) {
fu_progressbar_update(progressbar, FWUPD_STATUS_LOADING, 0);
fu_console_set_progress(console, FWUPD_STATUS_LOADING, 0);
g_usleep(1000);
}
fu_progressbar_update(progressbar, FWUPD_STATUS_IDLE, 0);
fu_console_set_progress(console, FWUPD_STATUS_IDLE, 0);
}
static gint
@ -4889,7 +4889,7 @@ main(int argc, char **argv)
/* tests go here */
if (g_test_slow()) {
g_test_add_data_func("/fwupd/progressbar", self, fu_progressbar_func);
g_test_add_data_func("/fwupd/console", self, fu_console_func);
}
g_test_add_data_func("/fwupd/backend{usb}", self, fu_backend_usb_func);
g_test_add_data_func("/fwupd/backend{usb-invalid}", self, fu_backend_usb_invalid_func);

View File

@ -30,13 +30,13 @@
#include "fu-bios-settings-private.h"
#include "fu-cabinet.h"
#include "fu-console.h"
#include "fu-context-private.h"
#include "fu-debug.h"
#include "fu-device-private.h"
#include "fu-engine.h"
#include "fu-history.h"
#include "fu-plugin-private.h"
#include "fu-progressbar.h"
#include "fu-security-attr-common.h"
#include "fu-security-attrs-private.h"
#include "fu-smbios-private.h"
@ -66,7 +66,7 @@ struct FuUtilPrivate {
FuEngine *engine;
FuEngineRequest *request;
FuProgress *progress;
FuProgressbar *progressbar;
FuConsole *console;
FwupdClient *client;
gboolean as_json;
gboolean no_reboot_check;
@ -94,9 +94,9 @@ fu_util_client_notify_cb(GObject *object, GParamSpec *pspec, FuUtilPrivate *priv
{
if (priv->as_json)
return;
fu_progressbar_update(priv->progressbar,
fwupd_client_get_status(priv->client),
fwupd_client_get_percentage(priv->client));
fu_console_set_progress(priv->console,
fwupd_client_get_status(priv->client),
fwupd_client_get_percentage(priv->client));
}
static void
@ -125,7 +125,6 @@ fu_util_show_plugin_warnings(FuUtilPrivate *priv)
for (guint i = 0; i < 64; i++) {
FwupdPluginFlags flag = (guint64)1 << i;
const gchar *tmp;
g_autofree gchar *fmt = NULL;
g_autofree gchar *url = NULL;
g_autoptr(GString) str = g_string_new(NULL);
if ((flags & flag) == 0)
@ -133,17 +132,11 @@ fu_util_show_plugin_warnings(FuUtilPrivate *priv)
tmp = fu_util_plugin_flag_to_string((guint64)1 << i);
if (tmp == NULL)
continue;
/* TRANSLATORS: this is a prefix on the console */
fmt = fu_util_term_format(_("WARNING:"), FU_UTIL_TERM_COLOR_RED);
g_string_append_printf(str, "%s %s\n", fmt, tmp);
fu_console_print_full(priv->console, FU_CONSOLE_PRINT_FLAG_WARNING, "%s\n", tmp);
url = g_strdup_printf("https://github.com/fwupd/fwupd/wiki/PluginFlag:%s",
fwupd_plugin_flag_to_string(flag));
g_string_append(str, " ");
/* TRANSLATORS: %s is a link to a website */
g_string_append_printf(str, _("See %s for more information."), url);
g_string_append(str, "\n");
g_printerr("%s", str->str);
fu_console_print(priv->console, _("See %s for more information."), url);
}
}
@ -234,7 +227,7 @@ fu_util_start_engine(FuUtilPrivate *priv,
if (!fu_engine_load(priv->engine, flags, progress, error))
return FALSE;
fu_util_show_plugin_warnings(priv);
fu_util_show_unsupported_warn();
fu_util_show_unsupported_warning(priv->console);
/* copy properties from engine to client */
g_object_set(priv->client,
@ -270,7 +263,7 @@ fu_util_cancelled_cb(GCancellable *cancellable, gpointer user_data)
{
FuUtilPrivate *priv = (FuUtilPrivate *)user_data;
/* TRANSLATORS: this is when a device ctrl+c's a watch */
g_print("%s\n", _("Cancelled"));
fu_console_print_literal(priv->console, _("Cancelled"));
g_main_loop_quit(priv->loop);
}
@ -290,7 +283,7 @@ fu_util_smbios_dump(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_smbios_setup_from_file(smbios, values[0], error))
return FALSE;
tmp = fu_firmware_to_string(FU_FIRMWARE(smbios));
g_print("%s\n", tmp);
fu_console_print_literal(priv->console, tmp);
return TRUE;
}
@ -332,8 +325,8 @@ fu_util_private_free(FuUtilPrivate *priv)
g_main_loop_unref(priv->loop);
if (priv->cancellable != NULL)
g_object_unref(priv->cancellable);
if (priv->progressbar != NULL)
g_object_unref(priv->progressbar);
if (priv->console != NULL)
g_object_unref(priv->console);
if (priv->progress != NULL)
g_object_unref(priv->progress);
if (priv->context != NULL)
@ -366,9 +359,9 @@ fu_util_update_device_request_cb(FwupdClient *client, FwupdRequest *request, FuU
g_autofree gchar *tmp = NULL;
/* TRANSLATORS: the user needs to do something, e.g. remove the device */
fmt = fu_util_term_format(_("Action Required:"), FU_UTIL_TERM_COLOR_RED);
fmt = fu_console_color_format(_("Action Required:"), FU_CONSOLE_COLOR_RED);
tmp = g_strdup_printf("%s %s", fmt, fwupd_request_get_message(request));
fu_progressbar_set_title(priv->progressbar, tmp);
fu_console_set_progress_title(priv->console, tmp);
}
/* save for later */
@ -395,7 +388,7 @@ fu_main_engine_status_changed_cb(FuEngine *engine, FwupdStatus status, FuUtilPri
{
if (priv->as_json)
return;
fu_progressbar_update(priv->progressbar, status, 0);
fu_console_set_progress(priv->console, status, 0);
}
static void
@ -403,7 +396,7 @@ fu_util_progress_percentage_changed_cb(FuProgress *progress, guint percentage, F
{
if (priv->as_json)
return;
fu_progressbar_update(priv->progressbar, fu_progress_get_status(progress), percentage);
fu_console_set_progress(priv->console, fu_progress_get_status(progress), percentage);
}
static void
@ -411,7 +404,7 @@ fu_util_progress_status_changed_cb(FuProgress *progress, FwupdStatus status, FuU
{
if (priv->as_json)
return;
fu_progressbar_update(priv->progressbar, status, fu_progress_get_percentage(progress));
fu_console_set_progress(priv->console, status, fu_progress_get_percentage(progress));
}
static gboolean
@ -445,7 +438,7 @@ fu_util_get_plugins_as_json(FuUtilPrivate *priv, GPtrArray *plugins, GError **er
}
json_builder_end_array(builder);
json_builder_end_object(builder);
return fu_util_print_builder(builder, error);
return fu_util_print_builder(priv->console, builder, error);
}
static gboolean
@ -467,11 +460,11 @@ fu_util_get_plugins(FuUtilPrivate *priv, gchar **values, GError **error)
for (guint i = 0; i < plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index(plugins, i);
g_autofree gchar *str = fu_util_plugin_to_string(FWUPD_PLUGIN(plugin), 0);
g_print("%s\n", str);
fu_console_print_literal(priv->console, str);
}
if (plugins->len == 0) {
/* TRANSLATORS: nothing found */
g_print("%s\n", _("No plugins found"));
fu_console_print_literal(priv->console, _("No plugins found"));
}
return TRUE;
@ -531,8 +524,12 @@ fu_util_prompt_for_device(FuUtilPrivate *priv, GPtrArray *devices_opt, GError **
if (devices_filtered->len == 1) {
dev = g_ptr_array_index(devices_filtered, 0);
if (!priv->as_json) {
/* TRANSLATORS: device has been chosen by the daemon for the user */
g_print("%s: %s\n", _("Selected device"), fu_device_get_name(dev));
fu_console_print(
priv->console,
"%s: %s",
/* TRANSLATORS: device has been chosen by the daemon for the user */
_("Selected device"),
fu_device_get_name(dev));
}
return g_object_ref(dev);
}
@ -547,14 +544,18 @@ fu_util_prompt_for_device(FuUtilPrivate *priv, GPtrArray *devices_opt, GError **
}
/* TRANSLATORS: get interactive prompt */
g_print("%s\n", _("Choose a device:"));
fu_console_print_literal(priv->console, _("Choose a device:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print("0.\t%s\n", _("Cancel"));
fu_console_print(priv->console, "0.\t%s", _("Cancel"));
for (guint i = 0; i < devices_filtered->len; i++) {
dev = g_ptr_array_index(devices_filtered, i);
g_print("%u.\t%s (%s)\n", i + 1, fu_device_get_id(dev), fu_device_get_name(dev));
fu_console_print(priv->console,
"%u.\t%s (%s)",
i + 1,
fu_device_get_id(dev),
fu_device_get_name(dev));
}
idx = fu_util_prompt_for_number(devices_filtered->len);
idx = fu_console_input_uint(priv->console, devices_filtered->len);
if (idx == 0) {
g_set_error_literal(error,
FWUPD_ERROR,
@ -666,20 +667,23 @@ fu_util_get_updates(FuUtilPrivate *priv, gchar **values, GError **error)
/* devices that have no updates available for whatever reason */
if (devices_no_support->len > 0) {
/* TRANSLATORS: message letting the user know no device upgrade
* available due to missing on LVFS */
g_printerr("%s\n", _("Devices with no available firmware updates: "));
fu_console_print_literal(priv->console,
/* TRANSLATORS: message letting the user know no device
* upgrade available due to missing on LVFS */
_("Devices with no available firmware updates: "));
for (guint i = 0; i < devices_no_support->len; i++) {
FwupdDevice *dev = g_ptr_array_index(devices_no_support, i);
g_printerr(" • %s\n", fwupd_device_get_name(dev));
fu_console_print(priv->console, " • %s", fwupd_device_get_name(dev));
}
}
if (devices_no_upgrades->len > 0) {
/* TRANSLATORS: message letting the user know no device upgrade available */
g_printerr("%s\n", _("Devices with the latest available firmware version:"));
fu_console_print_literal(
priv->console,
/* TRANSLATORS: message letting the user know no device upgrade available */
_("Devices with the latest available firmware version:"));
for (guint i = 0; i < devices_no_upgrades->len; i++) {
FwupdDevice *dev = g_ptr_array_index(devices_no_upgrades, i);
g_printerr(" • %s\n", fwupd_device_get_name(dev));
fu_console_print(priv->console, " • %s", fwupd_device_get_name(dev));
}
}
@ -692,7 +696,7 @@ fu_util_get_updates(FuUtilPrivate *priv, gchar **values, GError **error)
return FALSE;
}
fu_util_print_tree(priv->client, root);
fu_util_print_tree(priv->console, priv->client, root);
return TRUE;
}
@ -750,7 +754,7 @@ fu_util_get_details(FuUtilPrivate *priv, gchar **values, GError **error)
if (rel != NULL)
g_node_append_data(child, rel);
}
fu_util_print_tree(priv->client, root);
fu_util_print_tree(priv->console, priv->client, root);
return TRUE;
}
@ -771,7 +775,7 @@ fu_util_get_device_flags(FuUtilPrivate *priv, gchar **values, GError **error)
g_string_append(str, " ~");
g_string_append(str, tmp);
}
g_print("%s\n", str->str);
fu_console_print_literal(priv->console, str->str);
return TRUE;
}
@ -817,11 +821,12 @@ fu_util_get_devices(FuUtilPrivate *priv, gchar **values, GError **error)
/* print */
if (g_node_n_children(root) == 0) {
/* TRANSLATORS: nothing attached that can be upgraded */
g_print("%s\n", _("No hardware detected with firmware update capability"));
fu_console_print_literal(priv->console,
/* TRANSLATORS: nothing attached that can be upgraded */
_("No hardware detected with firmware update capability"));
return TRUE;
}
fu_util_print_tree(priv->client, root);
fu_util_print_tree(priv->console, priv->client, root);
return TRUE;
}
@ -854,19 +859,19 @@ fu_util_update_device_changed_cb(FwupdClient *client, FwupdDevice *device, FuUti
return;
}
/* show message in progressbar */
/* show message in console */
if (priv->current_operation == FU_UTIL_OPERATION_UPDATE) {
/* TRANSLATORS: %1 is a device name */
str = g_strdup_printf(_("Updating %s…"), fwupd_device_get_name(device));
fu_progressbar_set_title(priv->progressbar, str);
fu_console_set_progress_title(priv->console, str);
} else if (priv->current_operation == FU_UTIL_OPERATION_INSTALL) {
/* TRANSLATORS: %1 is a device name */
str = g_strdup_printf(_("Installing on %s…"), fwupd_device_get_name(device));
fu_progressbar_set_title(priv->progressbar, str);
fu_console_set_progress_title(priv->console, str);
} else if (priv->current_operation == FU_UTIL_OPERATION_READ) {
/* TRANSLATORS: %1 is a device name */
str = g_strdup_printf(_("Reading from %s…"), fwupd_device_get_name(device));
fu_progressbar_set_title(priv->progressbar, str);
fu_console_set_progress_title(priv->console, str);
} else {
g_warning("no FuUtilOperation set");
}
@ -879,7 +884,7 @@ fu_util_display_current_message(FuUtilPrivate *priv)
/* print all POST requests */
for (guint i = 0; i < priv->post_requests->len; i++) {
FwupdRequest *request = g_ptr_array_index(priv->post_requests, i);
g_print("%s\n", fu_util_request_get_message(request));
fu_console_print_literal(priv->console, fu_util_request_get_message(request));
}
}
@ -984,7 +989,7 @@ fu_util_install_blob(FuUtilPrivate *priv, gchar **values, GError **error)
fu_util_display_current_message(priv);
/* success */
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -1251,7 +1256,7 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
if (device == NULL)
return FALSE;
if (!priv->no_safety_check) {
if (!fu_util_prompt_warning_fde(FWUPD_DEVICE(device), error))
if (!fu_util_prompt_warning_fde(priv->console, FWUPD_DEVICE(device), error))
return FALSE;
}
devices_possible =
@ -1381,7 +1386,7 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
}
/* success */
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -1510,13 +1515,14 @@ fu_util_update(FuUtilPrivate *priv, gchar **values, GError **error)
continue;
if (!fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_SUPPORTED)) {
if (!no_updates_header) {
g_printerr("%s\n",
/* TRANSLATORS: message letting the user know no device
* upgrade available due to missing on LVFS */
_("Devices with no available firmware updates: "));
fu_console_print_literal(
priv->console,
/* TRANSLATORS: message letting the user know no
* device upgrade available due to missing on LVFS */
_("Devices with no available firmware updates: "));
no_updates_header = TRUE;
}
g_printerr(" • %s\n", fwupd_device_get_name(dev));
fu_console_print(priv->console, " • %s", fwupd_device_get_name(dev));
continue;
}
if (!fu_util_filter_device(priv, dev))
@ -1525,14 +1531,14 @@ fu_util_update(FuUtilPrivate *priv, gchar **values, GError **error)
rels = fu_engine_get_upgrades(priv->engine, priv->request, device_id, &error_local);
if (rels == NULL) {
if (!latest_header) {
g_printerr(
"%s\n",
fu_console_print_literal(
priv->console,
/* TRANSLATORS: message letting the user know no device upgrade
* available */
_("Devices with the latest available firmware version:"));
latest_header = TRUE;
}
g_printerr(" • %s\n", fwupd_device_get_name(dev));
fu_console_print(priv->console, " • %s", fwupd_device_get_name(dev));
/* discard the actual reason from user, but leave for debugging */
g_debug("%s", error_local->message);
continue;
@ -1544,14 +1550,14 @@ fu_util_update(FuUtilPrivate *priv, gchar **values, GError **error)
g_strdup_printf("%s %s",
fu_engine_get_host_vendor(priv->engine),
fu_engine_get_host_product(priv->engine));
if (!fu_util_prompt_warning(dev, rel, title, error))
if (!fu_util_prompt_warning(priv->console, dev, rel, title, error))
return FALSE;
if (!fu_util_prompt_warning_fde(dev, error))
if (!fu_util_prompt_warning_fde(priv->console, dev, error))
return FALSE;
}
if (!fu_util_install_release(priv, rel, &error_local)) {
g_printerr("%s\n", error_local->message);
fu_console_print_literal(priv->console, error_local->message);
continue;
}
fu_util_display_current_message(priv);
@ -1563,7 +1569,7 @@ fu_util_update(FuUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -1633,7 +1639,7 @@ fu_util_reinstall(FuUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -1861,7 +1867,7 @@ fu_util_get_report_metadata(FuUtilPrivate *priv, gchar **values, GError **error)
fu_progress_step_done(priv->progress);
/* display */
g_print("\n%s", str->str);
fu_console_print_literal(priv->console, str->str);
/* success */
return TRUE;
@ -1951,8 +1957,12 @@ fu_util_activate(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION))
continue;
has_pending = TRUE;
/* TRANSLATORS: shown when shutting down to switch to the new version */
g_print("%s %s…\n", _("Activating firmware update"), fu_device_get_name(device));
fu_console_print(
priv->console,
"%s %s…",
/* TRANSLATORS: shown when shutting down to switch to the new version */
_("Activating firmware update"),
fu_device_get_name(device));
if (!fu_engine_activate(priv->engine,
fu_device_get_id(device),
fu_progress_get_child(priv->progress),
@ -2030,8 +2040,8 @@ fu_util_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
return FALSE;
/* show debug output */
g_print("Computer Information\n");
g_print("--------------------\n");
fu_console_print_literal(priv->console, "Computer Information");
fu_console_print_literal(priv->console, "--------------------");
for (guint i = 0; i < hwid_keys->len; i++) {
const gchar *hwid_key = g_ptr_array_index(hwid_keys, i);
const gchar *value = fu_hwids_get_value(hwids, hwid_key);
@ -2040,15 +2050,15 @@ fu_util_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
if (g_strcmp0(hwid_key, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE) == 0 ||
g_strcmp0(hwid_key, FU_HWIDS_KEY_BIOS_MINOR_RELEASE) == 0) {
guint64 val = g_ascii_strtoull(value, NULL, 16);
g_print("%s: %" G_GUINT64_FORMAT "\n", hwid_key, val);
fu_console_print(priv->console, "%s: %" G_GUINT64_FORMAT, hwid_key, val);
} else {
g_print("%s: %s\n", hwid_key, value);
fu_console_print(priv->console, "%s: %s", hwid_key, value);
}
}
/* show GUIDs */
g_print("\nHardware IDs\n");
g_print("------------\n");
fu_console_print_literal(priv->console, "Hardware IDs");
fu_console_print_literal(priv->console, "------------");
for (guint i = 0; i < 15; i++) {
const gchar *keys = NULL;
g_autofree gchar *guid = NULL;
@ -2062,14 +2072,14 @@ fu_util_hwids(FuUtilPrivate *priv, gchar **values, GError **error)
keys = fu_hwids_get_replace_keys(hwids, key);
guid = fu_hwids_get_guid(hwids, key, &error_local);
if (guid == NULL) {
g_print("%s\n", error_local->message);
fu_console_print_literal(priv->console, error_local->message);
continue;
}
/* show what makes up the GUID */
keysv = g_strsplit(keys, "&", -1);
keys_str = g_strjoinv(" + ", keysv);
g_print("{%s} <- %s\n", guid, keys_str);
fu_console_print(priv->console, "{%s} <- %s", guid, keys_str);
}
return TRUE;
@ -2098,7 +2108,7 @@ fu_util_self_sign(FuUtilPrivate *priv, gchar **values, GError **error)
error);
if (sig == NULL)
return FALSE;
g_print("%s\n", sig);
fu_console_print_literal(priv->console, sig);
return TRUE;
}
@ -2108,7 +2118,7 @@ fu_util_device_added_cb(FwupdClient *client, FwupdDevice *device, gpointer user_
FuUtilPrivate *priv = (FuUtilPrivate *)user_data;
g_autofree gchar *tmp = fu_util_device_to_string(priv->client, device, 0);
/* TRANSLATORS: this is when a device is hotplugged */
g_print("%s\n%s", _("Device added:"), tmp);
fu_console_print(priv->console, "%s\n%s", _("Device added:"), tmp);
}
static void
@ -2117,7 +2127,7 @@ fu_util_device_removed_cb(FwupdClient *client, FwupdDevice *device, gpointer use
FuUtilPrivate *priv = (FuUtilPrivate *)user_data;
g_autofree gchar *tmp = fu_util_device_to_string(priv->client, device, 0);
/* TRANSLATORS: this is when a device is hotplugged */
g_print("%s\n%s", _("Device removed:"), tmp);
fu_console_print(priv->console, "%s\n%s", _("Device removed:"), tmp);
}
static void
@ -2126,14 +2136,15 @@ fu_util_device_changed_cb(FwupdClient *client, FwupdDevice *device, gpointer use
FuUtilPrivate *priv = (FuUtilPrivate *)user_data;
g_autofree gchar *tmp = fu_util_device_to_string(priv->client, device, 0);
/* TRANSLATORS: this is when a device has been updated */
g_print("%s\n%s", _("Device changed:"), tmp);
fu_console_print(priv->console, "%s\n%s", _("Device changed:"), tmp);
}
static void
fu_util_changed_cb(FwupdClient *client, gpointer user_data)
{
FuUtilPrivate *priv = (FuUtilPrivate *)user_data;
/* TRANSLATORS: this is when the daemon state changes */
g_print("%s\n", _("Changed"));
fu_console_print_literal(priv->console, _("Changed"));
}
static gboolean
@ -2183,11 +2194,11 @@ fu_util_get_firmware_types(FuUtilPrivate *priv, gchar **values, GError **error)
firmware_types = fu_context_get_firmware_gtype_ids(fu_engine_get_context(priv->engine));
for (guint i = 0; i < firmware_types->len; i++) {
const gchar *id = g_ptr_array_index(firmware_types, i);
g_print("%s\n", id);
fu_console_print_literal(priv->console, id);
}
if (firmware_types->len == 0) {
/* TRANSLATORS: nothing found */
g_print("%s\n", _("No firmware IDs found"));
fu_console_print_literal(priv->console, _("No firmware IDs found"));
return TRUE;
}
@ -2202,14 +2213,14 @@ fu_util_prompt_for_firmware_type(FuUtilPrivate *priv, GError **error)
firmware_types = fu_context_get_firmware_gtype_ids(fu_engine_get_context(priv->engine));
/* TRANSLATORS: get interactive prompt */
g_print("%s\n", _("Choose a firmware type:"));
fu_console_print_literal(priv->console, _("Choose a firmware type:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print("0.\t%s\n", _("Cancel"));
fu_console_print(priv->console, "0.\t%s", _("Cancel"));
for (guint i = 0; i < firmware_types->len; i++) {
const gchar *id = g_ptr_array_index(firmware_types, i);
g_print("%u.\t%s\n", i + 1, id);
fu_console_print(priv->console, "%u.\t%s", i + 1, id);
}
idx = fu_util_prompt_for_number(firmware_types->len);
idx = fu_console_input_uint(priv->console, firmware_types->len);
if (idx == 0) {
g_set_error_literal(error,
FWUPD_ERROR,
@ -2289,7 +2300,7 @@ fu_util_firmware_parse(FuUtilPrivate *priv, gchar **values, GError **error)
}
str = fu_firmware_to_string(firmware);
g_print("%s", str);
fu_console_print_literal(priv->console, str);
return TRUE;
}
@ -2350,7 +2361,7 @@ fu_util_firmware_export(FuUtilPrivate *priv, gchar **values, GError **error)
str = fu_firmware_export_to_xml(firmware, flags, error);
if (str == NULL)
return FALSE;
g_print("%s", str);
fu_console_print_literal(priv->console, str);
return TRUE;
}
@ -2406,7 +2417,7 @@ fu_util_firmware_extract(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_firmware_parse(firmware, blob, priv->flags, error))
return FALSE;
str = fu_firmware_to_string(firmware);
g_print("%s", str);
fu_console_print_literal(priv->console, str);
images = fu_firmware_get_images(firmware);
for (guint i = 0; i < images->len; i++) {
FuFirmware *img = g_ptr_array_index(images, i);
@ -2431,7 +2442,7 @@ fu_util_firmware_extract(FuUtilPrivate *priv, gchar **values, GError **error)
fn = g_strdup_printf("img-0x%x.fw", i);
}
/* TRANSLATORS: decompressing images from a container firmware */
g_print("%s : %s\n", _("Writing file:"), fn);
fu_console_print(priv->console, "%s : %s", _("Writing file:"), fn);
if (!fu_bytes_set_contents(fn, blob_img, error))
return FALSE;
}
@ -2531,7 +2542,7 @@ fu_util_firmware_build(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_firmware_parse(firmware_dst, blob_dst, priv->flags, error))
return FALSE;
str = fu_firmware_to_string(firmware_dst);
g_print("%s", str);
fu_console_print_literal(priv->console, str);
/* success */
return TRUE;
@ -2611,7 +2622,7 @@ fu_util_firmware_convert(FuUtilPrivate *priv, gchar **values, GError **error)
return FALSE;
}
str_src = fu_firmware_to_string(firmware_src);
g_print("%s", str_src);
fu_console_print_literal(priv->console, str_src);
/* copy images */
firmware_dst = g_object_new(gtype_dst, NULL);
@ -2642,7 +2653,7 @@ fu_util_firmware_convert(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_bytes_set_contents(values[1], blob_dst, error))
return FALSE;
str_dst = fu_firmware_to_string(firmware_dst);
g_print("%s", str_dst);
fu_console_print_literal(priv->console, str_dst);
/* success */
return TRUE;
@ -2753,7 +2764,7 @@ fu_util_firmware_patch(FuUtilPrivate *priv, gchar **values, GError **error)
if (!fu_bytes_set_contents(values[0], blob_dst, error))
return FALSE;
str = fu_firmware_to_string(firmware);
g_print("%s", str);
fu_console_print_literal(priv->console, str);
/* success */
return TRUE;
@ -2801,7 +2812,7 @@ fu_util_verify_update(FuUtilPrivate *priv, gchar **values, GError **error)
/* show checksums */
str = fu_device_to_string(dev);
g_print("%s\n", str);
fu_console_print_literal(priv->console, str);
return TRUE;
}
@ -2874,7 +2885,7 @@ fu_util_get_history(FuUtilPrivate *priv, gchar **values, GError **error)
continue;
}
}
fu_util_print_tree(priv->client, root);
fu_util_print_tree(priv->console, priv->client, root);
return TRUE;
}
@ -2987,7 +2998,7 @@ fu_util_get_remotes(FuUtilPrivate *priv, gchar **values, GError **error)
FwupdRemote *remote_tmp = g_ptr_array_index(remotes, i);
g_node_append_data(root, remote_tmp);
}
fu_util_print_tree(priv->client, root);
fu_util_print_tree(priv->console, priv->client, root);
return TRUE;
}
@ -3051,17 +3062,18 @@ fu_util_security(FuUtilPrivate *priv, gchar **values, GError **error)
str = fu_security_attrs_to_json_string(attrs, error);
if (str == NULL)
return FALSE;
g_print("%s\n", str);
fu_console_print_literal(priv->console, str);
return TRUE;
}
g_print("%s \033[1m%s\033[0m\n",
/* TRANSLATORS: this is a string like 'HSI:2-U' */
_("Host Security ID:"),
fu_engine_get_host_security_id(priv->engine));
fu_console_print(priv->console,
"%s \033[1m%s\033[0m",
/* TRANSLATORS: this is a string like 'HSI:2-U' */
_("Host Security ID:"),
fu_engine_get_host_security_id(priv->engine));
str = fu_util_security_attrs_to_string(items, flags);
g_print("%s\n", str);
fu_console_print_literal(priv->console, str);
/* print the "when" */
events = fu_engine_get_host_security_events(priv->engine, 10, error);
@ -3071,7 +3083,7 @@ fu_util_security(FuUtilPrivate *priv, gchar **values, GError **error)
if (events_array->len > 0) {
g_autofree gchar *estr = fu_util_security_events_to_string(events_array, flags);
if (estr != NULL)
g_print("%s\n", estr);
fu_console_print_literal(priv->console, estr);
}
/* print the "also" */
@ -3081,7 +3093,7 @@ fu_util_security(FuUtilPrivate *priv, gchar **values, GError **error)
if (devices->len > 0) {
g_autofree gchar *estr = fu_util_security_issues_to_string(devices);
if (estr != NULL)
g_print("%s\n", estr);
fu_console_print_literal(priv->console, estr);
}
/* success */
@ -3102,20 +3114,23 @@ fu_util_prompt_for_volume(FuUtilPrivate *priv, GError **error)
return NULL;
if (volumes->len == 1) {
volume = g_ptr_array_index(volumes, 0);
/* TRANSLATORS: Volume has been chosen by the user */
g_print("%s: %s\n", _("Selected volume"), fu_volume_get_id(volume));
fu_console_print(priv->console,
"%s: %s",
/* TRANSLATORS: Volume has been chosen by the user */
_("Selected volume"),
fu_volume_get_id(volume));
return g_object_ref(volume);
}
/* TRANSLATORS: get interactive prompt */
g_print("%s\n", _("Choose a volume:"));
fu_console_print_literal(priv->console, _("Choose a volume:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print("0.\t%s\n", _("Cancel"));
fu_console_print(priv->console, "0.\t%s", _("Cancel"));
for (guint i = 0; i < volumes->len; i++) {
volume = g_ptr_array_index(volumes, i);
g_print("%u.\t%s\n", i + 1, fu_volume_get_id(volume));
fu_console_print(priv->console, "%u.\t%s", i + 1, fu_volume_get_id(volume));
}
idx = fu_util_prompt_for_number(volumes->len);
idx = fu_console_input_uint(priv->console, volumes->len);
if (idx == 0) {
g_set_error_literal(error,
FWUPD_ERROR,
@ -3167,7 +3182,7 @@ fu_util_esp_list(FuUtilPrivate *priv, gchar **values, GError **error)
return FALSE;
for (guint i = 0; i < files->len; i++) {
const gchar *fn = g_ptr_array_index(files, i);
g_print("%s\n", fn);
fu_console_print_literal(priv->console, fn);
}
return TRUE;
}
@ -3238,14 +3253,17 @@ fu_util_switch_branch(FuUtilPrivate *priv, gchar **values, GError **error)
/* TRANSLATORS: get interactive prompt, where branch is the
* supplier of the firmware, e.g. "non-free" or "free" */
g_print("%s\n", _("Choose a branch:"));
fu_console_print_literal(priv->console, _("Choose a branch:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print("0.\t%s\n", _("Cancel"));
fu_console_print(priv->console, "0.\t%s", _("Cancel"));
for (guint i = 0; i < branches->len; i++) {
const gchar *branch_tmp = g_ptr_array_index(branches, i);
g_print("%u.\t%s\n", i + 1, fu_util_branch_for_display(branch_tmp));
fu_console_print(priv->console,
"%u.\t%s",
i + 1,
fu_util_branch_for_display(branch_tmp));
}
idx = fu_util_prompt_for_number(branches->len);
idx = fu_console_input_uint(priv->console, branches->len);
if (idx == 0) {
g_set_error_literal(error,
FWUPD_ERROR,
@ -3285,7 +3303,7 @@ fu_util_switch_branch(FuUtilPrivate *priv, gchar **values, GError **error)
}
/* we're switching branch */
if (!fu_util_switch_branch_warning(FWUPD_DEVICE(dev), rel, FALSE, error))
if (!fu_util_switch_branch_warning(priv->console, FWUPD_DEVICE(dev), rel, FALSE, error))
return FALSE;
/* update the console if composite devices are also updated */
@ -3306,7 +3324,7 @@ fu_util_switch_branch(FuUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -3340,7 +3358,7 @@ fu_util_set_bios_setting(FuUtilPrivate *priv, gchar **input, GError **error)
g_strdup_printf(_("Set BIOS setting '%s' using '%s'."),
(const gchar *)key,
(const gchar *)value);
g_print("\n%s\n", msg);
fu_console_print_literal(priv->console, msg);
}
}
priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT;
@ -3350,7 +3368,7 @@ fu_util_set_bios_setting(FuUtilPrivate *priv, gchar **input, GError **error)
return TRUE;
}
return fu_util_prompt_complete(priv->completion_flags, TRUE, error);
return fu_util_prompt_complete(priv->console, priv->completion_flags, TRUE, error);
}
static gboolean
@ -3371,13 +3389,13 @@ fu_util_get_bios_setting(FuUtilPrivate *priv, gchar **values, GError **error)
attrs = fu_context_get_bios_settings(ctx);
items = fu_bios_settings_get_all(attrs);
if (priv->as_json)
return fu_util_get_bios_setting_as_json(values, items, error);
return fu_util_get_bios_setting_as_json(priv->console, values, items, error);
for (guint i = 0; i < items->len; i++) {
FwupdBiosSetting *attr = g_ptr_array_index(items, i);
if (fu_util_bios_setting_matches_args(attr, values)) {
g_autofree gchar *tmp = fu_util_bios_setting_to_string(attr, 0);
g_print("%s\n", tmp);
fu_console_print_literal(priv->console, tmp);
found = TRUE;
}
}
@ -3393,8 +3411,9 @@ fu_util_get_bios_setting(FuUtilPrivate *priv, gchar **values, GError **error)
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_ARGS,
"%s: '%s'",
/* TRANSLATORS: error message */
"Unable to find attribute '%s'",
_("Unable to find attribute"),
values[0]);
return FALSE;
}
@ -3422,9 +3441,9 @@ fu_util_version(FuUtilPrivate *priv, GError **error)
/* dump to the screen in the most appropriate format */
if (priv->as_json)
return fu_util_project_versions_as_json(metadata, error);
return fu_util_project_versions_as_json(priv->console, metadata, error);
str = fu_util_project_versions_to_string(metadata);
g_print("%s", str);
fu_console_print_literal(priv->console, str);
return TRUE;
}
@ -3442,17 +3461,17 @@ fu_util_setup_interactive(FuUtilPrivate *priv, GError **error)
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "using --json");
return FALSE;
}
return fu_util_setup_interactive_console(error);
return fu_console_setup(priv->console, error);
}
static void
fu_util_print_error(FuUtilPrivate *priv, const GError *error)
{
if (priv->as_json) {
fu_util_print_error_as_json(error);
fu_util_print_error_as_json(priv->console, error);
return;
}
g_printerr("%s\n", error->message);
fu_console_print_full(priv->console, FU_CONSOLE_PRINT_FLAG_STDERR, "%s\n", error->message);
}
int
@ -3652,9 +3671,9 @@ main(int argc, char *argv[])
/* create helper object */
priv->main_ctx = g_main_context_new();
priv->loop = g_main_loop_new(priv->main_ctx, FALSE);
priv->progressbar = fu_progressbar_new();
priv->console = fu_console_new();
priv->post_requests = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
fu_progressbar_set_main_context(priv->progressbar, priv->main_ctx);
fu_console_set_main_context(priv->console, priv->main_ctx);
priv->request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
/* used for monitoring and downloading */
@ -4001,7 +4020,7 @@ main(int argc, char *argv[])
FWUPD_FEATURE_FLAG_COMMUNITY_TEXT | FWUPD_FEATURE_FLAG_SHOW_PROBLEMS |
FWUPD_FEATURE_FLAG_REQUESTS);
}
fu_progressbar_set_interactive(priv->progressbar, priv->interactive);
fu_console_set_interactive(priv->console, priv->interactive);
/* get a list of the commands */
priv->context = g_option_context_new(NULL);
@ -4019,23 +4038,24 @@ main(int argc, char *argv[])
g_option_context_add_group(priv->context, fu_debug_get_option_group());
ret = g_option_context_parse(priv->context, &argc, &argv, &error);
if (!ret) {
/* TRANSLATORS: the user didn't read the man page */
g_print("%s: %s\n", _("Failed to parse arguments"), error->message);
fu_console_print(priv->console,
"%s: %s",
/* TRANSLATORS: the user didn't read the man page */
_("Failed to parse arguments"),
error->message);
return EXIT_FAILURE;
}
fu_progress_set_profile(priv->progress, g_getenv("FWUPD_VERBOSE") != NULL);
/* allow disabling SSL strict mode for broken corporate proxies */
if (priv->disable_ssl_strict) {
g_autofree gchar *fmt = NULL;
/* TRANSLATORS: this is a prefix on the console */
fmt = fu_util_term_format(_("WARNING:"), FU_UTIL_TERM_COLOR_RED);
g_printerr("%s %s\n",
fmt,
/* TRANSLATORS: try to help */
_("Ignoring SSL strict checks, "
"to do this automatically in the future "
"export DISABLE_SSL_STRICT in your environment"));
fu_console_print_full(priv->console,
FU_CONSOLE_PRINT_FLAG_WARNING,
"%s\n",
/* TRANSLATORS: try to help */
_("Ignoring SSL strict checks, "
"to do this automatically in the future "
"export DISABLE_SSL_STRICT in your environment"));
(void)g_setenv("DISABLE_SSL_STRICT", "1", TRUE);
}
@ -4112,8 +4132,9 @@ main(int argc, char *argv[])
#endif
fu_util_print_error(priv, error);
if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) {
/* TRANSLATORS: error message explaining command on how to get help */
g_printerr("\n%s\n", _("Use fwupdtool --help for help"));
fu_console_print_literal(priv->console,
/* TRANSLATORS: explain how to get help */
_("Use fwupdtool --help for help"));
} else if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) {
g_debug("%s\n", error->message);
return EXIT_NOTHING_TO_DO;
@ -4121,8 +4142,12 @@ main(int argc, char *argv[])
#ifdef HAVE_GETUID
/* if not root, then notify users on the error path */
if (priv->interactive && (getuid() != 0 || geteuid() != 0)) {
/* TRANSLATORS: we're poking around as a power user */
g_printerr("%s\n", _("NOTE: This program may only work correctly as root"));
fu_console_print_full(priv->console,
FU_CONSOLE_PRINT_FLAG_STDERR |
FU_CONSOLE_PRINT_FLAG_WARNING,
"%s\n",
/* TRANSLATORS: we're poking around as a power user */
_("This program may only work correctly as root"));
}
#endif
return EXIT_FAILURE;
@ -4132,7 +4157,7 @@ main(int argc, char *argv[])
if (fu_progress_get_profile(priv->progress)) {
g_autofree gchar *str = fu_progress_traceback(priv->progress);
if (str != NULL)
g_print("\n%s\n", str);
fu_console_print_literal(priv->console, str);
}
/* success */

View File

@ -62,7 +62,10 @@ fu_util_bios_setting_matches_args(FwupdBiosSetting *setting, gchar **values)
}
gboolean
fu_util_get_bios_setting_as_json(gchar **values, GPtrArray *settings, GError **error)
fu_util_get_bios_setting_as_json(FuConsole *console,
gchar **values,
GPtrArray *settings,
GError **error)
{
g_autoptr(JsonBuilder) builder = json_builder_new();
json_builder_begin_object(builder);
@ -80,7 +83,7 @@ fu_util_get_bios_setting_as_json(gchar **values, GPtrArray *settings, GError **e
}
json_builder_end_array(builder);
json_builder_end_object(builder);
return fu_util_print_builder(builder, error);
return fu_util_print_builder(console, builder, error);
}
gchar *

View File

@ -10,11 +10,16 @@
#include "fwupd-bios-setting-private.h"
#include "fu-console.h"
gchar *
fu_util_bios_setting_to_string(FwupdBiosSetting *setting, guint idt);
gboolean
fu_util_bios_setting_matches_args(FwupdBiosSetting *setting, gchar **values);
gboolean
fu_util_get_bios_setting_as_json(gchar **values, GPtrArray *settings, GError **error);
fu_util_get_bios_setting_as_json(FuConsole *console,
gchar **values,
GPtrArray *settings,
GError **error);
GHashTable *
fu_util_bios_settings_parse_argv(gchar **input, GError **error);

View File

@ -20,11 +20,7 @@
#include <curl/curl.h>
#endif
#ifdef _WIN32
#include <wchar.h>
#include <windows.h>
#endif
#include "fu-console.h"
#include "fu-device-private.h"
#include "fu-security-attr-common.h"
#include "fu-util-common.h"
@ -45,7 +41,7 @@ fu_util_get_systemd_unit(void)
}
gchar *
fu_util_term_format(const gchar *text, FuUtilTermColor fg_color)
fu_console_color_format(const gchar *text, FuConsoleColor fg_color)
{
if (g_getenv("NO_COLOR") != NULL)
return g_strdup(text);
@ -94,79 +90,15 @@ fu_util_using_correct_daemon(GError **error)
return TRUE;
}
void
fu_util_print_data(const gchar *title, const gchar *msg)
{
gsize title_len;
g_auto(GStrv) lines = NULL;
if (msg == NULL)
return;
g_print("%s:", title);
/* pad */
title_len = fu_strwidth(title) + 1;
lines = g_strsplit(msg, "\n", -1);
for (guint j = 0; lines[j] != NULL; j++) {
for (gsize i = title_len; i < 25; i++)
g_print(" ");
g_print("%s\n", lines[j]);
title_len = 0;
}
}
guint
fu_util_prompt_for_number(guint maxnum)
{
gint retval;
guint answer = 0;
do {
char buffer[64];
/* swallow the \n at end of line too */
if (!fgets(buffer, sizeof(buffer), stdin))
break;
if (strlen(buffer) == sizeof(buffer) - 1)
continue;
/* get a number */
retval = sscanf(buffer, "%u", &answer);
/* positive */
if (retval == 1 && answer <= maxnum)
break;
/* TRANSLATORS: the user isn't reading the question */
g_print(_("Please enter a number from 0 to %u: "), maxnum);
} while (TRUE);
return answer;
}
gboolean
fu_util_prompt_for_boolean(gboolean def)
{
do {
char buffer[4];
if (!fgets(buffer, sizeof(buffer), stdin))
continue;
if (strlen(buffer) == sizeof(buffer) - 1)
continue;
if (g_strcmp0(buffer, "\n") == 0)
return def;
buffer[0] = g_ascii_toupper(buffer[0]);
if (g_strcmp0(buffer, "Y\n") == 0)
return TRUE;
if (g_strcmp0(buffer, "N\n") == 0)
return FALSE;
} while (TRUE);
return FALSE;
}
typedef struct {
FwupdClient *client;
FuConsole *console;
} FuUtilPrintTreeHelper;
static gboolean
fu_util_traverse_tree(GNode *n, gpointer data)
{
FwupdClient *client = FWUPD_CLIENT(data);
FuUtilPrintTreeHelper *helper = (FuUtilPrintTreeHelper *)data;
guint idx = g_node_depth(n) - 1;
g_autofree gchar *tmp = NULL;
g_auto(GStrv) split = NULL;
@ -174,7 +106,7 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* get split lines */
if (FWUPD_IS_DEVICE(n->data)) {
FwupdDevice *dev = FWUPD_DEVICE(n->data);
tmp = fu_util_device_to_string(client, dev, idx);
tmp = fu_util_device_to_string(helper->client, dev, idx);
} else if (FWUPD_IS_REMOTE(n->data)) {
FwupdRemote *remote = FWUPD_REMOTE(n->data);
tmp = fu_util_remote_to_string(remote, idx);
@ -186,9 +118,10 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* root node */
if (n->data == NULL && g_getenv("FWUPD_VERBOSE") == NULL) {
g_autofree gchar *str = g_strdup_printf("%s %s",
fwupd_client_get_host_vendor(client),
fwupd_client_get_host_product(client));
g_autofree gchar *str =
g_strdup_printf("%s %s",
fwupd_client_get_host_vendor(helper->client),
fwupd_client_get_host_product(helper->client));
g_print("%s\n\n", str);
return FALSE;
}
@ -227,22 +160,23 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* empty line */
if (split[i][0] == '\0') {
g_print("%s\n", str->str);
fu_console_print_literal(helper->console, str->str);
continue;
}
/* dump to the console */
g_string_append(str, split[i] + (idx * 2));
g_print("%s\n", str->str);
fu_console_print_literal(helper->console, str->str);
}
return FALSE;
}
void
fu_util_print_tree(FwupdClient *client, GNode *n)
fu_util_print_tree(FuConsole *console, FwupdClient *client, GNode *n)
{
g_node_traverse(n, G_PRE_ORDER, G_TRAVERSE_ALL, -1, fu_util_traverse_tree, client);
FuUtilPrintTreeHelper helper = {.client = client, .console = console};
g_node_traverse(n, G_PRE_ORDER, G_TRAVERSE_ALL, -1, fu_util_traverse_tree, &helper);
}
static gboolean
@ -420,7 +354,8 @@ fu_util_get_release_description_with_fallback(FwupdRelease *rel)
}
gboolean
fu_util_prompt_warning(FwupdDevice *device,
fu_util_prompt_warning(FuConsole *console,
FwupdDevice *device,
FwupdRelease *release,
const gchar *machine,
GError **error)
@ -507,13 +442,10 @@ fu_util_prompt_warning(FwupdDevice *device,
}
}
}
fu_util_warning_box(title->str, str->str, 80);
fu_console_box(console, title->str, str->str, 80);
/* ask for confirmation */
g_print("\n%s [Y|n]: ",
/* TRANSLATORS: prompt to apply the update */
_("Perform operation?"));
if (!fu_util_prompt_for_boolean(TRUE)) {
/* TRANSLATORS: prompt to apply the update */
if (!fu_console_input_bool(console, TRUE, "%s", _("Perform operation?"))) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
@ -526,28 +458,31 @@ fu_util_prompt_warning(FwupdDevice *device,
}
gboolean
fu_util_prompt_complete(FwupdDeviceFlags flags, gboolean prompt, GError **error)
fu_util_prompt_complete(FuConsole *console, FwupdDeviceFlags flags, gboolean prompt, GError **error)
{
if (flags & FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) {
if (prompt) {
g_print("\n%s %s [y|N]: ",
/* TRANSLATORS: explain why we want to shutdown */
_("An update requires the system to shutdown to complete."),
/* TRANSLATORS: shutdown to apply the update */
_("Shutdown now?"));
if (!fu_util_prompt_for_boolean(FALSE))
if (!fu_console_input_bool(console,
FALSE,
"%s %s",
/* TRANSLATORS: explain why */
_("An update requires the system to shutdown "
"to complete."),
/* TRANSLATORS: shutdown to apply the update */
_("Shutdown now?")))
return TRUE;
}
return fu_util_update_shutdown(error);
}
if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) {
if (prompt) {
g_print("\n%s %s [y|N]: ",
/* TRANSLATORS: explain why we want to reboot */
_("An update requires a reboot to complete."),
/* TRANSLATORS: reboot to apply the update */
_("Restart now?"));
if (!fu_util_prompt_for_boolean(FALSE))
if (!fu_console_input_bool(console,
FALSE,
"%s %s",
/* TRANSLATORS: explain why we want to reboot */
_("An update requires a reboot to complete."),
/* TRANSLATORS: reboot to apply the update */
_("Restart now?")))
return TRUE;
}
return fu_util_update_reboot(error);
@ -849,116 +784,6 @@ fu_util_release_get_name(FwupdRelease *release)
return g_strdup_printf(_("%s Update"), name);
}
static GPtrArray *
fu_util_strsplit_words(const gchar *text, guint line_len)
{
g_auto(GStrv) tokens = NULL;
g_autoptr(GPtrArray) lines = g_ptr_array_new_with_free_func(g_free);
g_autoptr(GString) curline = g_string_new(NULL);
/* sanity check */
if (text == NULL || text[0] == '\0')
return NULL;
if (line_len == 0)
return NULL;
/* tokenize the string */
tokens = g_strsplit(text, " ", -1);
for (guint i = 0; tokens[i] != NULL; i++) {
/* current line plus new token is okay */
if (curline->len + fu_strwidth(tokens[i]) < line_len) {
g_string_append_printf(curline, "%s ", tokens[i]);
continue;
}
/* too long, so remove space, add newline and dump */
if (curline->len > 0)
g_string_truncate(curline, curline->len - 1);
g_ptr_array_add(lines, g_strdup(curline->str));
g_string_truncate(curline, 0);
g_string_append_printf(curline, "%s ", tokens[i]);
}
/* any incomplete line? */
if (curline->len > 0) {
g_string_truncate(curline, curline->len - 1);
g_ptr_array_add(lines, g_strdup(curline->str));
}
return g_steal_pointer(&lines);
}
static void
fu_util_warning_box_line(const gchar *start,
const gchar *text,
const gchar *end,
const gchar *padding,
guint width)
{
guint offset = 0;
if (start != NULL) {
offset += fu_strwidth(start);
g_print("%s", start);
}
if (text != NULL) {
offset += fu_strwidth(text);
g_print("%s", text);
}
if (end != NULL)
offset += fu_strwidth(end);
for (guint i = offset; i < width; i++)
g_print("%s", padding);
if (end != NULL)
g_print("%s\n", end);
}
void
fu_util_warning_box(const gchar *title, const gchar *body, guint width)
{
/* nothing to do */
if (title == NULL && body == NULL)
return;
/* header */
fu_util_warning_box_line("", NULL, "", "", width);
/* optional title */
if (title != NULL) {
g_autoptr(GPtrArray) lines = fu_util_strsplit_words(title, width - 4);
for (guint j = 0; j < lines->len; j++) {
const gchar *line = g_ptr_array_index(lines, j);
fu_util_warning_box_line("", line, "", " ", width);
}
}
/* join */
if (title != NULL && body != NULL)
fu_util_warning_box_line("", NULL, "", "", width);
/* optional body */
if (body != NULL) {
gboolean has_nonempty = FALSE;
g_auto(GStrv) split = g_strsplit(body, "\n", -1);
for (guint i = 0; split[i] != NULL; i++) {
g_autoptr(GPtrArray) lines = fu_util_strsplit_words(split[i], width - 4);
if (lines == NULL) {
if (has_nonempty) {
fu_util_warning_box_line("", NULL, "", " ", width);
has_nonempty = FALSE;
}
continue;
}
for (guint j = 0; j < lines->len; j++) {
const gchar *line = g_ptr_array_index(lines, j);
fu_util_warning_box_line("", line, "", " ", width);
}
has_nonempty = TRUE;
}
}
/* footer */
fu_util_warning_box_line("", NULL, "", "", width);
}
gboolean
fu_util_parse_filter_flags(const gchar *filter,
FwupdDeviceFlags *include,
@ -1561,7 +1386,7 @@ fu_util_device_to_string(FwupdClient *client, FwupdDevice *dev, guint idt)
tmp = fwupd_device_get_update_message(dev);
if (tmp != NULL) {
g_autofree gchar *color =
fu_util_term_format(tmp, FU_UTIL_TERM_COLOR_BLUE);
fu_console_color_format(tmp, FU_CONSOLE_COLOR_BLUE);
fu_string_append(
str,
idt + 1,
@ -1596,7 +1421,8 @@ fu_util_device_to_string(FwupdClient *client, FwupdDevice *dev, guint idt)
if (fwupd_device_get_problems(dev) == FWUPD_DEVICE_PROBLEM_NONE) {
tmp = fwupd_device_get_update_error(dev);
if (tmp != NULL) {
g_autofree gchar *color = fu_util_term_format(tmp, FU_UTIL_TERM_COLOR_RED);
g_autofree gchar *color =
fu_console_color_format(tmp, FU_CONSOLE_COLOR_RED);
/* TRANSLATORS: error message from last update attempt */
fu_string_append(str, idt + 1, _("Update Error"), color);
}
@ -1615,7 +1441,7 @@ fu_util_device_to_string(FwupdClient *client, FwupdDevice *dev, guint idt)
if (desc == NULL)
continue;
bullet = g_strdup_printf("• %s", desc);
color = fu_util_term_format(bullet, FU_UTIL_TERM_COLOR_RED);
color = fu_console_color_format(bullet, FU_CONSOLE_COLOR_RED);
fu_string_append(str, idt + 1, tmp, color);
tmp = NULL;
}
@ -1780,12 +1606,12 @@ fu_util_plugin_flag_to_cli_text(FwupdPluginFlags plugin_flag)
case FWUPD_PLUGIN_FLAG_MODULAR:
case FWUPD_PLUGIN_FLAG_MEASURE_SYSTEM_INTEGRITY:
case FWUPD_PLUGIN_FLAG_SECURE_CONFIG:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_GREEN);
return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_CONSOLE_COLOR_GREEN);
case FWUPD_PLUGIN_FLAG_DISABLED:
case FWUPD_PLUGIN_FLAG_NO_HARDWARE:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_BLACK);
return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_CONSOLE_COLOR_BLACK);
case FWUPD_PLUGIN_FLAG_LEGACY_BIOS:
case FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED:
case FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED:
@ -1793,8 +1619,8 @@ fu_util_plugin_flag_to_cli_text(FwupdPluginFlags plugin_flag)
case FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED:
case FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND:
case FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_RED);
return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_CONSOLE_COLOR_RED);
default:
break;
}
@ -2334,16 +2160,16 @@ fu_security_attr_append_str(FwupdSecurityAttr *attr,
for (guint i = fu_strwidth(name); i < 30; i++)
g_string_append(str, " ");
if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) {
g_autofree gchar *fmt = fu_util_term_format(fu_security_attr_get_result(attr),
FU_UTIL_TERM_COLOR_YELLOW);
g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
FU_CONSOLE_COLOR_YELLOW);
g_string_append(str, fmt);
} else if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) {
g_autofree gchar *fmt = fu_util_term_format(fu_security_attr_get_result(attr),
FU_UTIL_TERM_COLOR_GREEN);
g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
FU_CONSOLE_COLOR_GREEN);
g_string_append(str, fmt);
} else {
g_autofree gchar *fmt =
fu_util_term_format(fu_security_attr_get_result(attr), FU_UTIL_TERM_COLOR_RED);
g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
FU_CONSOLE_COLOR_RED);
g_string_append(str, fmt);
}
if ((flags & FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS) > 0 &&
@ -2545,9 +2371,9 @@ fu_util_security_events_to_string(GPtrArray *events, FuSecurityAttrToStringFlags
if (eventstr == NULL)
continue;
if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) {
check = fu_util_term_format("", FU_UTIL_TERM_COLOR_GREEN);
check = fu_console_color_format("", FU_CONSOLE_COLOR_GREEN);
} else {
check = fu_util_term_format("", FU_UTIL_TERM_COLOR_RED);
check = fu_console_color_format("", FU_CONSOLE_COLOR_RED);
}
if (str->len == 0) {
/* TRANSLATORS: title for host security events */
@ -2820,7 +2646,8 @@ fu_util_device_order_sort_cb(gconstpointer a, gconstpointer b)
}
gboolean
fu_util_switch_branch_warning(FwupdDevice *dev,
fu_util_switch_branch_warning(FuConsole *console,
FwupdDevice *dev,
FwupdRelease *rel,
gboolean assume_yes,
GError **error)
@ -2863,13 +2690,14 @@ fu_util_switch_branch_warning(FwupdDevice *dev,
title = g_strdup_printf(_("Switch branch from %s to %s?"),
fu_util_branch_for_display(fwupd_device_get_branch(dev)),
fu_util_branch_for_display(fwupd_release_get_branch(rel)));
fu_util_warning_box(title, desc_full->str, 80);
fu_console_box(console, title, desc_full->str, 80);
if (!assume_yes) {
/* ask for permission */
g_print("\n%s [y|N]: ",
/* TRANSLATORS: should the branch be changed */
_("Do you understand the consequences of changing the firmware branch?"));
if (!fu_util_prompt_for_boolean(FALSE)) {
if (!fu_console_input_bool(console,
FALSE,
"%s",
/* TRANSLATORS: should the branch be changed */
_("Do you understand the consequences "
"of changing the firmware branch?"))) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
@ -2881,7 +2709,7 @@ fu_util_switch_branch_warning(FwupdDevice *dev,
}
gboolean
fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error)
fu_util_prompt_warning_fde(FuConsole *console, FwupdDevice *dev, GError **error)
{
const gchar *url = "https://github.com/fwupd/fwupd/wiki/Full-Disk-Encryption-Detected";
g_autoptr(GString) str = g_string_new(NULL);
@ -2904,13 +2732,10 @@ fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error)
_("See %s for more details."),
url);
/* TRANSLATORS: title text, shown as a warning */
fu_util_warning_box(_("Full Disk Encryption Detected"), str->str, 80);
fu_console_box(console, _("Full Disk Encryption Detected"), str->str, 80);
/* ask for confirmation */
g_print("\n%s [Y|n]: ",
/* TRANSLATORS: prompt to apply the update */
_("Perform operation?"));
if (!fu_util_prompt_for_boolean(TRUE)) {
/* TRANSLATORS: prompt to apply the update */
if (!fu_console_input_bool(console, TRUE, "%s", _("Perform operation?"))) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
@ -2921,19 +2746,17 @@ fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error)
}
void
fu_util_show_unsupported_warn(void)
fu_util_show_unsupported_warning(FuConsole *console)
{
#ifndef SUPPORTED_BUILD
g_autofree gchar *fmt = NULL;
if (g_getenv("FWUPD_SUPPORTED") != NULL)
return;
/* TRANSLATORS: this is a prefix on the console */
fmt = fu_util_term_format(_("WARNING:"), FU_UTIL_TERM_COLOR_YELLOW);
g_printerr("%s %s\n",
fmt,
/* TRANSLATORS: unsupported build of the package */
_("This package has not been validated, it may not work properly."));
fu_console_print_full(console,
FU_CONSOLE_PRINT_FLAG_WARNING | FU_CONSOLE_PRINT_FLAG_STDERR,
"%s\n",
/* TRANSLATORS: unsupported build of the package */
_("This package has not been validated, it may not work properly."));
#endif
}
@ -2954,67 +2777,7 @@ fu_util_is_url(const gchar *perhaps_url)
}
gboolean
fu_util_setup_interactive_console(GError **error)
{
#ifdef _WIN32
HANDLE hOut;
DWORD dwMode = 0;
/* enable VT sequences */
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to get stdout [%u]",
(guint)GetLastError());
return FALSE;
}
if (!GetConsoleMode(hOut, &dwMode)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to get mode [%u]",
(guint)GetLastError());
return FALSE;
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set mode [%u]",
(guint)GetLastError());
return FALSE;
}
if (!SetConsoleOutputCP(CP_UTF8)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set output UTF-8 [%u]",
(guint)GetLastError());
return FALSE;
}
if (!SetConsoleCP(CP_UTF8)) {
g_set_error(error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"failed to set UTF-8 [%u]",
(guint)GetLastError());
return FALSE;
}
#else
if (isatty(fileno(stdout)) == 0) {
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "not a TTY");
return FALSE;
}
#endif
/* success */
return TRUE;
}
gboolean
fu_util_print_builder(JsonBuilder *builder, GError **error)
fu_util_print_builder(FuConsole *console, JsonBuilder *builder, GError **error)
{
g_autofree gchar *data = NULL;
g_autoptr(JsonGenerator) json_generator = NULL;
@ -3035,12 +2798,12 @@ fu_util_print_builder(JsonBuilder *builder, GError **error)
}
/* just print */
g_print("%s\n", data);
fu_console_print_literal(console, data);
return TRUE;
}
void
fu_util_print_error_as_json(const GError *error)
fu_util_print_error_as_json(FuConsole *console, const GError *error)
{
g_autoptr(JsonBuilder) builder = json_builder_new();
json_builder_begin_object(builder);
@ -3054,7 +2817,7 @@ fu_util_print_error_as_json(const GError *error)
json_builder_add_string_value(builder, error->message);
json_builder_end_object(builder);
json_builder_end_object(builder);
fu_util_print_builder(builder, NULL);
fu_util_print_builder(console, builder, NULL);
}
typedef enum {
@ -3104,7 +2867,7 @@ fu_util_print_version_key_valid(const gchar *key)
}
gboolean
fu_util_project_versions_as_json(GHashTable *metadata, GError **error)
fu_util_project_versions_as_json(FuConsole *console, GHashTable *metadata, GError **error)
{
GHashTableIter iter;
const gchar *key;
@ -3138,7 +2901,7 @@ fu_util_project_versions_as_json(GHashTable *metadata, GError **error)
}
json_builder_end_array(builder);
json_builder_end_object(builder);
return fu_util_print_builder(builder, error);
return fu_util_print_builder(console, builder, error);
}
gchar *

View File

@ -13,6 +13,8 @@
#include "fwupd-bios-setting-private.h"
#include "fwupd-security-attr-private.h"
#include "fu-console.h"
/* this is only valid for tools */
#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST + 1)
@ -33,44 +35,26 @@ typedef enum {
FU_SECURITY_ATTR_TO_STRING_FLAG_LAST
} FuSecurityAttrToStringFlags;
typedef enum {
FU_UTIL_TERM_COLOR_BLACK = 30,
FU_UTIL_TERM_COLOR_RED = 31,
FU_UTIL_TERM_COLOR_GREEN = 32,
FU_UTIL_TERM_COLOR_YELLOW = 33,
FU_UTIL_TERM_COLOR_BLUE = 34,
FU_UTIL_TERM_COLOR_MAGENTA = 35,
FU_UTIL_TERM_COLOR_CYAN = 36,
FU_UTIL_TERM_COLOR_WHITE = 37,
} FuUtilTermColor;
void
fu_util_print_data(const gchar *title, const gchar *msg);
gchar *
fu_util_term_format(const gchar *text, FuUtilTermColor fg_color);
guint
fu_util_prompt_for_number(guint maxnum);
gboolean
fu_util_prompt_for_boolean(gboolean def);
void
fu_util_print_tree(FwupdClient *client, GNode *n);
fu_util_print_tree(FuConsole *console, FwupdClient *client, GNode *n);
gboolean
fu_util_is_interesting_device(FwupdDevice *dev);
gchar *
fu_util_get_user_cache_path(const gchar *fn);
void
fu_util_warning_box(const gchar *title, const gchar *body, guint width);
gboolean
fu_util_prompt_warning(FwupdDevice *device,
fu_util_prompt_warning(FuConsole *console,
FwupdDevice *device,
FwupdRelease *release,
const gchar *machine,
GError **error);
gboolean
fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error);
fu_util_prompt_warning_fde(FuConsole *console, FwupdDevice *dev, GError **error);
gboolean
fu_util_prompt_complete(FwupdDeviceFlags flags, gboolean prompt, GError **error);
fu_util_prompt_complete(FuConsole *console,
FwupdDeviceFlags flags,
gboolean prompt,
GError **error);
gboolean
fu_util_update_reboot(GError **error);
@ -145,21 +129,20 @@ gint
fu_util_device_order_sort_cb(gconstpointer a, gconstpointer b);
gboolean
fu_util_switch_branch_warning(FwupdDevice *dev,
fu_util_switch_branch_warning(FuConsole *console,
FwupdDevice *dev,
FwupdRelease *rel,
gboolean assume_yes,
GError **error);
void
fu_util_show_unsupported_warn(void);
fu_util_show_unsupported_warning(FuConsole *console);
gboolean
fu_util_is_url(const gchar *perhaps_url);
gboolean
fu_util_setup_interactive_console(GError **error);
gboolean
fu_util_print_builder(JsonBuilder *builder, GError **error);
fu_util_print_builder(FuConsole *console, JsonBuilder *builder, GError **error);
void
fu_util_print_error_as_json(const GError *error);
fu_util_print_error_as_json(FuConsole *console, const GError *error);
gchar *
fu_util_project_versions_to_string(GHashTable *metadata);
gboolean
fu_util_project_versions_as_json(GHashTable *metadata, GError **error);
fu_util_project_versions_as_json(FuConsole *console, GHashTable *metadata, GError **error);

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@ endif
fwupdutil = library(
'fwupdutil',
sources: [
'fu-progressbar.c',
'fu-console.c',
'fu-security-attr-common.c',
'fu-util-bios-setting.c',
'fu-util-common.c',