/** * as_utils_find_files: */ GPtrArray* as_utils_find_files (const gchar *dir, gboolean recursive, GError **error) { GPtrArray* res = NULL; g_return_val_if_fail (dir != NULL, NULL); res = as_utils_find_files_matching (dir, "", recursive, error); return res; }
/** * as_pool_scan_apt: * * Scan for additional metadata in 3rd-party directories and move it to the right place. */ void as_pool_scan_apt (AsPool *pool, gboolean force, GError **error) { const gchar *apt_lists_dir = "/var/lib/apt/lists/"; const gchar *appstream_yml_target = "/var/lib/app-info/yaml"; const gchar *appstream_icons_target = "/var/lib/app-info/icons"; g_autoptr(GPtrArray) yml_files = NULL; g_autoptr(GError) tmp_error = NULL; gboolean data_changed = FALSE; guint i; /* skip this step if the APT lists directory doesn't exist */ if (!g_file_test (apt_lists_dir, G_FILE_TEST_IS_DIR)) { g_debug ("APT lists directory (%s) not found!", apt_lists_dir); return; } if (g_file_test (appstream_yml_target, G_FILE_TEST_IS_DIR)) { g_autoptr(GPtrArray) ytfiles = NULL; /* we can't modify the files here if we don't have write access */ if (!as_utils_is_writable (appstream_yml_target)) { g_debug ("Unable to write to '%s': Can't add AppStream data from APT to the pool.", appstream_yml_target); return; } ytfiles = as_utils_find_files_matching (appstream_yml_target, "*", FALSE, &tmp_error); if (tmp_error != NULL) { g_warning ("Could not scan for broken symlinks in DEP-11 target: %s", tmp_error->message); return; } for (i = 0; i < ytfiles->len; i++) { const gchar *fname = (const gchar*) g_ptr_array_index (ytfiles, i); if (!g_file_test (fname, G_FILE_TEST_EXISTS)) { g_remove (fname); data_changed = TRUE; } } } yml_files = as_utils_find_files_matching (apt_lists_dir, "*Components-*.yml.gz", FALSE, &tmp_error); if (tmp_error != NULL) { g_warning ("Could not scan for APT-downloaded DEP-11 files: %s", tmp_error->message); return; } /* no data found? skip scan step */ if (yml_files->len <= 0) { g_debug ("Couldn't find DEP-11 data in APT directories."); return; } /* We have to check if our metadata is in the target directory at all, and - if not - trigger a cache refresh. * This is needed because APT is putting files with the *server* ctime/mtime into it's lists directory, * and that time might be lower than the time the metadata cache was last updated, which may result * in no cache update being triggered at all. */ for (i = 0; i < yml_files->len; i++) { g_autofree gchar *fbasename = NULL; g_autofree gchar *dest_fname = NULL; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); fbasename = g_path_get_basename (fname); dest_fname = g_build_filename (appstream_yml_target, fbasename, NULL); if (!g_file_test (dest_fname, G_FILE_TEST_EXISTS)) { data_changed = TRUE; g_debug ("File '%s' missing, cache update is needed.", dest_fname); break; } } /* get the last time we touched the database */ if (!data_changed) { for (i = 0; i < yml_files->len; i++) { struct stat sb; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); if (stat (fname, &sb) < 0) continue; if (sb.st_ctime > as_pool_get_cache_age (pool)) { /* we need to update the cache */ data_changed = TRUE; break; } } } /* no changes means nothing to do here */ if ((!data_changed) && (!force)) return; /* this is not really great, but we simply can't detect if we should remove an icons folder or not, * or which specific icons we should drop from a folder. * So, we hereby simply "own" the icons directory and all it's contents, anything put in there by 3rd-parties will * be deleted. * (And there should actually be no cases 3rd-parties put icons there on a Debian machine, since metadata in packages * will land in /usr/share/app-info anyway) */ as_utils_delete_dir_recursive (appstream_icons_target); if (g_mkdir_with_parents (appstream_yml_target, 0755) > 0) { g_debug ("Unable to create '%s': %s", appstream_yml_target, g_strerror (errno)); return; } for (i = 0; i < yml_files->len; i++) { g_autofree gchar *fbasename = NULL; g_autofree gchar *dest_fname = NULL; g_autofree gchar *origin = NULL; g_autofree gchar *file_baseprefix = NULL; const gchar *fname = (const gchar*) g_ptr_array_index (yml_files, i); fbasename = g_path_get_basename (fname); dest_fname = g_build_filename (appstream_yml_target, fbasename, NULL); if (!g_file_test (fname, G_FILE_TEST_EXISTS)) { /* broken symlinks in the dest will have been removed earlier */ g_debug ("File %s is a broken symlink, skipping.", fname); continue; } else if (!g_file_test (dest_fname, G_FILE_TEST_EXISTS)) { /* file not found, let's symlink */ if (symlink (fname, dest_fname) != 0) { g_debug ("Unable to set symlink (%s -> %s): %s", fname, dest_fname, g_strerror (errno)); continue; } } else if (!g_file_test (dest_fname, G_FILE_TEST_IS_SYMLINK)) { /* file found, but it isn't a symlink, try to rescue */ g_debug ("Regular file '%s' found, which doesn't belong there. Removing it.", dest_fname); g_remove (dest_fname); continue; } /* get DEP-11 data origin */ origin = as_get_yml_data_origin (dest_fname); if (origin == NULL) { g_warning ("No origin found for file %s", fbasename); continue; } /* get base prefix for this file in the APT download cache */ file_baseprefix = g_strndup (fbasename, strlen (fbasename) - strlen (g_strrstr (fbasename, "_") + 1)); /* extract icons to their destination (if they exist at all */ as_extract_icon_cache_tarball (appstream_icons_target, origin, file_baseprefix, apt_lists_dir, "64x64"); as_extract_icon_cache_tarball (appstream_icons_target, origin, file_baseprefix, apt_lists_dir, "128x128"); } /* ensure the cache-rebuild process notices these changes */ as_touch_location (appstream_yml_target); }
/** * 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_utils_find_files_matching: */ GPtrArray* as_utils_find_files_matching (const gchar* dir, const gchar* pattern, gboolean recursive, GError **error) { GPtrArray *list; GFileInfo *file_info; GFileEnumerator *enumerator = NULL; GFile *fdir; GError *tmp_error = NULL; g_return_val_if_fail (dir != NULL, NULL); g_return_val_if_fail (pattern != NULL, NULL); list = g_ptr_array_new_with_free_func (g_free); fdir = g_file_new_for_path (dir); enumerator = g_file_enumerate_children (fdir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &tmp_error); if (tmp_error != NULL) goto out; while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &tmp_error)) != NULL) { g_autofree gchar *path = NULL; if (tmp_error != NULL) { g_object_unref (file_info); break; } if (g_file_info_get_is_hidden (file_info)) { g_object_unref (file_info); continue; } path = g_build_filename (dir, g_file_info_get_name (file_info), NULL); if ((!g_file_test (path, G_FILE_TEST_IS_REGULAR)) && (recursive)) { GPtrArray *subdir_list; guint i; subdir_list = as_utils_find_files_matching (path, pattern, recursive, &tmp_error); /* if there was an error, exit */ if (subdir_list == NULL) { g_ptr_array_unref (list); list = NULL; g_object_unref (file_info); break; } for (i=0; i<subdir_list->len; i++) g_ptr_array_add (list, g_strdup ((gchar *) g_ptr_array_index (subdir_list, i))); g_ptr_array_unref (subdir_list); } else { if (!as_str_empty (pattern)) { if (!g_pattern_match_simple (pattern, g_file_info_get_name (file_info))) { g_object_unref (file_info); continue; } } g_ptr_array_add (list, path); path = NULL; } g_object_unref (file_info); } out: g_object_unref (fdir); if (enumerator != NULL) g_object_unref (enumerator); if (tmp_error != NULL) { if (error == NULL) g_debug ("Error while searching for files in %s: %s", dir, tmp_error->message); else g_propagate_error (error, tmp_error); g_ptr_array_unref (list); return NULL; } return list; }
/** * as_validator_validate_tree: * @validator: An instance of #AsValidator. * @root_dir: The root directory of the filesystem tree that should be validated. * * Validate a full directory tree for issues in AppStream metadata. **/ gboolean as_validator_validate_tree (AsValidator *validator, const gchar *root_dir) { g_autofree gchar *metainfo_dir = NULL; g_autofree gchar *legacy_metainfo_dir = NULL; g_autofree gchar *apps_dir = NULL; g_autoptr(GPtrArray) mfiles = NULL; g_autoptr(GPtrArray) mfiles_legacy = NULL; g_autoptr(GPtrArray) dfiles = NULL; GHashTable *dfilenames = NULL; GHashTable *validated_cpts = NULL; guint i; gboolean ret = TRUE; g_autoptr(AsXMLData) xdt = NULL; struct MInfoCheckData ht_helper; /* cleanup */ as_validator_clear_issues (validator); metainfo_dir = g_build_filename (root_dir, "usr", "share", "metainfo", NULL); legacy_metainfo_dir = g_build_filename (root_dir, "usr", "share", "appdata", NULL); apps_dir = g_build_filename (root_dir, "usr", "share", "applications", NULL); /* check if we actually have a directory which could hold metadata */ if ((!g_file_test (metainfo_dir, G_FILE_TEST_IS_DIR)) && (!g_file_test (legacy_metainfo_dir, G_FILE_TEST_IS_DIR))) { as_validator_add_issue (validator, NULL, AS_ISSUE_IMPORTANCE_INFO, AS_ISSUE_KIND_FILE_MISSING, "No AppStream metadata was found."); goto out; } /* check if we actually have a directory which could hold application information */ if (!g_file_test (apps_dir, G_FILE_TEST_IS_DIR)) { as_validator_add_issue (validator, NULL, AS_ISSUE_IMPORTANCE_PEDANTIC, /* pedantic because not everything which has metadata is an application */ AS_ISSUE_KIND_FILE_MISSING, "No XDG applications directory found."); } /* holds a filename -> component mapping */ validated_cpts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* set up XML parser */ xdt = as_xmldata_new (); as_xmldata_initialize (xdt, AS_CURRENT_FORMAT_VERSION, "C", NULL, NULL, NULL, 0); as_xmldata_set_format_style (xdt, AS_FORMAT_STYLE_METAINFO); /* validate all metainfo files */ mfiles = as_utils_find_files_matching (metainfo_dir, "*.xml", FALSE, NULL); mfiles_legacy = as_utils_find_files_matching (legacy_metainfo_dir, "*.xml", FALSE, NULL); /* in case we only have legacy files */ if (mfiles == NULL) mfiles = g_ptr_array_new_with_free_func (g_free); if (mfiles_legacy != NULL) { for (i = 0; i < mfiles_legacy->len; i++) { const gchar *fname; g_autofree gchar *fname_basename = NULL; /* process metainfo files in legacy paths */ fname = (const gchar*) g_ptr_array_index (mfiles_legacy, i); fname_basename = g_path_get_basename (fname); as_validator_set_current_fname (validator, fname_basename); as_validator_add_issue (validator, NULL, AS_ISSUE_IMPORTANCE_INFO, AS_ISSUE_KIND_LEGACY, "The metainfo file is stored in a legacy path. Please place it in '/usr/share/metainfo'."); g_ptr_array_add (mfiles, g_strdup (fname)); } } for (i = 0; i < mfiles->len; i++) { const gchar *fname; g_autoptr(GFile) file = NULL; g_autoptr(GInputStream) file_stream = NULL; g_autoptr(GError) tmp_error = NULL; g_autoptr(GString) asdata = NULL; gssize len; const gsize buffer_size = 1024 * 24; g_autofree gchar *buffer = NULL; xmlNode *root; xmlDoc *doc; g_autofree gchar *fname_basename = NULL; fname = (const gchar*) g_ptr_array_index (mfiles, i); file = g_file_new_for_path (fname); if (!g_file_query_exists (file, NULL)) { g_warning ("File '%s' suddenly vanished.", fname); g_object_unref (file); continue; } fname_basename = g_path_get_basename (fname); as_validator_set_current_fname (validator, fname_basename); /* load a plaintext file */ file_stream = G_INPUT_STREAM (g_file_read (file, NULL, &tmp_error)); if (tmp_error != NULL) { as_validator_add_issue (validator, NULL, AS_ISSUE_IMPORTANCE_ERROR, AS_ISSUE_KIND_READ_ERROR, "Unable to read file: %s", tmp_error->message); continue; } asdata = g_string_new (""); buffer = g_malloc (buffer_size); while ((len = g_input_stream_read (file_stream, buffer, buffer_size, NULL, &tmp_error)) > 0) { g_string_append_len (asdata, buffer, len); } /* check if there was an error */ if (tmp_error != NULL) { as_validator_add_issue (validator, NULL, AS_ISSUE_IMPORTANCE_ERROR, AS_ISSUE_KIND_READ_ERROR, "Unable to read file: %s", tmp_error->message); continue; } /* now read the XML */ doc = as_validator_open_xml_document (validator, xdt, asdata->str); if (doc == NULL) { as_validator_clear_current_fname (validator); continue; } root = xmlDocGetRootElement (doc); if (g_strcmp0 ((gchar*) root->name, "component") == 0) { AsComponent *cpt; cpt = as_validator_validate_component_node (validator, xdt, root); if (cpt != NULL) g_hash_table_insert (validated_cpts, g_strdup (fname_basename), cpt); } else if (g_strcmp0 ((gchar*) root->name, "components") == 0) { as_validator_add_issue (validator, root, AS_ISSUE_IMPORTANCE_ERROR, AS_ISSUE_KIND_TAG_NOT_ALLOWED, "The metainfo file specifies multiple components. This is not allowed."); ret = FALSE; } else if (g_str_has_prefix ((gchar*) root->name, "application")) { as_validator_add_issue (validator, root, AS_ISSUE_IMPORTANCE_ERROR, AS_ISSUE_KIND_LEGACY, "The metainfo file uses an ancient version of the AppStream specification, which can not be validated. Please migrate it to version 0.6 (or higher)."); ret = FALSE; } as_validator_clear_current_fname (validator); xmlFreeDoc (doc); } /* check if we have matching .desktop files */ dfilenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); dfiles = as_utils_find_files_matching (apps_dir, "*.desktop", FALSE, NULL); if (dfiles != NULL) { for (i = 0; i < dfiles->len; i++) { const gchar *fname; fname = (const gchar*) g_ptr_array_index (dfiles, i); g_hash_table_add (dfilenames, g_path_get_basename (fname)); } } /* validate the component-id <-> filename relations and availability of other metadata */ ht_helper.validator = validator; ht_helper.desktop_fnames = dfilenames; ht_helper.apps_dir = apps_dir; g_hash_table_foreach (validated_cpts, (GHFunc) as_validator_analyze_component_metainfo_relation_cb, &ht_helper); out: if (dfilenames != NULL) g_hash_table_unref (dfilenames); if (validated_cpts != NULL) g_hash_table_unref (validated_cpts); return ret; }
/** * 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; }