Esempio n. 1
0
/**
 * as_merge_components:
 *
 * Merge selected data from two components.
 */
static void
as_merge_components (AsComponent *dest_cpt, AsComponent *src_cpt)
{
	guint i;
	AsMergeKind merge_kind;

	merge_kind = as_component_get_merge_kind (src_cpt);
	g_return_if_fail (merge_kind != AS_MERGE_KIND_NONE);

	/* FIXME: We need to merge more attributes */

	/* merge stuff in append mode */
	if (merge_kind == AS_MERGE_KIND_APPEND) {
		GPtrArray *suggestions;
		GPtrArray *cats;

		/* merge categories */
		cats = as_component_get_categories (src_cpt);
		if (cats->len > 0) {
			g_autoptr(GHashTable) cat_table = NULL;
			GPtrArray *dest_categories;

			cat_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
			for (i = 0; i < cats->len; i++) {
				const gchar *cat = (const gchar*) g_ptr_array_index (cats, i);
				g_hash_table_add (cat_table, g_strdup (cat));
			}

			dest_categories = as_component_get_categories (dest_cpt);
			if (dest_categories->len > 0) {
				for (i = 0; i < dest_categories->len; i++) {
					const gchar *cat = (const gchar*) g_ptr_array_index (dest_categories, i);
					g_hash_table_add (cat_table, g_strdup (cat));
				}
			}

			g_ptr_array_set_size (dest_categories, 0);
			as_hash_table_string_keys_to_array (cat_table, dest_categories);
		}

		/* merge suggestions */
		suggestions = as_component_get_suggested (src_cpt);
		if (suggestions != NULL) {
			for (i = 0; i < suggestions->len; i++) {
				as_component_add_suggested (dest_cpt,
						    AS_SUGGESTED (g_ptr_array_index (suggestions, i)));
			}
		}
	}

	/* merge stuff in replace mode */
	if (merge_kind == AS_MERGE_KIND_REPLACE) {
		gchar **pkgnames;

		/* merge names */
		if (as_component_get_name (src_cpt) != NULL)
			as_component_set_name (dest_cpt, as_component_get_name (src_cpt), as_component_get_active_locale (src_cpt));

		/* merge package names */
		pkgnames = as_component_get_pkgnames (src_cpt);
		if ((pkgnames != NULL) && (pkgnames[0] != '\0'))
			as_component_set_pkgnames (dest_cpt, as_component_get_pkgnames (src_cpt));

		/* merge bundles */
		if (as_component_has_bundle (src_cpt))
			as_component_set_bundles_array (dest_cpt, as_component_get_bundles (src_cpt));
	}

	g_debug ("Merged data for '%s'", as_component_get_data_id (dest_cpt));
}
Esempio n. 2
0
/**
 * as_validator_analyze_component_metainfo_relation_cb:
 *
 * Helper function for GHashTable foreach iteration.
 */
static void
as_validator_analyze_component_metainfo_relation_cb (const gchar *fname, AsComponent *cpt, struct MInfoCheckData *data)
{
	gchar *tmp;

	/* if we have no component-id, we can't check anything */
	if (as_component_get_id (cpt) == NULL)
		return;

	as_validator_set_current_cpt (data->validator, cpt);
	as_validator_set_current_fname (data->validator, fname);

	/* check if the fname and the component-id match */
	tmp = g_strndup (as_component_get_id (cpt),
				g_strrstr (as_component_get_id (cpt), ".") - as_component_get_id (cpt));
	if (!as_matches_metainfo (fname, tmp)) {
		/* the name-without-type didn't match - check for the full id in the component name */
		if (!as_matches_metainfo (fname, as_component_get_id (cpt))) {
			as_validator_add_issue (data->validator,
					AS_ISSUE_IMPORTANCE_WARNING,
					AS_ISSUE_KIND_WRONG_NAME,
					"The metainfo filename does not match the component ID.");
		}
	}
	g_free (tmp);

	/* check if the referenced .desktop file exists */
	if (as_component_get_kind (cpt) == AS_COMPONENT_KIND_DESKTOP_APP) {
		if (g_hash_table_contains (data->desktop_fnames, as_component_get_id (cpt))) {
			g_autofree gchar *desktop_fname_full = NULL;
			g_autoptr(GKeyFile) dfile = NULL;
			GError *tmp_error = NULL;

			desktop_fname_full = g_build_filename (data->apps_dir, as_component_get_id (cpt), NULL);
			dfile = g_key_file_new ();

			g_key_file_load_from_file (dfile, desktop_fname_full, G_KEY_FILE_NONE, &tmp_error);
			if (tmp_error != NULL) {
				as_validator_add_issue (data->validator,
						AS_ISSUE_IMPORTANCE_WARNING,
						AS_ISSUE_KIND_READ_ERROR,
						"Unable to read associated .desktop file: %s", tmp_error->message);
				g_error_free (tmp_error);
				tmp_error = NULL;
			} else {
				/* we successfully opened the .desktop file, now perform some checks */

				/* name */
				if ((g_strcmp0 (as_component_get_name (cpt), "") == 0) &&
				    (!g_key_file_has_key (dfile, "Desktop Entry", "Name", NULL))) {
					/* we don't have a summary, and there is also none in the .desktop file - this is bad. */
					as_validator_add_issue (data->validator,
							AS_ISSUE_IMPORTANCE_ERROR,
							AS_ISSUE_KIND_VALUE_MISSING,
							"The component is missing a name (none found in its metainfo or .desktop file)");
				}

				/* summary */
				if ((g_strcmp0 (as_component_get_summary (cpt), "") == 0) &&
				    (!g_key_file_has_key (dfile, "Desktop Entry", "Comment", NULL))) {
					/* we don't have a summary, and there is also none in the .desktop file - this is bad. */
					as_validator_add_issue (data->validator,
							AS_ISSUE_IMPORTANCE_ERROR,
							AS_ISSUE_KIND_VALUE_MISSING,
							"The component is missing a summary (none found in its metainfo or .desktop file)");
				}
			}
		} else {
			as_validator_add_issue (data->validator,
					AS_ISSUE_IMPORTANCE_ERROR,
					AS_ISSUE_KIND_FILE_MISSING,
					"Component metadata refers to a non-existing .desktop file.");
		}
	}

	as_validator_clear_current_cpt (data->validator);
	as_validator_clear_current_fname (data->validator);
}
Esempio n. 3
0
/**
 * as_validator_analyze_component_metainfo_relation_cb:
 *
 * Helper function for GHashTable foreach iteration.
 */
static void
as_validator_analyze_component_metainfo_relation_cb (const gchar *fname, AsComponent *cpt, struct MInfoCheckData *data)
{
	g_autofree gchar *cid_base = NULL;

	/* if we have no component-id, we can't check anything */
	if (as_component_get_id (cpt) == NULL)
		return;

	as_validator_set_current_cpt (data->validator, cpt);
	as_validator_set_current_fname (data->validator, fname);

	/* check if the fname and the component-id match */
	if (g_str_has_suffix (as_component_get_id (cpt), ".desktop")) {
		cid_base = g_strndup (as_component_get_id (cpt),
					g_strrstr (as_component_get_id (cpt), ".") - as_component_get_id (cpt));
	} else {
		cid_base = g_strdup (as_component_get_id (cpt));
	}
	if (!as_matches_metainfo (fname, cid_base)) {
		/* the name-without-type didn't match - check for the full id in the component name */
		if (!as_matches_metainfo (fname, as_component_get_id (cpt))) {
			as_validator_add_issue (data->validator, NULL,
					AS_ISSUE_IMPORTANCE_WARNING,
					AS_ISSUE_KIND_WRONG_NAME,
					"The metainfo filename does not match the component ID.");
		}
	}

	/* check if the referenced .desktop file exists */
	if (as_component_get_kind (cpt) == AS_COMPONENT_KIND_DESKTOP_APP) {
		if (g_hash_table_contains (data->desktop_fnames, as_component_get_desktop_id (cpt))) {
			g_autofree gchar *desktop_fname_full = NULL;
			g_autoptr(GKeyFile) dfile = NULL;
			GError *tmp_error = NULL;

			desktop_fname_full = g_build_filename (data->apps_dir, as_component_get_desktop_id (cpt), NULL);
			dfile = g_key_file_new ();

			g_key_file_load_from_file (dfile, desktop_fname_full, G_KEY_FILE_NONE, &tmp_error);
			if (tmp_error != NULL) {
				as_validator_add_issue (data->validator, NULL,
						AS_ISSUE_IMPORTANCE_WARNING,
						AS_ISSUE_KIND_READ_ERROR,
						"Unable to read associated .desktop file: %s", tmp_error->message);
				g_error_free (tmp_error);
				tmp_error = NULL;
			} else {
				/* we successfully opened the .desktop file, now perform some checks */

				/* name */
				if (as_str_empty (as_component_get_name (cpt)) &&
				    (!g_key_file_has_key (dfile, G_KEY_FILE_DESKTOP_GROUP,
								 G_KEY_FILE_DESKTOP_KEY_NAME, NULL))) {
					/* we don't have a summary, and there is also none in the .desktop file - this is bad. */
					as_validator_add_issue (data->validator, NULL,
							AS_ISSUE_IMPORTANCE_ERROR,
							AS_ISSUE_KIND_VALUE_MISSING,
							"The component is missing a name (none found in its metainfo or .desktop file)");
				}

				/* summary */
				if (as_str_empty (as_component_get_summary (cpt)) &&
				    (!g_key_file_has_key (dfile, G_KEY_FILE_DESKTOP_GROUP,
								 G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL))) {
					/* we don't have a summary, and there is also none in the .desktop file - this is bad. */
					as_validator_add_issue (data->validator, NULL,
							AS_ISSUE_IMPORTANCE_ERROR,
							AS_ISSUE_KIND_VALUE_MISSING,
							"The component is missing a summary (none found in its metainfo or .desktop file)");
				}

				/* categories */
				if (g_key_file_has_key (dfile, G_KEY_FILE_DESKTOP_GROUP,
								G_KEY_FILE_DESKTOP_KEY_CATEGORIES, NULL)) {
					g_autofree gchar *cats_str = NULL;
					g_auto(GStrv) cats = NULL;
					guint i;

					cats_str = g_key_file_get_string (dfile, G_KEY_FILE_DESKTOP_GROUP,
										 G_KEY_FILE_DESKTOP_KEY_CATEGORIES, NULL);
					cats = g_strsplit (cats_str, ";", -1);
					for (i = 0; cats[i] != NULL; i++) {
						if (as_str_empty (cats[i]))
							continue;
						if (!as_utils_is_category_name (cats[i])) {
							as_validator_add_issue (data->validator, NULL,
										AS_ISSUE_IMPORTANCE_ERROR,
										AS_ISSUE_KIND_VALUE_WRONG,
										"The category '%s' defined in the .desktop file does not exist.", cats[i]);
						}
					}
				}

			}
		} else {
			as_validator_add_issue (data->validator, NULL,
					AS_ISSUE_IMPORTANCE_ERROR,
					AS_ISSUE_KIND_FILE_MISSING,
					"Component metadata refers to a non-existing .desktop file.");
		}
	}

	as_validator_clear_current_cpt (data->validator);
	as_validator_clear_current_fname (data->validator);
}
Esempio n. 4
0
/**
 * 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;
}