trivial: Move the device list to a new object

This moves more functionality out of the engine, and will allow us to add some
cleverness to the device list to allow the FuDevice to be shared between
different plugins.
This commit is contained in:
Richard Hughes 2017-11-22 11:01:13 +00:00
parent e7e95452fd
commit 0a7e783cdd
6 changed files with 557 additions and 268 deletions

272
src/fu-device-list.c Normal file
View File

@ -0,0 +1,272 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <glib-object.h>
#include <string.h>
#include "fu-device-list.h"
#include "fwupd-error.h"
/**
* SECTION:fu-device-list
* @short_description: a list of devices
*
* This list of devices provides a way to find a device using either the
* device-id or a GUID.
*
* See also: #FuDevice
*/
static void fu_device_list_finalize (GObject *obj);
struct _FuDeviceList
{
GObject parent_instance;
GPtrArray *devices; /* of FuDeviceItem */
};
/* although this seems a waste of time, there are great plans for this... */
typedef struct {
FuDevice *device;
} FuDeviceItem;
G_DEFINE_TYPE (FuDeviceList, fu_device_list, G_TYPE_OBJECT)
/**
* fu_device_list_get_all:
* @self: A #FuDeviceList
*
* Returns all the devices that have been added to the device list.
*
* Returns: (transfer container) (element-type FuDevice): the devices
*
* Since: 1.0.2
**/
GPtrArray *
fu_device_list_get_all (FuDeviceList *self)
{
GPtrArray *devices;
g_return_val_if_fail (FU_IS_DEVICE_LIST (self), NULL);
devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
for (guint i = 0; i < self->devices->len; i++) {
FuDeviceItem *item = g_ptr_array_index (self->devices, i);
g_ptr_array_add (devices, g_object_ref (item->device));
}
return devices;
}
/**
* fu_device_list_remove:
* @self: A #FuDeviceList
* @device: A #FuDevice
*
* Removes a specific device from the list if it exists.
*
* Since: 1.0.2
**/
void
fu_device_list_remove (FuDeviceList *self, FuDevice *device)
{
g_return_if_fail (FU_IS_DEVICE_LIST (self));
g_return_if_fail (FU_IS_DEVICE (device));
for (guint i = 0; i < self->devices->len; i++) {
FuDeviceItem *item = g_ptr_array_index (self->devices, i);
if (item->device == device) {
g_ptr_array_remove (self->devices, item);
return;
}
}
}
/**
* fu_device_list_add:
* @self: A #FuDeviceList
* @device: A #FuDevice
* @error: A #GError, or %NULL
*
* Adds a specific device to the device list.
*
* Returns: (transfer none): a device, or %NULL if not found
*
* Since: 1.0.2
**/
void
fu_device_list_add (FuDeviceList *self, FuDevice *device)
{
FuDeviceItem *item;
g_return_if_fail (FU_IS_DEVICE_LIST (self));
g_return_if_fail (FU_IS_DEVICE (device));
/* FIXME: verify the device does not already exist */
/* add helper */
item = g_new0 (FuDeviceItem, 1);
item->device = g_object_ref (device);
g_ptr_array_add (self->devices, item);
}
/**
* fu_device_list_find_by_guid:
* @self: A #FuDeviceList
* @guid: A device GUID
* @error: A #GError, or %NULL
*
* Finds a specific device that has the matching GUID.
*
* Returns: (transfer none): a device, or %NULL if not found
*
* Since: 1.0.2
**/
FuDevice *
fu_device_list_find_by_guid (FuDeviceList *self, const gchar *guid, GError **error)
{
g_return_val_if_fail (FU_IS_DEVICE_LIST (self), NULL);
g_return_val_if_fail (guid != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
for (guint i = 0; i < self->devices->len; i++) {
FuDeviceItem *item = g_ptr_array_index (self->devices, i);
if (fu_device_has_guid (item->device, guid))
return item->device;
}
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"GUID %s was not found",
guid);
return NULL;
}
/**
* fu_device_list_find_by_id:
* @self: A #FuDeviceList
* @device_id: A device ID, typically a SHA1 hash
* @error: A #GError, or %NULL
*
* Finds a specific device using the ID string. This function also supports
* using abbreviated hashes.
*
* Returns: (transfer none): a device, or %NULL if not found
*
* Since: 1.0.2
**/
FuDevice *
fu_device_list_find_by_id (FuDeviceList *self, const gchar *device_id, GError **error)
{
FuDeviceItem *item = NULL;
gboolean multiple_matches = FALSE;
gsize device_id_len;
g_return_val_if_fail (FU_IS_DEVICE_LIST (self), NULL);
g_return_val_if_fail (device_id != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* support abbreviated hashes */
device_id_len = strlen (device_id);
for (gsize i = 0; i < self->devices->len; i++) {
FuDeviceItem *item_tmp = g_ptr_array_index (self->devices, i);
const gchar *ids[] = {
fu_device_get_id (item_tmp->device),
fu_device_get_equivalent_id (item_tmp->device),
NULL };
for (guint j = 0; ids[j] != NULL; j++) {
if (strncmp (ids[j], device_id, device_id_len) == 0) {
if (item != NULL)
multiple_matches = TRUE;
item = item_tmp;
}
}
}
/* nothing at all matched */
if (item == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"device ID %s was not found",
device_id);
return NULL;
}
/* multiple things matched */
if (multiple_matches) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"device ID %s was not unique",
device_id);
return NULL;
}
/* something found */
return item->device;
}
static void
fu_device_list_item_free (FuDeviceItem *item)
{
g_object_unref (item->device);
g_free (item);
}
static void
fu_device_list_class_init (FuDeviceListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fu_device_list_finalize;
}
static void
fu_device_list_init (FuDeviceList *self)
{
self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_device_list_item_free);
}
static void
fu_device_list_finalize (GObject *obj)
{
FuDeviceList *self = FU_DEVICE_LIST (obj);
g_ptr_array_unref (self->devices);
G_OBJECT_CLASS (fu_device_list_parent_class)->finalize (obj);
}
/**
* fu_device_list_new:
*
* Creates a new device list.
*
* Returns: (transfer full): a #FuDeviceList
*
* Since: 1.0.2
**/
FuDeviceList *
fu_device_list_new (void)
{
FuDeviceList *self;
self = g_object_new (FU_TYPE_DEVICE_LIST, NULL);
return FU_DEVICE_LIST (self);
}

50
src/fu-device-list.h Normal file
View File

@ -0,0 +1,50 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FU_DEVICE_LIST_H
#define __FU_DEVICE_LIST_H
G_BEGIN_DECLS
#include <glib-object.h>
#include "fu-device.h"
#define FU_TYPE_DEVICE_LIST (fu_device_list_get_type ())
G_DECLARE_FINAL_TYPE (FuDeviceList, fu_device_list, FU, DEVICE_LIST, GObject)
FuDeviceList *fu_device_list_new (void);
void fu_device_list_add (FuDeviceList *self,
FuDevice *device);
void fu_device_list_remove (FuDeviceList *self,
FuDevice *device);
GPtrArray *fu_device_list_get_all (FuDeviceList *self);
FuDevice *fu_device_list_find_by_id (FuDeviceList *self,
const gchar *device_id,
GError **error);
FuDevice *fu_device_list_find_by_guid (FuDeviceList *self,
const gchar *guid,
GError **error);
G_END_DECLS
#endif /* __FU_DEVICE_LIST_H */

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,6 @@ GPtrArray *fu_engine_get_details (FuEngine *self,
/* for the self tests */
void fu_engine_add_device (FuEngine *self,
FuPlugin *plugin,
FuDevice *device);
void fu_engine_add_plugin (FuEngine *self,
FuPlugin *plugin);

View File

@ -30,6 +30,7 @@
#include <string.h>
#include "fu-config.h"
#include "fu-device-list.h"
#include "fu-device-private.h"
#include "fu-engine.h"
#include "fu-quirks.h"
@ -69,12 +70,12 @@ fu_engine_partial_hash_func (void)
fu_device_set_id (device1, "device1");
fu_device_set_plugin (device1, "test");
fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012");
fu_engine_add_device (engine, plugin, device1);
fu_engine_add_device (engine, device1);
fu_device_set_id (device2, "device21");
fu_device_set_plugin (device2, "test");
fu_device_set_equivalent_id (device2, "b92f5b7560b84ca005a79f5a15de3c003ce494cf");
fu_device_add_guid (device2, "12345678-1234-1234-1234-123456789012");
fu_engine_add_device (engine, plugin, device2);
fu_engine_add_device (engine, device2);
/* match nothing */
ret = fu_engine_unlock (engine, "deadbeef", &error_none);
@ -145,7 +146,7 @@ fu_engine_require_hwid_func (void)
fu_device_set_id (device, "test_device");
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_engine_add_device (engine, plugin, device);
fu_engine_add_device (engine, device);
/* install it */
ret = fu_engine_install (engine, fu_device_get_id (device),
@ -271,7 +272,7 @@ fu_engine_func (void)
fu_device_set_name (device, "Test Device");
fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_engine_add_device (engine, plugin, device);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
@ -306,6 +307,65 @@ fu_engine_func (void)
g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.2");
}
static void
fu_device_list_func (void)
{
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) devices2 = NULL;
g_autoptr(GError) error = NULL;
FuDevice *device;
/* add both */
fu_device_set_id (device1, "device1");
fu_device_add_guid (device1, "foobar");
fu_device_list_add (device_list, device1);
fu_device_set_id (device2, "device2");
fu_device_add_guid (device2, "baz");
fu_device_list_add (device_list, device2);
/* get all */
devices = fu_device_list_get_all (device_list);
g_assert_cmpint (devices->len, ==, 2);
device = g_ptr_array_index (devices, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a");
/* find by ID */
device = fu_device_list_find_by_id (device_list,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a",
&error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a");
/* find by GUID */
device = fu_device_list_find_by_guid (device_list,
"579a3b1c-d1db-5bdc-b6b9-e2c1b28d5b8a",
&error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
/* find by missing GUID */
device = fu_device_list_find_by_guid (device_list, "notfound", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (device == NULL);
/* remove device */
fu_device_list_remove (device_list, device1);
devices2 = fu_device_list_get_all (device_list);
g_assert_cmpint (devices2->len, ==, 1);
device = g_ptr_array_index (devices2, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
}
static void
fu_device_metadata_func (void)
{
@ -1156,6 +1216,7 @@ main (int argc, char **argv)
g_test_add_func ("/fwupd/device-locker{success}", fu_device_locker_func);
g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func);
g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func);
g_test_add_func ("/fwupd/device-list", fu_device_list_func);
g_test_add_func ("/fwupd/engine", fu_engine_func);
g_test_add_func ("/fwupd/engine{require-hwid}", fu_engine_require_hwid_func);
g_test_add_func ("/fwupd/engine{partial-hash}", fu_engine_partial_hash_func);

View File

@ -128,6 +128,7 @@ executable(
'fu-hwids.c',
'fu-debug.c',
'fu-device.c',
'fu-device-list.c',
'fu-device-locker.c',
'fu-keyring.c',
'fu-pending.c',
@ -189,6 +190,7 @@ if get_option('enable-tests')
'fu-keyring.c',
'fu-hwids.c',
'fu-device.c',
'fu-device-list.c',
'fu-device-locker.c',
'fu-pending.c',
'fu-keyring.c',