/** * as_pool_load: * @pool: An instance of #AsPool. * @error: A #GError or %NULL. * * Builds an index of all found components in the watched locations. * The function will try to get as much data into the pool as possible, so even if * the update completes with %FALSE, it might still have added components to the pool. * * The function will load from all possible data sources, preferring caches if they * are up to date. * * Returns: %TRUE if update completed without error. **/ gboolean as_pool_load (AsPool *pool, GCancellable *cancellable, GError **error) { gboolean ret; gboolean ret2; AsPoolPrivate *priv = GET_PRIVATE (pool); /* load means to reload, so we get rid of all the old data */ if (g_hash_table_size (priv->cpt_table) > 0) { g_hash_table_unref (priv->cpt_table); priv->cpt_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); } 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."); } } /* read all AppStream metadata that we can find */ ret = as_pool_load_metadata (pool); /* automatically refine the metadata we have in the pool */ ret2 = as_pool_refine_data (pool); return ret && ret2; }
/** * as_pool_refresh_cache: * @pool: An instance of #AsPool. * @force: Enforce refresh, even if source data has not changed. * * Update the AppStream cache. There is normally no need to call this function manually, because cache updates are handled * transparently in the background. * * Returns: %TRUE if the cache was updated, %FALSE on error or if the cache update was not necessary and has been skipped. */ gboolean as_pool_refresh_cache (AsPool *pool, gboolean force, GError **error) { AsPoolPrivate *priv = GET_PRIVATE (pool); gboolean ret = FALSE; gboolean ret_poolupdate; g_autofree gchar *cache_fname = NULL; g_autoptr(GError) tmp_error = NULL; /* try to create cache directory, in case it doesn't exist */ g_mkdir_with_parents (priv->sys_cache_path, 0755); if (!as_utils_is_writable (priv->sys_cache_path)) { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_TARGET_NOT_WRITABLE, _("Cache location '%s' is not writable."), priv->sys_cache_path); return FALSE; } /* collect metadata */ #ifdef HAVE_APT_SUPPORT /* currently, we only do something here if we are running with explicit APT support compiled in */ as_pool_scan_apt (pool, force, &tmp_error); if (tmp_error != NULL) { /* the exact error is not forwarded here, since we might be able to partially update the cache */ g_warning ("Error while collecting metadata: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; } #endif /* create the filename of our cache */ cache_fname = g_strdup_printf ("%s/%s.gvz", priv->sys_cache_path, priv->locale); /* check if we need to refresh the cache * (which is only necessary if the AppStream data has changed) */ if (!as_pool_metadata_changed (pool)) { g_debug ("Data did not change, no cache refresh needed."); if (force) { g_debug ("Forcing refresh anyway."); } else { return FALSE; } } g_debug ("Refreshing AppStream cache"); /* find them wherever they are */ ret_poolupdate = as_pool_load (pool, NULL, &tmp_error); if (tmp_error != NULL) { /* the exact error is not forwarded here, since we might be able to partially update the cache */ g_warning ("Error while updating the in-memory data pool: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; } /* save the cache object */ as_pool_save_cache_file (pool, cache_fname, &tmp_error); if (tmp_error != NULL) { /* the exact error is not forwarded here, since we might be able to partially update the cache */ g_warning ("Error while updating the cache: %s", tmp_error->message); g_error_free (tmp_error); tmp_error = NULL; ret = FALSE; } else { ret = TRUE; } if (ret) { if (!ret_poolupdate) { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_INCOMPLETE, _("AppStream data pool was loaded, but some metadata was ignored due to errors.")); } /* update the cache mtime, to not needlessly rebuild it again */ as_touch_location (cache_fname); as_pool_check_cache_ctime (pool); } else { g_set_error (error, AS_POOL_ERROR, AS_POOL_ERROR_FAILED, _("AppStream cache update failed.")); } return TRUE; }
/** * 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; }