/* * This file is part of libmodulemd * Copyright (C) 2017-2018 Stephen Gallagher * * Fedora-License-Identifier: MIT * SPDX-2.0-License-Identifier: MIT * SPDX-3.0-License-Identifier: MIT * * This program is free software. * For more information on the license, see COPYING. * For more information on free software, see . */ #include "config.h" #include "modulemd.h" #include "modulemd-module.h" #include "private/modulemd-improvedmodule-private.h" #include "private/modulemd-yaml.h" #include "private/modulemd-util.h" #include GPtrArray * modulemd_objects_from_file (const gchar *yaml_file, GError **error) { return modulemd_objects_from_file_ext (yaml_file, NULL, error); } GPtrArray * modulemd_objects_from_file_ext (const gchar *yaml_file, GPtrArray **failures, GError **error) { g_autoptr (GPtrArray) data = NULL; GPtrArray *compat_data = NULL; g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (!parse_yaml_file (yaml_file, &data, failures, error)) { return NULL; } /* For backwards-compatibility, we need to return Modulemd.Module objects, * not Modulemd.ModuleStream objects */ compat_data = mmd_yaml_convert_modulestreams (data); return compat_data; } GHashTable * modulemd_index_from_file (const gchar *yaml_file, GPtrArray **failures, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); return parse_module_index_from_file (yaml_file, failures, error); } GPtrArray * modulemd_objects_from_stream (FILE *stream, GError **error) { return modulemd_objects_from_stream_ext (stream, NULL, error); } GPtrArray * modulemd_objects_from_stream_ext (FILE *stream, GPtrArray **failures, GError **error) { g_autoptr (GPtrArray) data = NULL; GPtrArray *compat_data = NULL; g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (!parse_yaml_stream (stream, &data, failures, error)) { return NULL; } /* For backwards-compatibility, we need to return Modulemd.Module objects, * not Modulemd.ModuleStream objects */ compat_data = mmd_yaml_convert_modulestreams (data); return compat_data; } GHashTable * modulemd_index_from_stream (FILE *yaml_stream, GPtrArray **failures, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); return parse_module_index_from_stream (yaml_stream, failures, error); } GPtrArray * modulemd_objects_from_string (const gchar *yaml_string, GError **error) { return modulemd_objects_from_string_ext (yaml_string, NULL, error); } GPtrArray * modulemd_objects_from_string_ext (const gchar *yaml_string, GPtrArray **failures, GError **error) { g_autoptr (GPtrArray) data = NULL; GPtrArray *compat_data = NULL; g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (!parse_yaml_string (yaml_string, &data, failures, error)) { return NULL; } /* For backwards-compatibility, we need to return Modulemd.Module objects, * not Modulemd.ModuleStream objects */ compat_data = mmd_yaml_convert_modulestreams (data); return compat_data; } GHashTable * modulemd_index_from_string (const gchar *yaml_string, GPtrArray **failures, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); return parse_module_index_from_string (yaml_string, failures, error); } gboolean modulemd_dump_index (GHashTable *index, const gchar *yaml_file, GError **error) { g_autoptr (GPtrArray) objects = _modulemd_index_serialize (index, error); if (!objects) { g_debug ("Serialization of index failed: %s", (*error)->message); return FALSE; } return emit_yaml_file (objects, yaml_file, error); } gchar * modulemd_dumps_index (GHashTable *index, GError **error) { gboolean result; gchar *yaml = NULL; g_autoptr (GPtrArray) objects = _modulemd_index_serialize (index, error); if (!objects) { g_debug ("Serialization of index failed: %s", (*error)->message); return FALSE; } result = emit_yaml_string (objects, &yaml, error); if (!result) { g_debug ("Emitting YAML string failed: %s", (*error)->message); return NULL; } return yaml; } void modulemd_dump (GPtrArray *objects, const gchar *yaml_file, GError **error) { g_return_if_fail (error == NULL || *error == NULL); emit_yaml_file (objects, yaml_file, error); } gchar * modulemd_dumps (GPtrArray *objects, GError **error) { gchar *yaml_string = NULL; g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (!emit_yaml_string (objects, &yaml_string, error)) { return NULL; } return yaml_string; } GPtrArray * modulemd_merge_defaults (const GPtrArray *first, const GPtrArray *second, gboolean override, GError **error) { g_autoptr (GPtrArray) merge_base = NULL; g_autoptr (GPtrArray) merged = NULL; g_autoptr (GPtrArray) keys = NULL; GObject *object = NULL; g_autoptr (GHashTable) defaults = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); gchar *key = NULL; gpointer value = NULL; ModulemdDefaults *updated_defs = NULL; gsize i; merge_base = g_ptr_array_new_full (first->len, g_object_unref); for (i = 0; i < first->len; i++) { g_ptr_array_add (merge_base, g_object_ref (g_ptr_array_index (first, i))); } if (second && !override) { /* If the second repo doesn't override the first, then we can just treat * them as concatenated together and save some processing time. */ g_ptr_array_set_size (merge_base, first->len + second->len); for (i = 0; i < second->len; i++) { g_ptr_array_add (merge_base, g_object_ref (g_ptr_array_index (second, i))); } } merged = g_ptr_array_new_full (merge_base->len, g_object_unref); for (i = 0; i < merge_base->len; i++) { object = g_ptr_array_index (merge_base, i); if (MODULEMD_IS_DEFAULTS (object)) { key = modulemd_defaults_dup_module_name (MODULEMD_DEFAULTS (object)); value = g_hash_table_lookup (defaults, key); if (!value) { /* This is the first time we've encountered the defaults for this * module. */ g_hash_table_replace (defaults, key, g_object_ref (object)); } else { /* We've seen this one before. Handle the merge */ updated_defs = modulemd_defaults_merge (MODULEMD_DEFAULTS (value), MODULEMD_DEFAULTS (object), FALSE, error); if (!updated_defs) { /* The merge failed. Raise the error */ g_clear_pointer (&key, g_free); return NULL; } g_hash_table_replace (defaults, key, updated_defs); } } else { /* Not a default object, so just add it to the list */ g_ptr_array_add (merged, g_object_ref (object)); } } if (second && override) { /* The repos had different priorities, so after resolving any conflicts * from the base repo, we will set any needed updates and overrides here. */ for (i = 0; i < second->len; i++) { object = g_ptr_array_index (second, i); if (MODULEMD_IS_DEFAULTS (object)) { key = modulemd_defaults_dup_module_name (MODULEMD_DEFAULTS (object)); value = g_hash_table_lookup (defaults, key); if (!value) { /* This is the first time we've encountered the defaults for this * module. */ g_hash_table_replace (defaults, key, g_object_ref (object)); } else { /* We've seen this one before. Handle the merge */ updated_defs = modulemd_defaults_merge (MODULEMD_DEFAULTS (value), MODULEMD_DEFAULTS (object), TRUE, error); if (!updated_defs) { /* The merge failed. Raise the error */ return NULL; } g_hash_table_replace (defaults, key, updated_defs); } } else { /* Not a default object, so just add it to the list */ g_ptr_array_add (merged, g_object_ref (object)); } } } /* Add all of the defaults to the end of the list */ keys = _modulemd_ordered_str_keys (defaults, _modulemd_strcmp_sort); for (i = 0; i < keys->len; i++) { value = g_hash_table_lookup (defaults, g_ptr_array_index (keys, i)); g_ptr_array_add (merged, g_object_ref (MODULEMD_DEFAULTS (value))); } return g_ptr_array_ref (merged); } const gchar * modulemd_get_version (void) { return LIBMODULEMD_VERSION; }