Add switch-branch support to fwupdtool

This commit is contained in:
Mario Limonciello 2020-10-20 15:39:47 -05:00 committed by Mario Limonciello
parent 0d778dbd50
commit 02f2cc311e
5 changed files with 195 additions and 54 deletions

View File

@ -26,6 +26,7 @@ _fwupdtool_cmd_list=(
'monitor'
'reinstall'
'security'
'switch-branch'
'self-sign'
'smbios-dump'
'attach'

View File

@ -2439,6 +2439,133 @@ fu_util_esp_list (FuUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
static gboolean
fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error)
{
const gchar *branch;
g_autoptr(FwupdRelease) rel = NULL;
g_autoptr(GPtrArray) rels = NULL;
g_autoptr(GPtrArray) branches = g_ptr_array_new_with_free_func (g_free);
g_autoptr(FuDevice) dev = NULL;
/* load engine */
if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error))
return FALSE;
/* find the device and check it has multiple branches */
priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED;
if (g_strv_length (values) == 1)
dev = fu_util_get_device (priv, values[1], error);
else
dev = fu_util_prompt_for_device (priv, NULL, error);
if (dev == NULL)
return FALSE;
if (!fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Multiple branches not available");
return FALSE;
}
/* get all releases, including the alternate branch versions */
rels = fu_engine_get_releases (priv->engine,
priv->request,
fu_device_get_id (dev),
error);
if (rels == NULL)
return FALSE;
/* get all the unique branches */
for (guint i = 0; i < rels->len; i++) {
FwupdRelease *rel_tmp = g_ptr_array_index (rels, i);
const gchar *branch_tmp = fu_util_release_get_branch (rel_tmp);
if (g_ptr_array_find_with_equal_func (branches, branch_tmp,
g_str_equal, NULL))
continue;
g_ptr_array_add (branches, g_strdup (branch_tmp));
}
/* branch name is optional */
if (g_strv_length (values) > 1) {
branch = values[1];
} else if (branches->len == 1) {
branch = g_ptr_array_index (branches, 0);
} else {
guint idx;
/* TRANSLATORS: get interactive prompt, where branch is the
* supplier of the firmware, e.g. "non-free" or "free" */
g_print ("%s\n", _("Choose a branch:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print ("0.\t%s\n", _("Cancel"));
for (guint i = 0; i < branches->len; i++) {
const gchar *branch_tmp = g_ptr_array_index (branches, i);
g_print ("%u.\t%s\n", i + 1, branch_tmp);
}
idx = fu_util_prompt_for_number (branches->len);
if (idx == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
"Request canceled");
return FALSE;
}
branch = g_ptr_array_index (branches, idx - 1);
}
/* sanity check */
if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s is already on branch %s",
fu_device_get_name (dev),
branch);
return FALSE;
}
/* the releases are ordered by version */
for (guint j = 0; j < rels->len; j++) {
FwupdRelease *rel_tmp = g_ptr_array_index (rels, j);
if (g_strcmp0 (fwupd_release_get_branch (rel_tmp), branch) == 0) {
rel = g_object_ref (rel_tmp);
break;
}
}
if (rel == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"No releases for branch %s",
branch);
return FALSE;
}
/* we're switching branch */
if (!fu_util_switch_branch_warning (FWUPD_DEVICE (dev), rel, FALSE, error))
return FALSE;
/* update the console if composite devices are also updated */
priv->current_operation = FU_UTIL_OPERATION_INSTALL;
g_signal_connect (priv->engine, "device-changed",
G_CALLBACK (fu_util_update_device_changed_cb), priv);
priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH;
if (!fu_util_install_release (priv, rel, error))
return FALSE;
fu_util_display_current_message (priv);
/* we don't want to ask anything */
if (priv->no_reboot_check) {
g_debug ("skipping reboot check");
return TRUE;
}
return fu_util_prompt_complete (priv->completion_flags, TRUE, error);
}
int
main (int argc, char *argv[])
{
@ -2749,6 +2876,12 @@ main (int argc, char *argv[])
/* TRANSLATORS: command description */
_("Lists files on the ESP"),
fu_util_esp_list);
fu_util_cmd_array_add (cmd_array,
"switch-branch",
"[DEVICE-ID|GUID] [BRANCH]",
/* TRANSLATORS: command description */
_("Switch the firmware branch on the device"),
fu_util_switch_branch);
/* do stuff on ctrl+c */
priv->cancellable = g_cancellable_new ();
@ -2772,6 +2905,7 @@ main (int argc, char *argv[])
/* set our implemented feature set */
fu_engine_request_set_feature_flags (priv->request,
FWUPD_FEATURE_FLAG_DETACH_ACTION |
FWUPD_FEATURE_FLAG_SWITCH_BRANCH |
FWUPD_FEATURE_FLAG_UPDATE_ACTION);
}

View File

@ -1939,3 +1939,57 @@ fu_util_device_order_sort_cb (gconstpointer a, gconstpointer b)
FuDevice *device_b = *((FuDevice **) b);
return fu_util_device_order_compare (device_a, device_b);
}
gboolean
fu_util_switch_branch_warning (FwupdDevice *dev,
FwupdRelease *rel,
gboolean assume_yes,
GError **error)
{
const gchar *desc_markup = NULL;
g_autofree gchar *desc_plain = NULL;
g_autoptr(GString) desc_full = g_string_new (NULL);
/* warn the user if the vendor is different */
if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) {
/* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */
g_string_append_printf (desc_full, _("The firmware from %s is not "
"supplied by %s, the hardware vendor."),
fwupd_release_get_vendor (rel),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
/* TRANSLATORS: %1 is the device vendor name */
g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, "
"and installing this release may void any warranty "
"with %s."),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
}
/* from the <description> in the AppStream data */
desc_markup = fwupd_release_get_description (rel);
if (desc_markup == NULL)
return TRUE;
desc_plain = fu_util_convert_description (desc_markup, error);
if (desc_plain == NULL)
return FALSE;
g_string_append (desc_full, desc_plain);
/* show and ask user to confirm */
fu_util_warning_box (desc_full->str, 80);
if (!assume_yes) {
/* ask for permission */
g_print ("\n%s [y|N]: ",
/* TRANSLATORS: should the branch be changed */
_("Do you understand the consequences of changing the firmware branch?"));
if (!fu_util_prompt_for_boolean (FALSE)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
"Declined branch switch");
return FALSE;
}
}
return TRUE;
}

View File

@ -113,3 +113,8 @@ gint fu_util_sort_devices_by_flags_cb (gconstpointer a,
gconstpointer b);
gint fu_util_device_order_sort_cb (gconstpointer a,
gconstpointer b);
gboolean fu_util_switch_branch_warning (FwupdDevice *dev,
FwupdRelease *rel,
gboolean assume_yes,
GError **error);

View File

@ -1900,59 +1900,6 @@ fu_util_reinstall (FuUtilPrivate *priv, gchar **values, GError **error)
return fu_util_prompt_complete (priv->completion_flags, TRUE, error);
}
static gboolean
fu_util_switch_branch_warning (FuUtilPrivate *priv,
FwupdDevice *dev,
FwupdRelease *rel,
GError **error)
{
const gchar *desc_markup = NULL;
g_autofree gchar *desc_plain = NULL;
g_autoptr(GString) desc_full = g_string_new (NULL);
/* warn the user if the vendor is different */
if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) {
/* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */
g_string_append_printf (desc_full, _("The firmware from %s is not "
"supplied by %s, the hardware vendor."),
fwupd_release_get_vendor (rel),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
/* TRANSLATORS: %1 is the device vendor name */
g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, "
"and installing this release may void any warranty "
"with %s."),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
}
/* from the <description> in the AppStream data */
desc_markup = fwupd_release_get_description (rel);
if (desc_markup == NULL)
return TRUE;
desc_plain = fu_util_convert_description (desc_markup, error);
if (desc_plain == NULL)
return FALSE;
g_string_append (desc_full, desc_plain);
/* show and ask user to confirm */
fu_util_warning_box (desc_full->str, 80);
if (!priv->assume_yes) {
/* ask for permission */
g_print ("\n%s [y|N]: ",
/* TRANSLATORS: should the branch be changed */
_("Do you understand the consequences of changing the firmware branch?"));
if (!fu_util_prompt_for_boolean (FALSE)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
"Declined branch switch");
return FALSE;
}
}
return TRUE;
}
static gboolean
fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error)
{
@ -2049,7 +1996,7 @@ fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error)
}
/* we're switching branch */
if (!fu_util_switch_branch_warning (priv, dev, rel, error))
if (!fu_util_switch_branch_warning (dev, rel, priv->assume_yes, error))
return FALSE;
/* update the console if composite devices are also updated */