summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel P. Berrangé <berrange@redhat.com>2021-11-25 12:33:11 +0000
committerDaniel P. Berrangé <berrange@redhat.com>2022-02-04 14:14:49 +0000
commitcb34f72a4045b9beade1222cb393a141746e227c (patch)
treedd978bd652d0104cf3b066459b9ff5b1e68af640
parentc17d09bfe36bca7db225c4844b3d7a54c1d5e5a7 (diff)
downloadlibosinfo-cb34f72a4045b9beade1222cb393a141746e227c.tar.gz
osinfo: allow tree matching code to report multiple entries
Refactor the tree matching code so that it can be told to return all matching entries, rather than only the first. The original behaviour can be requested to short-circuit matching if the caller only requires the first match. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
-rw-r--r--osinfo/osinfo_db.c70
1 files changed, 59 insertions, 11 deletions
diff --git a/osinfo/osinfo_db.c b/osinfo/osinfo_db.c
index 6cca925..13ff04f 100644
--- a/osinfo/osinfo_db.c
+++ b/osinfo/osinfo_db.c
@@ -821,19 +821,41 @@ gboolean osinfo_db_identify_media(OsinfoDb *db, OsinfoMedia *media)
return TRUE;
}
+/*
+ * Fill @matched_tree with all OsinfoOs in @oss
+ * that match @tree.
+ *
+ * If @onlyFirstMatch is TRUE then will return as soon as
+ * one matching tree is found
+ *
+ * If @onlyFirstMatch is FALSE then will return matching
+ * trees from all OsinfoOs, potentially with multiple trees
+ * per OsinfoOs reported.
+ *
+ * @fallback_os will be filled with any OsinfoOs that
+ * can be used as fallbacks matches. It will never contain
+ * any OsinfoOs that had tree added to @matched_tree.
+ *
+ * If @ret_os is non-NULL it will be filled with the first
+ * matching OsinfoOs.
+ */
static gboolean compare_tree(OsinfoTree *tree,
GList *oss,
OsinfoTreeList *matched_tree,
+ gboolean onlyFirstMatch,
OsinfoOs **ret_os,
GList **fallback_oss)
{
GList *os_iter;
+ gboolean matched = FALSE;
for (os_iter = oss; os_iter; os_iter = os_iter->next) {
OsinfoOs *os = OSINFO_OS(os_iter->data);
OsinfoTreeList *tree_list = osinfo_os_get_tree_list(os);
GList *trees = osinfo_list_get_elements(OSINFO_LIST(tree_list));
GList *tree_iter;
+ gboolean useFallback = TRUE;
+ gboolean haveFallback = FALSE;
for (tree_iter = trees; tree_iter; tree_iter = tree_iter->next) {
OsinfoTree *os_tree = OSINFO_TREE(tree_iter->data);
@@ -842,32 +864,39 @@ static gboolean compare_tree(OsinfoTree *tree,
os_tree_arch = osinfo_tree_get_architecture(os_tree);
if (fallback_oss != NULL) {
if (g_str_equal(os_tree_arch, "all")) {
- *fallback_oss = g_list_prepend(*fallback_oss, os);
+ haveFallback = TRUE;
continue;
}
}
if (osinfo_tree_matches(tree, os_tree)) {
- *ret_os = os;
+ if (ret_os && !*ret_os)
+ *ret_os = os;
osinfo_list_add(OSINFO_LIST(matched_tree), OSINFO_ENTITY(os_tree));
- break;
+ useFallback = FALSE;
+ matched = TRUE;
+ if (onlyFirstMatch)
+ break;
}
}
g_list_free(trees);
g_object_unref(tree_list);
- if (*ret_os)
- return TRUE;
+ if (useFallback && haveFallback)
+ *fallback_oss = g_list_prepend(*fallback_oss, os);
+ if (onlyFirstMatch && matched)
+ break;
}
- return FALSE;
+ return matched;
}
static gboolean
osinfo_db_guess_os_from_tree_internal(OsinfoDb *db,
OsinfoTree *tree,
OsinfoTreeList *matched_tree,
+ gboolean onlyFirstMatch,
OsinfoOs **matched_os)
{
GList *oss = NULL;
@@ -880,12 +909,31 @@ osinfo_db_guess_os_from_tree_internal(OsinfoDb *db,
g_return_val_if_fail(OSINFO_IS_DB(db), FALSE);
g_return_val_if_fail(tree != NULL, FALSE);
+
+ /*
+ * If we're looking for the first match only:
+ *
+ * - Try to get a preferred match
+ * - If that doesn't work, then try fallback matches
+ *
+ * If we're looking for all matches:
+ *
+ * - Add all preferred matches first
+ * - Add remaining fallback matches secon
+ *
+ * This ensures that if the caller requests all matches
+ * but then blindly picks the first match, they will
+ * not accidentally get a fallback match when a preferred
+ * match was available.
+ */
oss = osinfo_list_get_elements(OSINFO_LIST(db->priv->oses));
- if (compare_tree(tree, oss, matched_tree, matched_os, &fallback_oss))
+ if (compare_tree(tree, oss, matched_tree,
+ onlyFirstMatch, matched_os, &fallback_oss))
matched = TRUE;
- if (!matched &&
- compare_tree(tree, fallback_oss, matched_tree, matched_os, NULL))
+ if ((!onlyFirstMatch || !matched) &&
+ compare_tree(tree, fallback_oss, matched_tree,
+ onlyFirstMatch, matched_os, NULL))
matched = TRUE;
g_list_free(oss);
@@ -913,7 +961,7 @@ OsinfoOs *osinfo_db_guess_os_from_tree(OsinfoDb *db,
g_autoptr(OsinfoTreeList) all_matched_tree = osinfo_treelist_new();
OsinfoOs *ret;
- if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree, &ret))
+ if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree, TRUE, &ret))
return NULL;
return ret;
@@ -1017,7 +1065,7 @@ gboolean osinfo_db_identify_tree(OsinfoDb *db,
g_return_val_if_fail(OSINFO_IS_DB(db), FALSE);
if (!osinfo_db_guess_os_from_tree_internal(db, tree, all_matched_tree,
- &matched_os)) {
+ TRUE, &matched_os)) {
return FALSE;
}