From 0d7a8e9682fe3e855fa3ec8aac0264101521cf7f 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 tree matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A provided tree 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 ++ tests/test-db.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) diff --git a/osinfo/libosinfo.syms b/osinfo/libosinfo.syms index 5c4221d..ae5fee3 100644 --- a/osinfo/libosinfo.syms +++ b/osinfo/libosinfo.syms @@ -640,6 +640,7 @@ LIBOSINFO_1.10.0 { global: osinfo_db_identify_medialist; + osinfo_db_identify_treelist; 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 7b5ea9b..074726a 100644 --- a/osinfo/osinfo_db.c +++ b/osinfo/osinfo_db.c @@ -1086,6 +1086,13 @@ static void fill_tree(OsinfoDb *db, OsinfoTree *tree, * the tree could be identified, its OsinfoEntify::id and OsinfoMedia::os * properties will be set. * + * The match for @tree 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_tree + * method instead to receive all matched tree. + * * Returns: TRUE if @tree was found in @db, FALSE otherwise * * Since: 1.6.0 @@ -1111,6 +1118,35 @@ gboolean osinfo_db_identify_tree(OsinfoDb *db, return TRUE; } +/** + * osinfo_db_identify_treelist: + * @db: an #OsinfoDb database + * @tree: the installation tree data + * + * Try to match a newly created @tree with a tree description from @db. + * The return list will contain any #OsinfoTree instances from @db that + * matched @tree. Usuaully there will only be one match returned, but + * applications should be prepared to deal with multiple matches. The + * returned #OsinfoTree instances will have their OsinfoEntify::id and + * OsinfoTree::os properties will be set, while @tree is left unmodified. + * + * Returns: (transfer full): a list containing any matches for @tree found in @db + * + * Since: 1.10.0 + */ +OsinfoTreeList *osinfo_db_identify_treelist(OsinfoDb *db, OsinfoTree *tree) +{ + OsinfoTreeList *matched_tree = osinfo_treelist_new(); + + g_return_val_if_fail(OSINFO_IS_TREE(tree), FALSE); + g_return_val_if_fail(OSINFO_IS_DB(db), FALSE); + + osinfo_db_guess_os_from_tree_internal(db, tree, matched_tree, + FALSE, NULL); + + return matched_tree; +} + struct osinfo_db_populate_values_args { GHashTable *values; const gchar *property; diff --git a/osinfo/osinfo_db.h b/osinfo/osinfo_db.h index aee2e64..7289cfb 100644 --- a/osinfo/osinfo_db.h +++ b/osinfo/osinfo_db.h @@ -80,6 +80,8 @@ OsinfoOs *osinfo_db_guess_os_from_tree(OsinfoDb *db, OsinfoTree **matched_tree); gboolean osinfo_db_identify_tree(OsinfoDb *db, OsinfoTree *tree); +OsinfoTreeList *osinfo_db_identify_treelist(OsinfoDb *db, + OsinfoTree *tree); // Get me all unique values for property "vendor" among operating systems GList *osinfo_db_unique_values_for_property_in_os(OsinfoDb *db, const gchar *propName); diff --git a/tests/test-db.c b/tests/test-db.c index ac5bfed..d5f48af 100644 --- a/tests/test-db.c +++ b/tests/test-db.c @@ -789,6 +789,96 @@ test_identify_tree(void) } +static void +test_identify_all_tree(void) +{ + OsinfoLoader *loader = osinfo_loader_new(); + OsinfoDb *db; + OsinfoTree *tree, *newtree; + OsinfoTreeList *treelist; + gboolean seenV6, seenV7, seenFallback; + GError *error = NULL; + int i; + + osinfo_loader_process_path(loader, SRCDIR "/tests/dbdata", &error); + g_assert_no_error(error); + db = osinfo_loader_get_db(loader); + + /* Matching against an "all" architecture" */ + tree = create_tree("x86_64", NULL); + treelist = osinfo_db_identify_treelist(db, tree); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(treelist)), ==, 1); + newtree = OSINFO_TREE(osinfo_list_get_nth(OSINFO_LIST(treelist), 0)); + g_assert_cmpstr(osinfo_tree_get_architecture(newtree), ==, "all"); + g_object_unref(treelist); + g_object_unref(tree); + + /* Matching against a known architecture, which has to have precedence */ + tree = create_tree("i686", "i686"); + treelist = osinfo_db_identify_treelist(db, tree); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(treelist)), ==, 1); + newtree = OSINFO_TREE(osinfo_list_get_nth(OSINFO_LIST(treelist), 0)); + g_assert_cmpstr(osinfo_tree_get_architecture(newtree), ==, "i686"); + g_object_unref(treelist); + g_object_unref(tree); + + /* Matching against a known architecture, which has to have precedence */ + tree = create_tree(NULL, "i686"); + treelist = osinfo_db_identify_treelist(db, tree); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(treelist)), ==, 1); + newtree = OSINFO_TREE(osinfo_list_get_nth(OSINFO_LIST(treelist), 0)); + g_assert_cmpstr(osinfo_tree_get_architecture(newtree), ==, "i686"); + g_object_unref(treelist); + g_object_unref(tree); + + /* Should not match a tree tagged with different arch, even + * if treeinfo matches, but can match fallback arch */ + seenV6 = seenV7 = seenFallback = FALSE; + tree = create_tree("armv7hl", "arm"); + treelist = osinfo_db_identify_treelist(db, tree); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(treelist)), ==, 2); + for (i = 0; i < 2; i++) { + newtree = OSINFO_TREE(osinfo_list_get_nth(OSINFO_LIST(treelist), i)); + if (osinfo_tree_get_url(newtree) == NULL) { + g_assert_false(seenFallback); + seenFallback = TRUE; + } else if (g_str_equal(osinfo_tree_get_url(newtree), "http://libosinfo.org/tree/v6")) { + g_assert_false(seenV6); + seenV6 = TRUE; + } else if (g_str_equal(osinfo_tree_get_url(newtree), "http://libosinfo.org/tree/v7")) { + g_assert_false(seenV7); + seenV7 = TRUE; + } + } + g_assert(!seenV6 && seenV7 && seenFallback); + g_object_unref(treelist); + g_object_unref(tree); + + tree = create_tree("armv6", "arm"); + treelist = osinfo_db_identify_treelist(db, tree); + g_assert_cmpint(osinfo_list_get_length(OSINFO_LIST(treelist)), ==, 2); + seenV6 = seenV7 = seenFallback = FALSE; + for (i = 0; i < 2; i++) { + newtree = OSINFO_TREE(osinfo_list_get_nth(OSINFO_LIST(treelist), i)); + if (osinfo_tree_get_url(newtree) == NULL) { + g_assert_false(seenFallback); + seenFallback = TRUE; + } else if (g_str_equal(osinfo_tree_get_url(newtree), "http://libosinfo.org/tree/v6")) { + g_assert_false(seenV6); + seenV6 = TRUE; + } else if (g_str_equal(osinfo_tree_get_url(newtree), "http://libosinfo.org/tree/v7")) { + g_assert_false(seenV7); + seenV7 = TRUE; + } + } + g_assert(seenV6 && !seenV7 && seenFallback); + g_object_unref(treelist); + g_object_unref(tree); + + g_object_unref(loader); +} + + int main(int argc, char *argv[]) { @@ -805,6 +895,7 @@ main(int argc, char *argv[]) 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); + g_test_add_func("/db/identify_all_tree", test_identify_all_tree); /* Upfront so we don't confuse valgrind */ osinfo_entity_get_type(); -- cgit v1.2.1