/** * as_pool_refine_data: * * Automatically refine the data we have about software components in the pool. * * Returns: %TRUE if all metadata was used, %FALSE if we skipped some stuff. */ static gboolean as_pool_refine_data (AsPool *pool) { GHashTableIter iter; gpointer key, value; GHashTable *refined_cpts; gboolean ret = TRUE; AsPoolPrivate *priv = GET_PRIVATE (pool); /* since we might remove stuff from the pool, we need a new table to store the result */ refined_cpts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, &key, &value)) { AsComponent *cpt; const gchar *cdid; cpt = AS_COMPONENT (value); cdid = (const gchar*) key; /* validate the component */ if (!as_component_is_valid (cpt)) { g_debug ("WARNING: Ignored component '%s': The component is invalid.", as_component_get_id (cpt)); ret = FALSE; continue; } /* set the "addons" information */ as_pool_update_addon_info (pool, cpt); /* add to results table */ g_hash_table_insert (refined_cpts, g_strdup (cdid), g_object_ref (cpt)); } /* set refined components as new pool content */ g_hash_table_unref (priv->cpt_table); priv->cpt_table = refined_cpts; return ret; }
/** * as_data_pool_get_components_by_provided_item: * @dpool: An instance of #AsDataPool. * @kind: An #AsProvidesKind * @item: The value of the provided item. * @error: A #GError or %NULL. * * Find components in the AppStream data pool whcih provide a certain item. * * Returns: (element-type AsComponent) (transfer full): an array of #AsComponent objects which have been found. */ GPtrArray* as_data_pool_get_components_by_provided_item (AsDataPool *dpool, AsProvidedKind kind, const gchar *item, GError **error) { AsDataPoolPrivate *priv = GET_PRIVATE (dpool); GHashTableIter iter; gpointer value; GPtrArray *results; if (item == NULL) { g_set_error_literal (error, AS_DATA_POOL_ERROR, AS_DATA_POOL_ERROR_TERM_INVALID, "Search term must not be NULL."); return NULL; } results = g_ptr_array_new_with_free_func (g_object_unref); g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { g_autoptr(GList) provided = NULL; GList *l; AsComponent *cpt = AS_COMPONENT (value); provided = as_component_get_provided (cpt); for (l = provided; l != NULL; l = l->next) { AsProvided *prov = AS_PROVIDED (l->data); if (kind != AS_PROVIDED_KIND_UNKNOWN) { /* check if the kind matches. an unknown kind matches all provides types */ if (as_provided_get_kind (prov) != kind) continue; } if (as_provided_has_item (prov, item)) g_ptr_array_add (results, g_object_ref (cpt)); } } return results; }
/** * as_data_pool_get_components_by_categories: * @dpool: An instance of #AsDatabase. * @categories: A semicolon-separated list of XDG categories to include. * * Return a list of components which are in one of the categories. * * Returns: (element-type AsComponent) (transfer full): an array of #AsComponent objects which have been found. */ GPtrArray* as_data_pool_get_components_by_categories (AsDataPool *dpool, const gchar *categories) { AsDataPoolPrivate *priv = GET_PRIVATE (dpool); GHashTableIter iter; gpointer value; g_auto(GStrv) cats = NULL; guint i; GPtrArray *results; cats = g_strsplit (categories, ";", -1); results = g_ptr_array_new_with_free_func (g_object_unref); /* sanity check */ for (i = 0; cats[i] != NULL; i++) { if (!as_utils_is_category_name (cats[i])) { g_warning ("'%s' is not a valid XDG category name, search results might be invalid or empty.", cats[i]); } } g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { gchar **cpt_cats; guint j; AsComponent *cpt = AS_COMPONENT (value); cpt_cats = as_component_get_categories (cpt); if (cpt_cats == NULL) continue; for (i = 0; cats[i] != NULL; i++) { for (j = 0; cpt_cats[j] != NULL; j++) { if (g_strcmp0 (cats[i], cpt_cats[j]) == 0) g_ptr_array_add (results, g_object_ref (cpt)); } } } return results; }
/** * as_pool_get_components_by_kind: * @pool: An instance of #AsDatabase. * @kind: An #AsComponentKind. * * Return a list of all components in the pool which are of a certain kind. * * Returns: (transfer container) (element-type AsComponent): an array of #AsComponent objects which have been found. */ GPtrArray* as_pool_get_components_by_kind (AsPool *pool, AsComponentKind kind) { AsPoolPrivate *priv = GET_PRIVATE (pool); GHashTableIter iter; gpointer value; GPtrArray *results; /* sanity check */ g_return_val_if_fail ((kind < AS_COMPONENT_KIND_LAST) && (kind > AS_COMPONENT_KIND_UNKNOWN), NULL); results = g_ptr_array_new_with_free_func (g_object_unref); g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { AsComponent *cpt = AS_COMPONENT (value); if (as_component_get_kind (cpt) == kind) g_ptr_array_add (results, g_object_ref (cpt)); } return results; }
/** * as_pool_get_components_by_id: * @pool: An instance of #AsPool. * @cid: The AppStream-ID to look for. * * Get a specific component by its ID. * This function may contain multiple results if we have * data describing this component from multiple scopes/origin types. * * Returns: (transfer container) (element-type AsComponent): An #AsComponent */ GPtrArray* as_pool_get_components_by_id (AsPool *pool, const gchar *cid) { AsPoolPrivate *priv = GET_PRIVATE (pool); GPtrArray *result; GHashTableIter iter; gpointer value; result = g_ptr_array_new_with_free_func (g_object_unref); if (cid == NULL) return result; g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { AsComponent *cpt = AS_COMPONENT (value); if (g_strcmp0 (as_component_get_id (cpt), cid) == 0) g_ptr_array_add (result, g_object_ref (cpt)); } return result; }
/** * as_pool_search: * @pool: An instance of #AsPool * @search: A search string * * Search for a list of components matching the search terms. * The list will be unordered. * * Returns: (transfer container) (element-type AsComponent): an array of the found #AsComponent objects. * * Since: 0.9.7 */ GPtrArray* as_pool_search (AsPool *pool, const gchar *search) { AsPoolPrivate *priv = GET_PRIVATE (pool); g_auto(GStrv) terms = NULL; GPtrArray *results; GHashTableIter iter; gpointer value; /* sanitize user's search term */ terms = as_pool_build_search_terms (pool, search); results = g_ptr_array_new_with_free_func (g_object_unref); if (terms == NULL) { g_debug ("Search term invalid. Matching everything."); } else { g_autofree gchar *tmp_str = NULL; tmp_str = g_strjoinv (" ", terms); g_debug ("Searching for: %s", tmp_str); } g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { guint score; AsComponent *cpt = AS_COMPONENT (value); score = as_component_search_matches_all (cpt, terms); if (score == 0) continue; g_ptr_array_add (results, g_object_ref (cpt)); } /* sort the results by their priority */ g_ptr_array_sort (results, as_sort_components_by_score_cb); return results; }
/** * as_data_pool_get_components_by_kind: * @dpool: An instance of #AsDatabase. * @kind: An #AsComponentKind. * @error: A #GError or %NULL. * * Return a list of all components in the pool which are of a certain kind. * * Returns: (element-type AsComponent) (transfer full): an array of #AsComponent objects which have been found. */ GPtrArray* as_data_pool_get_components_by_kind (AsDataPool *dpool, AsComponentKind kind, GError **error) { AsDataPoolPrivate *priv = GET_PRIVATE (dpool); GHashTableIter iter; gpointer value; GPtrArray *results; if (kind >= AS_COMPONENT_KIND_LAST) { g_set_error_literal (error, AS_DATA_POOL_ERROR, AS_DATA_POOL_ERROR_TERM_INVALID, _("Can not search for unknown component type.")); return NULL; } if (kind == AS_COMPONENT_KIND_UNKNOWN) { g_set_error_literal (error, AS_DATA_POOL_ERROR, AS_DATA_POOL_ERROR_TERM_INVALID, _("Can not search for unknown component type.")); return NULL; } results = g_ptr_array_new_with_free_func (g_object_unref); g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { AsComponent *cpt = AS_COMPONENT (value); if (as_component_get_kind (cpt) == kind) g_ptr_array_add (results, g_object_ref (cpt)); } return results; }
/** * as_pool_get_components_by_provided_item: * @pool: An instance of #AsPool. * @kind: An #AsProvidesKind * @item: The value of the provided item. * * Find components in the AppStream data pool whcih provide a certain item. * * Returns: (transfer container) (element-type AsComponent): an array of #AsComponent objects which have been found. */ GPtrArray* as_pool_get_components_by_provided_item (AsPool *pool, AsProvidedKind kind, const gchar *item) { AsPoolPrivate *priv = GET_PRIVATE (pool); GHashTableIter iter; gpointer value; GPtrArray *results; /* sanity check */ g_return_val_if_fail (item != NULL, NULL); results = g_ptr_array_new_with_free_func (g_object_unref); g_hash_table_iter_init (&iter, priv->cpt_table); while (g_hash_table_iter_next (&iter, NULL, &value)) { GPtrArray *provided = NULL; guint i; AsComponent *cpt = AS_COMPONENT (value); provided = as_component_get_provided (cpt); for (i = 0; i < provided->len; i++) { AsProvided *prov = AS_PROVIDED (g_ptr_array_index (provided, i)); if (kind != AS_PROVIDED_KIND_UNKNOWN) { /* check if the kind matches. an unknown kind matches all provides types */ if (as_provided_get_kind (prov) != kind) continue; } if (as_provided_has_item (prov, item)) g_ptr_array_add (results, g_object_ref (cpt)); } } return results; }
/** * as_pool_load_metadata: * * Load fresh metadata from AppStream directories. */ static gboolean as_pool_load_metadata (AsPool *pool) { GPtrArray *cpts; g_autoptr(GPtrArray) merge_cpts = NULL; guint i; gboolean ret; g_autoptr(AsMetadata) metad = NULL; g_autoptr(GPtrArray) mdata_files = NULL; GError *error = NULL; AsPoolPrivate *priv = GET_PRIVATE (pool); /* prepare metadata parser */ metad = as_metadata_new (); as_metadata_set_format_style (metad, AS_FORMAT_STYLE_COLLECTION); as_metadata_set_locale (metad, priv->locale); /* find AppStream metadata */ ret = TRUE; mdata_files = g_ptr_array_new_with_free_func (g_free); /* find XML data */ for (i = 0; i < priv->xml_dirs->len; i++) { const gchar *xml_path = (const gchar *) g_ptr_array_index (priv->xml_dirs, i); guint j; if (g_file_test (xml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) xmls = NULL; g_debug ("Searching for data in: %s", xml_path); xmls = as_utils_find_files_matching (xml_path, "*.xml*", FALSE, NULL); if (xmls != NULL) { for (j = 0; j < xmls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (xmls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } } /* find YAML metadata */ for (i = 0; i < priv->yaml_dirs->len; i++) { const gchar *yaml_path = (const gchar *) g_ptr_array_index (priv->yaml_dirs, i); guint j; if (g_file_test (yaml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) yamls = NULL; g_debug ("Searching for data in: %s", yaml_path); yamls = as_utils_find_files_matching (yaml_path, "*.yml*", FALSE, NULL); if (yamls != NULL) { for (j = 0; j < yamls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (yamls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } } /* parse the found data */ for (i = 0; i < mdata_files->len; i++) { g_autoptr(GFile) infile = NULL; const gchar *fname; fname = (const gchar*) g_ptr_array_index (mdata_files, i); g_debug ("Reading: %s", fname); infile = g_file_new_for_path (fname); if (!g_file_query_exists (infile, NULL)) { g_warning ("Metadata file '%s' does not exist.", fname); continue; } as_metadata_parse_file (metad, infile, AS_FORMAT_KIND_UNKNOWN, &error); if (error != NULL) { g_debug ("WARNING: %s", error->message); g_error_free (error); error = NULL; ret = FALSE; } } /* add found components to the metadata pool */ cpts = as_metadata_get_components (metad); merge_cpts = g_ptr_array_new (); for (i = 0; i < cpts->len; i++) { AsComponent *cpt = AS_COMPONENT (g_ptr_array_index (cpts, i)); /* deal with merge-components later */ if (as_component_get_merge_kind (cpt) != AS_MERGE_KIND_NONE) { g_ptr_array_add (merge_cpts, cpt); continue; } as_pool_add_component (pool, cpt, &error); if (error != NULL) { g_debug ("Metadata ignored: %s", error->message); g_error_free (error); error = NULL; } } /* we need to merge the merge-components into the pool last, so the merge process can fetch * all components with matching IDs from the pool */ for (i = 0; i < merge_cpts->len; i++) { AsComponent *mcpt = AS_COMPONENT (g_ptr_array_index (merge_cpts, i)); as_pool_add_component (pool, mcpt, &error); if (error != NULL) { g_debug ("Merge component ignored: %s", error->message); g_error_free (error); error = NULL; } } return ret; }
/** * as_pool_add_component: * @pool: An instance of #AsPool * @cpt: The #AsComponent to add to the pool. * @error: A #GError or %NULL * * Register a new component in the AppStream metadata pool. * * Returns: %TRUE if the new component was successfully added to the pool. */ gboolean as_pool_add_component (AsPool *pool, AsComponent *cpt, GError **error) { const gchar *cdid = NULL; AsComponent *existing_cpt; gint pool_priority; AsPoolPrivate *priv = GET_PRIVATE (pool); cdid = as_component_get_data_id (cpt); existing_cpt = g_hash_table_lookup (priv->cpt_table, cdid); /* add additional data to the component, e.g. external screenshots. Also refines * the component's icon paths */ as_component_complete (cpt, priv->screenshot_service_url, priv->icon_dirs); if (existing_cpt == NULL) { g_hash_table_insert (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); return TRUE; } /* perform metadata merges if necessary */ if (as_component_get_merge_kind (cpt) != AS_MERGE_KIND_NONE) { g_autoptr(GPtrArray) matches = NULL; guint i; /* we merge the data into all components with matching IDs at time */ matches = as_pool_get_components_by_id (pool, as_component_get_id (cpt)); for (i = 0; i < matches->len; i++) { AsComponent *match = AS_COMPONENT (g_ptr_array_index (matches, i)); as_merge_components (match, cpt); } return TRUE; } /* if we are here, we might have duplicates and no merges, so check if we should replace a component * with data of higher priority, or if we have an actual error in the metadata */ pool_priority = as_component_get_priority (existing_cpt); if (pool_priority < as_component_get_priority (cpt)) { g_hash_table_replace (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); g_debug ("Replaced '%s' with data of higher priority.", cdid); } else { /* bundles are treated specially here */ if ((!as_component_has_bundle (existing_cpt)) && (as_component_has_bundle (cpt))) { GPtrArray *bundles; /* propagate bundle information to existing component */ bundles = as_component_get_bundles (cpt); as_component_set_bundles_array (existing_cpt, bundles); return TRUE; } /* experimental multiarch support */ if (as_component_get_architecture (cpt) != NULL) { if (as_arch_compatible (as_component_get_architecture (cpt), priv->current_arch)) { const gchar *earch; /* this component is compatible with our current architecture */ earch = as_component_get_architecture (existing_cpt); if (earch != NULL) { if (as_arch_compatible (earch, priv->current_arch)) { g_hash_table_replace (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); g_debug ("Preferred component for native architecture for %s (was %s)", cdid, earch); return TRUE; } else { g_debug ("Ignored additional entry for '%s' on architecture %s.", cdid, earch); return FALSE; } } } } if (pool_priority == as_component_get_priority (cpt)) { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with the same priority.", cdid); return FALSE; } else { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with a higher priority.", cdid); return FALSE; } } return TRUE; }
/** * as_data_pool_load_metadata: * * Load fresh metadata from AppStream directories. */ gboolean as_data_pool_load_metadata (AsDataPool *dpool) { GPtrArray *cpts; guint i; gboolean ret; g_autoptr(AsMetadata) metad = NULL; GError *error = NULL; AsDataPoolPrivate *priv = GET_PRIVATE (dpool); /* prepare metadata parser */ metad = as_metadata_new (); as_metadata_set_parser_mode (metad, AS_PARSER_MODE_DISTRO); as_metadata_set_locale (metad, priv->locale); /* find AppStream XML and YAML metadata */ ret = TRUE; for (i = 0; i < priv->mdata_dirs->len; i++) { const gchar *root_path; g_autofree gchar *xml_path = NULL; g_autofree gchar *yaml_path = NULL; g_autoptr(GPtrArray) mdata_files = NULL; gboolean subdir_found = FALSE; guint j; root_path = (const gchar *) g_ptr_array_index (priv->mdata_dirs, i); if (!g_file_test (root_path, G_FILE_TEST_EXISTS)) continue; xml_path = g_build_filename (root_path, "xmls", NULL); yaml_path = g_build_filename (root_path, "yaml", NULL); mdata_files = g_ptr_array_new_with_free_func (g_free); /* find XML data */ if (g_file_test (xml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) xmls = NULL; subdir_found = TRUE; g_debug ("Searching for data in: %s", xml_path); xmls = as_utils_find_files_matching (xml_path, "*.xml*", FALSE, NULL); if (xmls != NULL) { for (j = 0; j < xmls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (xmls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } /* find YAML data */ if (g_file_test (yaml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) yamls = NULL; subdir_found = TRUE; g_debug ("Searching for data in: %s", yaml_path); yamls = as_utils_find_files_matching (yaml_path, "*.yml*", FALSE, NULL); if (yamls != NULL) { for (j = 0; j < yamls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (yamls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } if (!subdir_found) { g_debug ("No metadata directories found in '%s'", root_path); continue; } /* parse the found data */ for (j = 0; j < mdata_files->len; j++) { g_autoptr(GFile) infile = NULL; const gchar *fname; fname = (const gchar*) g_ptr_array_index (mdata_files, j); g_debug ("Reading: %s", fname); infile = g_file_new_for_path (fname); if (!g_file_query_exists (infile, NULL)) { g_warning ("Metadata file '%s' does not exist.", fname); continue; } as_metadata_parse_file (metad, infile, &error); if (error != NULL) { g_debug ("WARNING: %s", error->message); g_error_free (error); error = NULL; ret = FALSE; } } } cpts = as_metadata_get_components (metad); for (i = 0; i < cpts->len; i++) { as_data_pool_add_component (dpool, AS_COMPONENT (g_ptr_array_index (cpts, i)), &error); if (error != NULL) { g_debug ("Data ignored: %s", error->message); g_error_free (error); error = NULL; } } return ret; }
/** * as_pool_load_desktop_entries: * * Load fresh metadata from .desktop files. */ static void as_pool_load_desktop_entries (AsPool *pool) { GPtrArray *cpts; guint i; g_autoptr(AsMetadata) metad = NULL; g_autoptr(GPtrArray) de_files = NULL; GError *error = NULL; AsPoolPrivate *priv = GET_PRIVATE (pool); /* prepare metadata parser */ metad = as_metadata_new (); as_metadata_set_locale (metad, priv->locale); /* find .desktop files */ g_debug ("Searching for data in: %s", APPLICATIONS_DIR); de_files = as_utils_find_files_matching (APPLICATIONS_DIR, "*.desktop", FALSE, NULL); if (de_files == NULL) { g_debug ("Unable find .desktop files."); return; } /* parse the found data */ for (i = 0; i < de_files->len; i++) { g_autoptr(GFile) infile = NULL; const gchar *fname; fname = (const gchar*) g_ptr_array_index (de_files, i); g_debug ("Reading: %s", fname); infile = g_file_new_for_path (fname); if (!g_file_query_exists (infile, NULL)) { g_warning ("Metadata file '%s' does not exist.", fname); continue; } as_metadata_parse_file (metad, infile, AS_FORMAT_KIND_UNKNOWN, &error); if (error != NULL) { g_debug ("WARNING: %s", error->message); g_error_free (error); error = NULL; } } /* add found components to the metadata pool */ cpts = as_metadata_get_components (metad); for (i = 0; i < cpts->len; i++) { AsComponent *cpt = AS_COMPONENT (g_ptr_array_index (cpts, i)); /* We only read .desktop files from system directories at time */ as_component_set_scope (cpt, AS_COMPONENT_SCOPE_SYSTEM); as_pool_add_component_internal (pool, cpt, FALSE, &error); if (error != NULL) { g_debug ("Metadata ignored: %s", error->message); g_error_free (error); error = NULL; } } }
/** * as_pool_load_appstream: * * Load fresh metadata from AppStream directories. */ static gboolean as_pool_load_appstream (AsPool *pool, GError **error) { GPtrArray *cpts; g_autoptr(GPtrArray) merge_cpts = NULL; guint i; gboolean ret; g_autoptr(AsMetadata) metad = NULL; g_autoptr(GPtrArray) mdata_files = NULL; GError *tmp_error = NULL; AsPoolPrivate *priv = GET_PRIVATE (pool); /* see if we can use the caches */ if (!as_pool_metadata_changed (pool)) { g_autofree gchar *fname = NULL; g_debug ("Caches are up to date."); if (as_flags_contains (priv->cache_flags, AS_CACHE_FLAG_USE_SYSTEM)) { g_debug ("Using cached data."); fname = g_strdup_printf ("%s/%s.gvz", priv->sys_cache_path, priv->locale); if (g_file_test (fname, G_FILE_TEST_EXISTS)) { return as_pool_load_cache_file (pool, fname, error); } else { g_debug ("Missing cache for language '%s', attempting to load fresh data.", priv->locale); } } else { g_debug ("Not using system cache."); } } /* prepare metadata parser */ metad = as_metadata_new (); as_metadata_set_format_style (metad, AS_FORMAT_STYLE_COLLECTION); as_metadata_set_locale (metad, priv->locale); /* find AppStream metadata */ ret = TRUE; mdata_files = g_ptr_array_new_with_free_func (g_free); /* find XML data */ for (i = 0; i < priv->xml_dirs->len; i++) { const gchar *xml_path = (const gchar *) g_ptr_array_index (priv->xml_dirs, i); guint j; if (g_file_test (xml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) xmls = NULL; g_debug ("Searching for data in: %s", xml_path); xmls = as_utils_find_files_matching (xml_path, "*.xml*", FALSE, NULL); if (xmls != NULL) { for (j = 0; j < xmls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (xmls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } } /* find YAML metadata */ for (i = 0; i < priv->yaml_dirs->len; i++) { const gchar *yaml_path = (const gchar *) g_ptr_array_index (priv->yaml_dirs, i); guint j; if (g_file_test (yaml_path, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) yamls = NULL; g_debug ("Searching for data in: %s", yaml_path); yamls = as_utils_find_files_matching (yaml_path, "*.yml*", FALSE, NULL); if (yamls != NULL) { for (j = 0; j < yamls->len; j++) { const gchar *val; val = (const gchar *) g_ptr_array_index (yamls, j); g_ptr_array_add (mdata_files, g_strdup (val)); } } } } /* parse the found data */ for (i = 0; i < mdata_files->len; i++) { g_autoptr(GFile) infile = NULL; const gchar *fname; fname = (const gchar*) g_ptr_array_index (mdata_files, i); g_debug ("Reading: %s", fname); infile = g_file_new_for_path (fname); if (!g_file_query_exists (infile, NULL)) { g_warning ("Metadata file '%s' does not exist.", fname); continue; } as_metadata_parse_file (metad, infile, AS_FORMAT_KIND_UNKNOWN, &tmp_error); if (tmp_error != NULL) { g_debug ("WARNING: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; ret = FALSE; } } /* add found components to the metadata pool */ cpts = as_metadata_get_components (metad); merge_cpts = g_ptr_array_new (); for (i = 0; i < cpts->len; i++) { AsComponent *cpt = AS_COMPONENT (g_ptr_array_index (cpts, i)); /* TODO: We support only system components at time */ as_component_set_scope (cpt, AS_COMPONENT_SCOPE_SYSTEM); /* deal with merge-components later */ if (as_component_get_merge_kind (cpt) != AS_MERGE_KIND_NONE) { g_ptr_array_add (merge_cpts, cpt); continue; } as_pool_add_component (pool, cpt, &tmp_error); if (tmp_error != NULL) { g_debug ("Metadata ignored: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; } } /* we need to merge the merge-components into the pool last, so the merge process can fetch * all components with matching IDs from the pool */ for (i = 0; i < merge_cpts->len; i++) { AsComponent *mcpt = AS_COMPONENT (g_ptr_array_index (merge_cpts, i)); as_pool_add_component (pool, mcpt, &tmp_error); if (tmp_error != NULL) { g_debug ("Merge component ignored: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; } } return ret; }
/** * as_pool_add_component_internal: * @pool: An instance of #AsPool * @cpt: The #AsComponent to add to the pool. * @pedantic_noadd: If %TRUE, always emit an error if component couldn't be added. * @error: A #GError or %NULL * * Internal. */ static gboolean as_pool_add_component_internal (AsPool *pool, AsComponent *cpt, gboolean pedantic_noadd, GError **error) { const gchar *cdid = NULL; AsComponent *existing_cpt; gint pool_priority; AsPoolPrivate *priv = GET_PRIVATE (pool); cdid = as_component_get_data_id (cpt); if (as_component_is_ignored (cpt)) { if (pedantic_noadd) g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_FAILED, "Skipping '%s' from inclusion into the pool: Component is ignored.", cdid); return FALSE; } existing_cpt = g_hash_table_lookup (priv->cpt_table, cdid); if (as_component_get_origin_kind (cpt) == AS_ORIGIN_KIND_DESKTOP_ENTRY) { g_autofree gchar *tmp_cdid = NULL; /* .desktop entries might map to existing metadata data with or without .desktop suffix, we need to check for that. * (the .desktop suffix is optional for desktop-application metainfo files, and the desktop-entry parser will automatically * omit it if the desktop-entry-id is following the reverse DNS scheme) */ if (existing_cpt == NULL) { tmp_cdid = g_strdup_printf ("%s.desktop", cdid); existing_cpt = g_hash_table_lookup (priv->cpt_table, tmp_cdid); } } if (existing_cpt == NULL) { /* add additional data to the component, e.g. external screenshots. Also refines * the component's icon paths */ as_component_complete (cpt, priv->screenshot_service_url, priv->icon_dirs); g_hash_table_insert (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); return TRUE; } /* perform metadata merges if necessary */ if (as_component_get_merge_kind (cpt) != AS_MERGE_KIND_NONE) { g_autoptr(GPtrArray) matches = NULL; guint i; /* we merge the data into all components with matching IDs at time */ matches = as_pool_get_components_by_id (pool, as_component_get_id (cpt)); for (i = 0; i < matches->len; i++) { AsComponent *match = AS_COMPONENT (g_ptr_array_index (matches, i)); as_merge_components (match, cpt); } return TRUE; } /* if we are here, we might have duplicates and no merges, so check if we should replace a component * with data of higher priority, or if we have an actual error in the metadata */ pool_priority = as_component_get_priority (existing_cpt); if (pool_priority < as_component_get_priority (cpt)) { g_hash_table_replace (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); g_debug ("Replaced '%s' with data of higher priority.", cdid); } else { /* bundles are treated specially here */ if ((!as_component_has_bundle (existing_cpt)) && (as_component_has_bundle (cpt))) { GPtrArray *bundles; /* propagate bundle information to existing component */ bundles = as_component_get_bundles (cpt); as_component_set_bundles_array (existing_cpt, bundles); return TRUE; } /* experimental multiarch support */ if (as_component_get_architecture (cpt) != NULL) { if (as_arch_compatible (as_component_get_architecture (cpt), priv->current_arch)) { const gchar *earch; /* this component is compatible with our current architecture */ earch = as_component_get_architecture (existing_cpt); if (earch != NULL) { if (as_arch_compatible (earch, priv->current_arch)) { g_hash_table_replace (priv->cpt_table, g_strdup (cdid), g_object_ref (cpt)); g_debug ("Preferred component for native architecture for %s (was %s)", cdid, earch); return TRUE; } else { g_debug ("Ignored additional entry for '%s' on architecture %s.", cdid, earch); return FALSE; } } } } if (pool_priority == as_component_get_priority (cpt)) { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with the same priority.", cdid); return FALSE; } else { if (pedantic_noadd) g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with a higher priority.", cdid); return FALSE; } } return TRUE; }