Add support for soft-requirements that can be ignored with --force

This allows OEMs to suggest that certain components are updated to specific
versions, but allowing end-users to override this as required.
This commit is contained in:
Richard Hughes 2021-06-21 18:05:32 +01:00
parent bcc513741c
commit 005bf9d0b4
2 changed files with 79 additions and 0 deletions

View File

@ -1645,6 +1645,28 @@ fu_engine_check_trust (FuInstallTask *task, GError **error)
return TRUE;
}
static gboolean
fu_engine_check_soft_requirement (FuEngine *self,
FuEngineRequest *request,
XbNode *req,
FuDevice *device,
FwupdInstallFlags flags,
GError **error)
{
g_autoptr(GError) error_local = NULL;
if (!fu_engine_check_requirement (self, request, req, device,
flags, &error_local)) {
if (flags & FWUPD_INSTALL_FLAG_FORCE) {
g_debug ("ignoring soft-requirement due to --force: %s",
error_local->message);
return TRUE;
}
g_propagate_error (error, g_steal_pointer (&error_local));
return FALSE;
}
return TRUE;
}
gboolean
fu_engine_check_requirements (FuEngine *self,
FuEngineRequest *request,
@ -1679,6 +1701,24 @@ fu_engine_check_requirements (FuEngine *self,
return FALSE;
}
/* soft requirements */
g_clear_error (&error_local);
reqs = xb_node_query (fu_install_task_get_component (task),
"suggests/*|recommends/*", 0, &error_local);
if (reqs != NULL) {
for (guint i = 0; i < reqs->len; i++) {
XbNode *req = g_ptr_array_index (reqs, i);
if (!fu_engine_check_soft_requirement (self, request,
req, device,
flags, error))
return FALSE;
}
} else if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
g_propagate_error (error, g_steal_pointer (&error_local));
return FALSE;
}
return TRUE;
}

View File

@ -220,6 +220,43 @@ fu_engine_requirements_missing_func (gconstpointer user_data)
g_assert (!ret);
}
static void
fu_engine_requirements_soft_func (gconstpointer user_data)
{
gboolean ret;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new ();
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
const gchar *xml =
"<component>"
" <suggests>"
" <id compare=\"ge\" version=\"1.2.3\">not.going.to.exist</id>"
" </suggests>"
"</component>";
/* set up a dummy version */
fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3");
/* make the component require one thing */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (NULL, component);
ret = fu_engine_check_requirements (engine, request, task,
FWUPD_INSTALL_FLAG_FORCE,
&error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_requirements_client_fail_func (gconstpointer user_data)
{
@ -3289,6 +3326,8 @@ main (int argc, char **argv)
fu_engine_downgrade_func);
g_test_add_data_func ("/fwupd/engine{requirements-success}", self,
fu_engine_requirements_func);
g_test_add_data_func ("/fwupd/engine{requirements-soft}", self,
fu_engine_requirements_soft_func);
g_test_add_data_func ("/fwupd/engine{requirements-missing}", self,
fu_engine_requirements_missing_func);
g_test_add_data_func ("/fwupd/engine{requirements-client-fail}", self,