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

View File

@ -62,7 +62,10 @@ fu_util_bios_setting_matches_args(FwupdBiosSetting *setting, gchar **values)
} }
gboolean 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(); g_autoptr(JsonBuilder) builder = json_builder_new();
json_builder_begin_object(builder); 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_array(builder);
json_builder_end_object(builder); json_builder_end_object(builder);
return fu_util_print_builder(builder, error); return fu_util_print_builder(console, builder, error);
} }
gchar * gchar *

View File

@ -10,11 +10,16 @@
#include "fwupd-bios-setting-private.h" #include "fwupd-bios-setting-private.h"
#include "fu-console.h"
gchar * gchar *
fu_util_bios_setting_to_string(FwupdBiosSetting *setting, guint idt); fu_util_bios_setting_to_string(FwupdBiosSetting *setting, guint idt);
gboolean gboolean
fu_util_bios_setting_matches_args(FwupdBiosSetting *setting, gchar **values); fu_util_bios_setting_matches_args(FwupdBiosSetting *setting, gchar **values);
gboolean 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 * GHashTable *
fu_util_bios_settings_parse_argv(gchar **input, GError **error); fu_util_bios_settings_parse_argv(gchar **input, GError **error);

View File

@ -20,11 +20,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#endif #endif
#ifdef _WIN32 #include "fu-console.h"
#include <wchar.h>
#include <windows.h>
#endif
#include "fu-device-private.h" #include "fu-device-private.h"
#include "fu-security-attr-common.h" #include "fu-security-attr-common.h"
#include "fu-util-common.h" #include "fu-util-common.h"
@ -45,7 +41,7 @@ fu_util_get_systemd_unit(void)
} }
gchar * 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) if (g_getenv("NO_COLOR") != NULL)
return g_strdup(text); return g_strdup(text);
@ -94,79 +90,15 @@ fu_util_using_correct_daemon(GError **error)
return TRUE; return TRUE;
} }
void typedef struct {
fu_util_print_data(const gchar *title, const gchar *msg) FwupdClient *client;
{ FuConsole *console;
gsize title_len; } FuUtilPrintTreeHelper;
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;
}
static gboolean static gboolean
fu_util_traverse_tree(GNode *n, gpointer data) fu_util_traverse_tree(GNode *n, gpointer data)
{ {
FwupdClient *client = FWUPD_CLIENT(data); FuUtilPrintTreeHelper *helper = (FuUtilPrintTreeHelper *)data;
guint idx = g_node_depth(n) - 1; guint idx = g_node_depth(n) - 1;
g_autofree gchar *tmp = NULL; g_autofree gchar *tmp = NULL;
g_auto(GStrv) split = NULL; g_auto(GStrv) split = NULL;
@ -174,7 +106,7 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* get split lines */ /* get split lines */
if (FWUPD_IS_DEVICE(n->data)) { if (FWUPD_IS_DEVICE(n->data)) {
FwupdDevice *dev = FWUPD_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)) { } else if (FWUPD_IS_REMOTE(n->data)) {
FwupdRemote *remote = FWUPD_REMOTE(n->data); FwupdRemote *remote = FWUPD_REMOTE(n->data);
tmp = fu_util_remote_to_string(remote, idx); tmp = fu_util_remote_to_string(remote, idx);
@ -186,9 +118,10 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* root node */ /* root node */
if (n->data == NULL && g_getenv("FWUPD_VERBOSE") == NULL) { if (n->data == NULL && g_getenv("FWUPD_VERBOSE") == NULL) {
g_autofree gchar *str = g_strdup_printf("%s %s", g_autofree gchar *str =
fwupd_client_get_host_vendor(client), g_strdup_printf("%s %s",
fwupd_client_get_host_product(client)); fwupd_client_get_host_vendor(helper->client),
fwupd_client_get_host_product(helper->client));
g_print("%s\n\n", str); g_print("%s\n\n", str);
return FALSE; return FALSE;
} }
@ -227,22 +160,23 @@ fu_util_traverse_tree(GNode *n, gpointer data)
/* empty line */ /* empty line */
if (split[i][0] == '\0') { if (split[i][0] == '\0') {
g_print("%s\n", str->str); fu_console_print_literal(helper->console, str->str);
continue; continue;
} }
/* dump to the console */ /* dump to the console */
g_string_append(str, split[i] + (idx * 2)); g_string_append(str, split[i] + (idx * 2));
g_print("%s\n", str->str); fu_console_print_literal(helper->console, str->str);
} }
return FALSE; return FALSE;
} }
void 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 static gboolean
@ -420,7 +354,8 @@ fu_util_get_release_description_with_fallback(FwupdRelease *rel)
} }
gboolean gboolean
fu_util_prompt_warning(FwupdDevice *device, fu_util_prompt_warning(FuConsole *console,
FwupdDevice *device,
FwupdRelease *release, FwupdRelease *release,
const gchar *machine, const gchar *machine,
GError **error) 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 */ /* TRANSLATORS: prompt to apply the update */
g_print("\n%s [Y|n]: ", if (!fu_console_input_bool(console, TRUE, "%s", _("Perform operation?"))) {
/* TRANSLATORS: prompt to apply the update */
_("Perform operation?"));
if (!fu_util_prompt_for_boolean(TRUE)) {
g_set_error_literal(error, g_set_error_literal(error,
FWUPD_ERROR, FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO, FWUPD_ERROR_NOTHING_TO_DO,
@ -526,28 +458,31 @@ fu_util_prompt_warning(FwupdDevice *device,
} }
gboolean 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 (flags & FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) {
if (prompt) { if (prompt) {
g_print("\n%s %s [y|N]: ", if (!fu_console_input_bool(console,
/* TRANSLATORS: explain why we want to shutdown */ FALSE,
_("An update requires the system to shutdown to complete."), "%s %s",
/* TRANSLATORS: shutdown to apply the update */ /* TRANSLATORS: explain why */
_("Shutdown now?")); _("An update requires the system to shutdown "
if (!fu_util_prompt_for_boolean(FALSE)) "to complete."),
/* TRANSLATORS: shutdown to apply the update */
_("Shutdown now?")))
return TRUE; return TRUE;
} }
return fu_util_update_shutdown(error); return fu_util_update_shutdown(error);
} }
if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) { if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) {
if (prompt) { if (prompt) {
g_print("\n%s %s [y|N]: ", if (!fu_console_input_bool(console,
/* TRANSLATORS: explain why we want to reboot */ FALSE,
_("An update requires a reboot to complete."), "%s %s",
/* TRANSLATORS: reboot to apply the update */ /* TRANSLATORS: explain why we want to reboot */
_("Restart now?")); _("An update requires a reboot to complete."),
if (!fu_util_prompt_for_boolean(FALSE)) /* TRANSLATORS: reboot to apply the update */
_("Restart now?")))
return TRUE; return TRUE;
} }
return fu_util_update_reboot(error); return fu_util_update_reboot(error);
@ -849,116 +784,6 @@ fu_util_release_get_name(FwupdRelease *release)
return g_strdup_printf(_("%s Update"), name); 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 gboolean
fu_util_parse_filter_flags(const gchar *filter, fu_util_parse_filter_flags(const gchar *filter,
FwupdDeviceFlags *include, FwupdDeviceFlags *include,
@ -1561,7 +1386,7 @@ fu_util_device_to_string(FwupdClient *client, FwupdDevice *dev, guint idt)
tmp = fwupd_device_get_update_message(dev); tmp = fwupd_device_get_update_message(dev);
if (tmp != NULL) { if (tmp != NULL) {
g_autofree gchar *color = 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( fu_string_append(
str, str,
idt + 1, 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) { if (fwupd_device_get_problems(dev) == FWUPD_DEVICE_PROBLEM_NONE) {
tmp = fwupd_device_get_update_error(dev); tmp = fwupd_device_get_update_error(dev);
if (tmp != NULL) { 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 */ /* TRANSLATORS: error message from last update attempt */
fu_string_append(str, idt + 1, _("Update Error"), color); 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) if (desc == NULL)
continue; continue;
bullet = g_strdup_printf("• %s", desc); 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); fu_string_append(str, idt + 1, tmp, color);
tmp = NULL; 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_MODULAR:
case FWUPD_PLUGIN_FLAG_MEASURE_SYSTEM_INTEGRITY: case FWUPD_PLUGIN_FLAG_MEASURE_SYSTEM_INTEGRITY:
case FWUPD_PLUGIN_FLAG_SECURE_CONFIG: case FWUPD_PLUGIN_FLAG_SECURE_CONFIG:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag), return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_GREEN); FU_CONSOLE_COLOR_GREEN);
case FWUPD_PLUGIN_FLAG_DISABLED: case FWUPD_PLUGIN_FLAG_DISABLED:
case FWUPD_PLUGIN_FLAG_NO_HARDWARE: case FWUPD_PLUGIN_FLAG_NO_HARDWARE:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag), return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_BLACK); FU_CONSOLE_COLOR_BLACK);
case FWUPD_PLUGIN_FLAG_LEGACY_BIOS: case FWUPD_PLUGIN_FLAG_LEGACY_BIOS:
case FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED: case FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED:
case FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED: 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_EFIVAR_NOT_MOUNTED:
case FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND: case FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND:
case FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD: case FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD:
return fu_util_term_format(fu_util_plugin_flag_to_string(plugin_flag), return fu_console_color_format(fu_util_plugin_flag_to_string(plugin_flag),
FU_UTIL_TERM_COLOR_RED); FU_CONSOLE_COLOR_RED);
default: default:
break; break;
} }
@ -2334,16 +2160,16 @@ fu_security_attr_append_str(FwupdSecurityAttr *attr,
for (guint i = fu_strwidth(name); i < 30; i++) for (guint i = fu_strwidth(name); i < 30; i++)
g_string_append(str, " "); g_string_append(str, " ");
if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { 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), g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
FU_UTIL_TERM_COLOR_YELLOW); FU_CONSOLE_COLOR_YELLOW);
g_string_append(str, fmt); g_string_append(str, fmt);
} else if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { } 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), g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
FU_UTIL_TERM_COLOR_GREEN); FU_CONSOLE_COLOR_GREEN);
g_string_append(str, fmt); g_string_append(str, fmt);
} else { } else {
g_autofree gchar *fmt = g_autofree gchar *fmt = fu_console_color_format(fu_security_attr_get_result(attr),
fu_util_term_format(fu_security_attr_get_result(attr), FU_UTIL_TERM_COLOR_RED); FU_CONSOLE_COLOR_RED);
g_string_append(str, fmt); g_string_append(str, fmt);
} }
if ((flags & FU_SECURITY_ATTR_TO_STRING_FLAG_SHOW_URLS) > 0 && 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) if (eventstr == NULL)
continue; continue;
if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { 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 { } else {
check = fu_util_term_format("", FU_UTIL_TERM_COLOR_RED); check = fu_console_color_format("", FU_CONSOLE_COLOR_RED);
} }
if (str->len == 0) { if (str->len == 0) {
/* TRANSLATORS: title for host security events */ /* TRANSLATORS: title for host security events */
@ -2820,7 +2646,8 @@ fu_util_device_order_sort_cb(gconstpointer a, gconstpointer b)
} }
gboolean gboolean
fu_util_switch_branch_warning(FwupdDevice *dev, fu_util_switch_branch_warning(FuConsole *console,
FwupdDevice *dev,
FwupdRelease *rel, FwupdRelease *rel,
gboolean assume_yes, gboolean assume_yes,
GError **error) GError **error)
@ -2863,13 +2690,14 @@ fu_util_switch_branch_warning(FwupdDevice *dev,
title = g_strdup_printf(_("Switch branch from %s to %s?"), 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_device_get_branch(dev)),
fu_util_branch_for_display(fwupd_release_get_branch(rel))); 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) { if (!assume_yes) {
/* ask for permission */ if (!fu_console_input_bool(console,
g_print("\n%s [y|N]: ", FALSE,
/* TRANSLATORS: should the branch be changed */ "%s",
_("Do you understand the consequences of changing the firmware branch?")); /* TRANSLATORS: should the branch be changed */
if (!fu_util_prompt_for_boolean(FALSE)) { _("Do you understand the consequences "
"of changing the firmware branch?"))) {
g_set_error_literal(error, g_set_error_literal(error,
FWUPD_ERROR, FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO, FWUPD_ERROR_NOTHING_TO_DO,
@ -2881,7 +2709,7 @@ fu_util_switch_branch_warning(FwupdDevice *dev,
} }
gboolean 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"; const gchar *url = "https://github.com/fwupd/fwupd/wiki/Full-Disk-Encryption-Detected";
g_autoptr(GString) str = g_string_new(NULL); 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."), _("See %s for more details."),
url); url);
/* TRANSLATORS: title text, shown as a warning */ /* 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 */ /* TRANSLATORS: prompt to apply the update */
g_print("\n%s [Y|n]: ", if (!fu_console_input_bool(console, TRUE, "%s", _("Perform operation?"))) {
/* TRANSLATORS: prompt to apply the update */
_("Perform operation?"));
if (!fu_util_prompt_for_boolean(TRUE)) {
g_set_error_literal(error, g_set_error_literal(error,
FWUPD_ERROR, FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO, FWUPD_ERROR_NOTHING_TO_DO,
@ -2921,19 +2746,17 @@ fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error)
} }
void void
fu_util_show_unsupported_warn(void) fu_util_show_unsupported_warning(FuConsole *console)
{ {
#ifndef SUPPORTED_BUILD #ifndef SUPPORTED_BUILD
g_autofree gchar *fmt = NULL;
if (g_getenv("FWUPD_SUPPORTED") != NULL) if (g_getenv("FWUPD_SUPPORTED") != NULL)
return; return;
/* TRANSLATORS: this is a prefix on the console */ /* TRANSLATORS: this is a prefix on the console */
fmt = fu_util_term_format(_("WARNING:"), FU_UTIL_TERM_COLOR_YELLOW); fu_console_print_full(console,
g_printerr("%s %s\n", FU_CONSOLE_PRINT_FLAG_WARNING | FU_CONSOLE_PRINT_FLAG_STDERR,
fmt, "%s\n",
/* TRANSLATORS: unsupported build of the package */ /* TRANSLATORS: unsupported build of the package */
_("This package has not been validated, it may not work properly.")); _("This package has not been validated, it may not work properly."));
#endif #endif
} }
@ -2954,67 +2777,7 @@ fu_util_is_url(const gchar *perhaps_url)
} }
gboolean gboolean
fu_util_setup_interactive_console(GError **error) fu_util_print_builder(FuConsole *console, JsonBuilder *builder, 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)
{ {
g_autofree gchar *data = NULL; g_autofree gchar *data = NULL;
g_autoptr(JsonGenerator) json_generator = NULL; g_autoptr(JsonGenerator) json_generator = NULL;
@ -3035,12 +2798,12 @@ fu_util_print_builder(JsonBuilder *builder, GError **error)
} }
/* just print */ /* just print */
g_print("%s\n", data); fu_console_print_literal(console, data);
return TRUE; return TRUE;
} }
void 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(); g_autoptr(JsonBuilder) builder = json_builder_new();
json_builder_begin_object(builder); 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_add_string_value(builder, error->message);
json_builder_end_object(builder); json_builder_end_object(builder);
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 { typedef enum {
@ -3104,7 +2867,7 @@ fu_util_print_version_key_valid(const gchar *key)
} }
gboolean 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; GHashTableIter iter;
const gchar *key; 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_array(builder);
json_builder_end_object(builder); json_builder_end_object(builder);
return fu_util_print_builder(builder, error); return fu_util_print_builder(console, builder, error);
} }
gchar * gchar *

View File

@ -13,6 +13,8 @@
#include "fwupd-bios-setting-private.h" #include "fwupd-bios-setting-private.h"
#include "fwupd-security-attr-private.h" #include "fwupd-security-attr-private.h"
#include "fu-console.h"
/* this is only valid for tools */ /* this is only valid for tools */
#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST + 1) #define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST + 1)
@ -33,44 +35,26 @@ typedef enum {
FU_SECURITY_ATTR_TO_STRING_FLAG_LAST FU_SECURITY_ATTR_TO_STRING_FLAG_LAST
} FuSecurityAttrToStringFlags; } 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 void
fu_util_print_data(const gchar *title, const gchar *msg); fu_util_print_tree(FuConsole *console, FwupdClient *client, GNode *n);
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);
gboolean gboolean
fu_util_is_interesting_device(FwupdDevice *dev); fu_util_is_interesting_device(FwupdDevice *dev);
gchar * gchar *
fu_util_get_user_cache_path(const gchar *fn); fu_util_get_user_cache_path(const gchar *fn);
void
fu_util_warning_box(const gchar *title, const gchar *body, guint width);
gboolean gboolean
fu_util_prompt_warning(FwupdDevice *device, fu_util_prompt_warning(FuConsole *console,
FwupdDevice *device,
FwupdRelease *release, FwupdRelease *release,
const gchar *machine, const gchar *machine,
GError **error); GError **error);
gboolean gboolean
fu_util_prompt_warning_fde(FwupdDevice *dev, GError **error); fu_util_prompt_warning_fde(FuConsole *console, FwupdDevice *dev, GError **error);
gboolean gboolean
fu_util_prompt_complete(FwupdDeviceFlags flags, gboolean prompt, GError **error); fu_util_prompt_complete(FuConsole *console,
FwupdDeviceFlags flags,
gboolean prompt,
GError **error);
gboolean gboolean
fu_util_update_reboot(GError **error); fu_util_update_reboot(GError **error);
@ -145,21 +129,20 @@ gint
fu_util_device_order_sort_cb(gconstpointer a, gconstpointer b); fu_util_device_order_sort_cb(gconstpointer a, gconstpointer b);
gboolean gboolean
fu_util_switch_branch_warning(FwupdDevice *dev, fu_util_switch_branch_warning(FuConsole *console,
FwupdDevice *dev,
FwupdRelease *rel, FwupdRelease *rel,
gboolean assume_yes, gboolean assume_yes,
GError **error); GError **error);
void void
fu_util_show_unsupported_warn(void); fu_util_show_unsupported_warning(FuConsole *console);
gboolean gboolean
fu_util_is_url(const gchar *perhaps_url); fu_util_is_url(const gchar *perhaps_url);
gboolean gboolean
fu_util_setup_interactive_console(GError **error); fu_util_print_builder(FuConsole *console, JsonBuilder *builder, GError **error);
gboolean
fu_util_print_builder(JsonBuilder *builder, GError **error);
void void
fu_util_print_error_as_json(const GError *error); fu_util_print_error_as_json(FuConsole *console, const GError *error);
gchar * gchar *
fu_util_project_versions_to_string(GHashTable *metadata); fu_util_project_versions_to_string(GHashTable *metadata);
gboolean 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 = library(
'fwupdutil', 'fwupdutil',
sources: [ sources: [
'fu-progressbar.c', 'fu-console.c',
'fu-security-attr-common.c', 'fu-security-attr-common.c',
'fu-util-bios-setting.c', 'fu-util-bios-setting.c',
'fu-util-common.c', 'fu-util-common.c',