From c0ba8e5d0b74625f1236c904d951f4bd6221818e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 24 Nov 2021 18:27:53 +0000 Subject: osinfo: add API for resolving multiple media matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A provided media object might match multiple entries from the database. Add an API that allows for this possibility to let applications decide how to handle it. Signed-off-by: Daniel P. Berrangé --- osinfo/libosinfo.syms | 1 + osinfo/osinfo_db.c | 36 ++++ osinfo/osinfo_db.h | 2 + .../os/libosinfo.org/test-db-media-dupe1.xml | 17 ++ .../os/libosinfo.org/test-db-media-dupe2.xml | 17 ++ .../os/libosinfo.org/test-db-media-dupe3.xml | 17 ++ .../os/libosinfo.org/test-db-media-dupe4.xml | 17 ++ tests/test-db.c | 193 +++++++++++++++++++++ 8 files changed, 300 insertions(+) create mode 100644 tests/dbdata/os/libosinfo.org/test-db-media-dupe1.xml create mode 100644 tests/dbdata/os/libosinfo.org/test-db-media-dupe2.xml create mode 100644 tests/dbdata/os/libosinfo.org/test-db-media-dupe3.xml create mode 100644 tests/dbdata/os/libosinfo.org/test-db-media-dupe4.xml diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms index a49678c..5c4221d 100644 --- a/osinfo/libosinfo.syms +++ b/osinfo/libosinfo.syms @@ -639,6 +639,7 @@ LIBOSINFO_1.8.0 { LIBOSINFO_1.10.0 { global: + osinfo_db_identify_medialist; osinfo_media_matches; osinfo_os_get_complete_firmware_list; osinfo_tree_matches; diff --git a/osinfo/osinfo_db.c b/osinfo/osinfo_db.c index 13ff04f..7b5ea9b 100644 --- a/osinfo/osinfo_db.c +++ b/osinfo/osinfo_db.c @@ -797,6 +797,13 @@ static void fill_media(OsinfoDb *db, OsinfoMedia *media, * the media could be identified, its OsinfoEntify::id and OsinfoMedia::os * properties will be set. * + * The match for @media in @db is not guaranteed to be unique and + * this method will only return the first match found. The order + * in which matches are identified is not guaranteed, so when there + * are multiple matches, the returned match may vary over time. + * Applications are recommended to use the #osinfo_db_identify_all_media + * method instead to receive all matched media. + * * Returns: TRUE if @media was found in @db, FALSE otherwise * * Since: 0.2.3 @@ -821,6 +828,35 @@ gboolean osinfo_db_identify_media(OsinfoDb *db, OsinfoMedia *media) return TRUE; } +/** + * osinfo_db_identify_medialist: + * @db: an #OsinfoDb database + * @media: the installation media data + * + * Try to match a newly created @media with a media description from @db. + * The return list will contain any #OsinfoMedia instances from @db that + * matched @media. Usuaully there will only be one match returned, but + * applications should be prepared to deal with multiple matches. The + * returned #OsinfoMedia instances will have their OsinfoEntify::id and + * OsinfoMedia::os properties will be set, while @media is left unmodified. + * + * Returns: (transfer full): a list containing any matches for @media found in @db + * + * Since: 1.10.0 + */ +OsinfoMediaList *osinfo_db_identify_medialist(OsinfoDb *db, OsinfoMedia *media) +{ + OsinfoMediaList *matched_media = osinfo_medialist_new(); + + g_return_val_if_fail(OSINFO_IS_MEDIA(media), FALSE); + g_return_val_if_fail(OSINFO_IS_DB(db), FALSE); + + osinfo_db_guess_os_from_media_internal(db, media, matched_media, + FALSE, NULL); + + return matched_media; +} + /* * Fill @matched_tree with all OsinfoOs in @oss * that match @tree. diff --git a/osinfo/osinfo_db.h b/osinfo/osinfo_db.h index 31ee7a0..aee2e64 100644 --- a/osinfo/osinfo_db.h +++ b/osinfo/osinfo_db.h @@ -71,6 +71,8 @@ OsinfoOs *osinfo_db_guess_os_from_media(OsinfoDb *db, OsinfoMedia **matched_media); gboolean osinfo_db_identify_media(OsinfoDb *db, OsinfoMedia *media); +OsinfoMediaList *osinfo_db_identify_medialist(OsinfoDb *db, + OsinfoMedia *media); G_DEPRECATED_FOR(osinfo_db_identify_tree) OsinfoOs *osinfo_db_guess_os_from_tree(OsinfoDb *db, diff --git a/tests/dbdata/os/libosinfo.org/test-db-media-dupe1.xml b/tests/dbdata/os/libosinfo.org/test-db-media-dupe1.xml new file mode 100644 index 0000000..312197d --- /dev/null +++ b/tests/dbdata/os/libosinfo.org/test-db-media-dupe1.xml @@ -0,0 +1,17 @@ + + + + db-media-dupe1 + DB Media Dupe1 + unknown + libosinfo.org + test + + + + dupe + LINUX + + + + diff --git a/tests/dbdata/os/libosinfo.org/test-db-media-dupe2.xml b/tests/dbdata/os/libosinfo.org/test-db-media-dupe2.xml new file mode 100644 index 0000000..152a6a4 --- /dev/null +++ b/tests/dbdata/os/libosinfo.org/test-db-media-dupe2.xml @@ -0,0 +1,17 @@ + + + + db-media-dupe2 + DB Media Dupe2 + unknown + libosinfo.org + test + + + + dupe + LINUX + + + + diff --git a/tests/dbdata/os/libosinfo.org/test-db-media-dupe3.xml b/tests/dbdata/os/libosinfo.org/test-db-media-dupe3.xml new file mode 100644 index 0000000..215bbf9 --- /dev/null +++ b/tests/dbdata/os/libosinfo.org/test-db-media-dupe3.xml @@ -0,0 +1,17 @@ + + + + db-media-dupe3 + DB Media Dupe3 + unknown + libosinfo.org + test + + + + dupe + LINUX + + + + diff --git a/tests/dbdata/os/libosinfo.org/test-db-media-dupe4.xml b/tests/dbdata/os/libosinfo.org/test-db-media-dupe4.xml new file mode 100644 index 0000000..b2b2075 --- /dev/null +++ b/tests/dbdata/os/libosinfo.org/test-db-media-dupe4.xml @@ -0,0 +1,17 @@ + + + + db-media-dupe4 + DB Media Dupe4 + unknown + libosinfo.org + test + + + + dupe + LINUX + + + + diff --git a/tests/test-db.c b/tests/test-db.c index 32c2835..ac5bfed 100644 --- a/tests/test-db.c +++ b/tests/test-db.c @@ -529,6 +529,198 @@ test_identify_media(void) } +static void +test_identify_all_media(void) +{ + OsinfoLoader *loader = osinfo_loader_new(); + OsinfoDb *db; + OsinfoMedia *media, *newmedia; + OsinfoMediaList *medialist; + OsinfoOs *os; + OsinfoInstallScriptList *scripts; + GError *error = NULL; + int i; + gboolean seenDupe1, seenDupe2, seenDupe3, seenDupe4; + gboolean seenRolling, seenVersioned; + + osinfo_loader_process_path(loader, SRCDIR "/tests/dbdata", &error); + g_assert_no_error(error); + db = osinfo_loader_get_db(loader); + + media = osinfo_media_new("foo", "ppc64le"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "DB Media"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_SYSTEM_ID, + "LINUX"); + + medialist = osinfo_db_identify_medialist(db, media); + g_assert_nonnull(medialist); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 1); + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), 0)); + g_object_unref(medialist); + g_assert_cmpstr(osinfo_media_get_architecture(newmedia), ==, "ppc64le"); + g_assert_true(osinfo_media_get_live(newmedia)); + g_assert_true(osinfo_media_get_installer(newmedia)); + g_assert_false(osinfo_media_supports_installer_script(newmedia)); + g_assert_cmpint(osinfo_media_get_installer_reboots(newmedia), ==, 6); + g_assert_false(osinfo_media_get_eject_after_install(newmedia)); + g_assert_cmpstr(osinfo_media_get_kernel_path(newmedia), ==, "isolinux/vmlinuz"); + g_assert_cmpstr(osinfo_media_get_initrd_path(newmedia), ==, "isolinux/initrd.img"); + scripts = osinfo_media_get_install_script_list(newmedia); + g_assert_nonnull(scripts); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(scripts)), ==, 1); + os = osinfo_media_get_os(newmedia); + g_assert_nonnull(os); + g_assert_cmpstr(osinfo_entity_get_id(OSINFO_ENTITY(os)), ==, "http://libosinfo.org/test/db/media"); + g_object_unref(scripts); + + media = osinfo_media_new("foo", "ppc64le"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "Media DB"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_SYSTEM_ID, + "LINUX"); + + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 0); + g_object_unref(medialist); + g_object_unref(media); + + /* Matching against an "all" architecture */ + media = osinfo_media_new("foo", "x86_64"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "bootimg"); + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 1); + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), 0)); + g_assert_cmpstr(osinfo_media_get_architecture(newmedia), ==, "all"); + g_object_unref(medialist); + g_object_unref(media); + + /* Matching against a known architecture, which has to have precedence */ + media = osinfo_media_new("foo", "i686"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "bootimg"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_SYSTEM_ID, + "LINUX"); + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 1); + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), 0)); + g_assert_cmpstr(osinfo_media_get_architecture(newmedia), ==, "i686"); + g_object_unref(medialist); + g_object_unref(media); + + /* Should return both the version and non-versioned rolling OS matches */ + media = osinfo_media_new("foo", "x86_64"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "ROLLING_VERSIONED"); + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 2); + seenVersioned = seenRolling = FALSE; + for (i = 0; i < 2; i++) { + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), i)); + os = osinfo_media_get_os(newmedia); + g_assert_nonnull(os); + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "versioned")) { + g_assert_false(seenVersioned); + seenVersioned = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "rolling")) { + g_assert_false(seenRolling); + seenRolling = TRUE; + } + } + g_assert(seenVersioned && seenRolling); + g_object_unref(medialist); + g_object_unref(media); + + /* Matching against a image with many matches. Should match two OS + * with corresponding arch, and one with fallback arch */ + media = osinfo_media_new("foo", "i686"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "dupe"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_SYSTEM_ID, + "LINUX"); + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 3); + seenDupe1 = seenDupe2 = seenDupe3 = seenDupe4 = FALSE; + for (i = 0; i < 3; i++) { + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), i)); + os = osinfo_media_get_os(newmedia); + g_assert_nonnull(os); + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe1")) { + g_assert_false(seenDupe1); + seenDupe1 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe2")) { + g_assert_false(seenDupe2); + seenDupe2 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe3")) { + g_assert_false(seenDupe3); + seenDupe3 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe4")) { + g_assert_false(seenDupe4); + seenDupe4 = TRUE; + } + } + g_assert(seenDupe1 && seenDupe2 && !seenDupe3 && seenDupe4); + + g_object_unref(medialist); + g_object_unref(media); + + /* Matching without arch against a image with many matches. + * Should match all OS regardless of their media arch */ + media = osinfo_media_new("foo", NULL); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_VOLUME_ID, + "dupe"); + osinfo_entity_set_param(OSINFO_ENTITY(media), + OSINFO_MEDIA_PROP_SYSTEM_ID, + "LINUX"); + medialist = osinfo_db_identify_medialist(db, media); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(medialist)), ==, 4); + seenDupe1 = seenDupe2 = seenDupe3 = seenDupe4 = FALSE; + for (i = 0; i < 4; i++) { + newmedia = OSINFO_MEDIA(osinfo_list_get_nth(OSINFO_LIST(medialist), i)); + os = osinfo_media_get_os(newmedia); + g_assert_nonnull(os); + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe1")) { + g_assert_false(seenDupe1); + seenDupe1 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe2")) { + g_assert_false(seenDupe2); + seenDupe2 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe3")) { + g_assert_false(seenDupe3); + seenDupe3 = TRUE; + } + if (g_str_equal(osinfo_product_get_short_id(OSINFO_PRODUCT(os)), "db-media-dupe4")) { + g_assert_false(seenDupe4); + seenDupe4 = TRUE; + } + } + g_assert(seenDupe1 && seenDupe2 && seenDupe3 && seenDupe4); + + g_object_unref(medialist); + g_object_unref(media); + + g_object_unref(loader); +} + + static OsinfoTree * create_tree(const gchar *arch, const gchar *treeinfo_arch) { @@ -611,6 +803,7 @@ main(int argc, char *argv[]) g_test_add_func("/db/prop_os", test_prop_os); g_test_add_func("/db/rel_os", test_rel_os); g_test_add_func("/db/identify_media", test_identify_media); + g_test_add_func("/db/identify_all_media", test_identify_all_media); g_test_add_func("/db/identify_tree", test_identify_tree); /* Upfront so we don't confuse valgrind */ -- cgit v1.2.1