/** * as_data_pool_add_component: * @dpool: An instance of #AsDataPool * @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_data_pool_add_component (AsDataPool *dpool, AsComponent *cpt, GError **error) { const gchar *cpt_id; AsComponent *existing_cpt; int priority; AsDataPoolPrivate *priv = GET_PRIVATE (dpool); g_return_val_if_fail (cpt != NULL, FALSE); cpt_id = as_component_get_id (cpt); existing_cpt = g_hash_table_lookup (priv->cpt_table, cpt_id); /* 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_paths); if (existing_cpt == NULL) { g_hash_table_insert (priv->cpt_table, g_strdup (cpt_id), g_object_ref (cpt)); return TRUE; } /* if we are here, we have duplicates */ priority = as_component_get_priority (existing_cpt); if (priority < as_component_get_priority (cpt)) { g_hash_table_replace (priv->cpt_table, g_strdup (cpt_id), g_object_ref (cpt)); g_debug ("Replaced '%s' with data of higher priority.", cpt_id); } else { gboolean ecpt_has_name; gboolean ncpt_has_name; if ((!as_component_has_bundle (existing_cpt)) && (as_component_has_bundle (cpt))) { GHashTable *bundles; /* propagate bundle information to existing component */ bundles = as_component_get_bundles_table (cpt); as_component_set_bundles_table (existing_cpt, bundles); return TRUE; } ecpt_has_name = as_component_get_name (existing_cpt) != NULL; ncpt_has_name = as_component_get_name (cpt) != NULL; if ((ecpt_has_name) && (!ncpt_has_name)) { /* existing component is updated with data from the new one */ as_data_pool_merge_components (dpool, cpt, existing_cpt); g_debug ("Merged stub data for component %s (<-, based on name)", cpt_id); return TRUE; } if ((!ecpt_has_name) && (ncpt_has_name)) { /* new component is updated with data from the existing component, * then it replaces the prior metadata */ as_data_pool_merge_components (dpool, existing_cpt, cpt); g_hash_table_replace (priv->cpt_table, g_strdup (cpt_id), g_object_ref (cpt)); g_debug ("Merged stub data for component %s (->, based on name)", cpt_id); return TRUE; } 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 (cpt_id), g_object_ref (cpt)); g_debug ("Preferred component for native architecture for %s (was %s)", cpt_id, earch); return TRUE; } else { g_debug ("Ignored additional entry for '%s' on architecture %s.", cpt_id, earch); return FALSE; } } } } if (priority == as_component_get_priority (cpt)) { g_set_error (error, AS_DATA_POOL_ERROR, AS_DATA_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with the same priority.", cpt_id); return FALSE; } else { g_set_error (error, AS_DATA_POOL_ERROR, AS_DATA_POOL_ERROR_COLLISION, "Detected colliding ids: %s was already added with a higher priority.", cpt_id); return FALSE; } } return TRUE; }
/** * 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_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; }