/
githubmirror
/
libmodulemd
Обзор
Документация
Войти
/
githubmirror
/
libmodulemd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
libmodulemd-2.9.2
modulemd/modulemd-module.c
816 строк
23 KB
Stephen Gallagher
Relax handling of differing content for the same NSVCA
28 фев 2020, 19:11
Не верифицирован
28 фев 2020, 19:11
4af0dba
Код
Авторство
О чём код?
/* * This file is part of libmodulemd * Copyright (C) 2018 Red Hat, Inc. * * 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 <https://www.gnu.org/philosophy/free-sw.en.html>. */ #include <glib.h> #include <inttypes.h> #include <yaml.h> #include "modulemd-errors.h" #include "modulemd-module.h" #include "private/glib-extensions.h" #include "private/modulemd-module-private.h" #include "private/modulemd-module-stream-private.h" #include "private/modulemd-translation-private.h" #include "private/modulemd-util.h" #include "private/modulemd-yaml.h" struct _ModulemdModule { GObject parent_instance; gchar *module_name; GPtrArray *streams; ModulemdDefaults *defaults; GHashTable *translations; }; G_DEFINE_TYPE (ModulemdModule, modulemd_module, G_TYPE_OBJECT) enum { PROP_0, PROP_MODULE_NAME, N_PROPS }; static GParamSpec *properties[N_PROPS]; ModulemdModule * modulemd_module_new (const gchar *module_name) { return g_object_new (MODULEMD_TYPE_MODULE, "module-name", module_name, NULL); } ModulemdModule * modulemd_module_copy (ModulemdModule *self) { g_autoptr (ModulemdModule) m = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); gsize i = 0; m = modulemd_module_new (modulemd_module_get_module_name (self)); m->defaults = modulemd_defaults_copy (self->defaults); for (i = 0; i < self->streams->len; i++) { g_ptr_array_add (m->streams, g_ptr_array_index (self->streams, i)); } return g_steal_pointer (&m); } gboolean modulemd_module_validate (ModulemdModule *self, GError **error) { /* No validation yet */ return TRUE; } static void modulemd_module_finalize (GObject *object) { ModulemdModule *self = (ModulemdModule *)object; g_clear_pointer (&self->module_name, g_free); g_clear_object (&self->defaults); g_clear_pointer (&self->streams, g_ptr_array_unref); g_clear_pointer (&self->translations, g_hash_table_unref); G_OBJECT_CLASS (modulemd_module_parent_class)->finalize (object); } static void modulemd_module_set_module_name (ModulemdModule *self, const gchar *module_name) { g_return_if_fail (MODULEMD_IS_MODULE (self)); g_return_if_fail (module_name); g_clear_pointer (&self->module_name, g_free); self->module_name = g_strdup (module_name); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODULE_NAME]); } const gchar * modulemd_module_get_module_name (ModulemdModule *self) { g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); return self->module_name; } static void modulemd_module_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ModulemdModule *self = MODULEMD_MODULE (object); switch (prop_id) { case PROP_MODULE_NAME: g_value_set_string (value, modulemd_module_get_module_name (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void modulemd_module_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ModulemdModule *self = MODULEMD_MODULE (object); switch (prop_id) { case PROP_MODULE_NAME: modulemd_module_set_module_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void modulemd_module_class_init (ModulemdModuleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = modulemd_module_finalize; object_class->get_property = modulemd_module_get_property; object_class->set_property = modulemd_module_set_property; properties[PROP_MODULE_NAME] = g_param_spec_string ( "module-name", "Module name", "The name of this module.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, N_PROPS, properties); } static void modulemd_module_init (ModulemdModule *self) { self->streams = g_ptr_array_new_full (0, g_object_unref); self->translations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } ModulemdDefaultsVersionEnum modulemd_module_set_defaults (ModulemdModule *self, ModulemdDefaults *defaults, ModulemdDefaultsVersionEnum index_mdversion, GError **error) { g_autoptr (ModulemdDefaults) upgraded_defaults = NULL; g_autoptr (GError) nested_error = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), MD_DEFAULTS_VERSION_ERROR); g_clear_object (&self->defaults); if (defaults == NULL) { /* If we are empty here, return MD_DEFAULTS_VERSION_UNSET so the * function reports success and does not influence further upgrades. */ return MD_DEFAULTS_VERSION_UNSET; } /* We should never get a defaults object added whose module name doesn't * match. */ if (g_strcmp0 (modulemd_defaults_get_module_name (defaults), modulemd_module_get_module_name (self)) != 0) { g_set_error (error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Attempted to add defaults for module '%s' to module '%s'", modulemd_defaults_get_module_name (defaults), modulemd_module_get_module_name (self)); return MD_DEFAULTS_VERSION_ERROR; } /* For Modulemd.ModuleIndex, we always want all entries to have the same * version, so that merges can be performed. If this Defaults object has a * lower mdversion than the Index, upgrade it to that version. * * We only call this if the mdversion is definitely lower, because the * upgrade() routine is not designed to handle downgrades. */ if (modulemd_defaults_get_mdversion (defaults) < index_mdversion) { upgraded_defaults = modulemd_defaults_upgrade (defaults, index_mdversion, &nested_error); if (!upgraded_defaults) { g_propagate_error (error, g_steal_pointer (&nested_error)); return MD_DEFAULTS_VERSION_ERROR; } } else { /* The new defaults were of the same or a higher version, so just copy it * and return that. The ModulemdModuleIndex will handle upgrading other * Defaults in the index to match. */ upgraded_defaults = modulemd_defaults_copy (defaults); } /* Return the mdversion we saved so that the Index can check to see if we * need to upgrade other modules to match. */ self->defaults = g_steal_pointer (&upgraded_defaults); return modulemd_defaults_get_mdversion (self->defaults); } ModulemdDefaults * modulemd_module_get_defaults (ModulemdModule *self) { g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); return self->defaults; } ModulemdModuleStreamVersionEnum modulemd_module_add_stream (ModulemdModule *self, ModulemdModuleStream *stream, ModulemdModuleStreamVersionEnum index_mdversion, GError **error) { ModulemdModuleStream *old = NULL; ModulemdTranslation *translation = NULL; ModulemdModuleStream *newstream = NULL; g_autoptr (GError) nested_error = NULL; const gchar *module_name = NULL; const gchar *stream_name = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), MD_MODULESTREAM_VERSION_ERROR); g_return_val_if_fail (MODULEMD_IS_MODULE_STREAM (stream), MD_MODULESTREAM_VERSION_ERROR); module_name = modulemd_module_stream_get_module_name (stream); stream_name = modulemd_module_stream_get_stream_name (stream); if (!module_name) { g_set_error ( error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Attempted to add stream with no module name to module '%s'", modulemd_module_get_module_name (self)); return MD_MODULESTREAM_VERSION_ERROR; } if (!stream_name) { g_set_error ( error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Attempted to add stream with no stream name to module '%s'", modulemd_module_get_module_name (self)); return MD_MODULESTREAM_VERSION_ERROR; } /* We should never get a stream object added whose module name doesn't * match. */ if (g_strcmp0 (module_name, modulemd_module_get_module_name (self)) != 0) { g_set_error (error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Attempted to add stream for module '%s' to module '%s'", module_name, modulemd_module_get_module_name (self)); return MD_MODULESTREAM_VERSION_ERROR; } old = modulemd_module_get_stream_by_NSVCA ( self, modulemd_module_stream_get_stream_name (stream), modulemd_module_stream_get_version (stream), modulemd_module_stream_get_context (stream), modulemd_module_stream_get_arch (stream), &nested_error); if (old != NULL) { /* We're probably deduplicating content here, so remove the old one in * favor of the new one. */ if (!modulemd_module_stream_equals (old, stream)) { g_autofree gchar *nsvca = modulemd_module_stream_get_NSVCA_as_string (stream); /* The two streams have matching NSVCA, but differ in content */ g_set_error (error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "Encountered two streams with matching NSVCA %s but " "differing content", nsvca); return MD_MODULESTREAM_VERSION_ERROR; } /* First, drop the existing stream */ g_ptr_array_remove (self->streams, old); old = NULL; } else if (old == NULL && g_error_matches (nested_error, MODULEMD_ERROR, MMD_ERROR_TOO_MANY_MATCHES)) { /* It should be impossible to get more than one error back here */ g_propagate_error (error, g_steal_pointer (&nested_error)); return MD_MODULESTREAM_VERSION_ERROR; } g_clear_error (&nested_error); if (modulemd_module_stream_get_mdversion (stream) < index_mdversion) { /* If the stream we were passed is of a lower version than the index has * seen before, upgrade it to the index version. * * We only call this if the mdversion is definitely lower, because the * upgrade() routine is not designed to handle downgrades. */ newstream = modulemd_module_stream_upgrade ( stream, index_mdversion, &nested_error); if (!newstream) { g_propagate_error (error, g_steal_pointer (&nested_error)); return MD_MODULESTREAM_VERSION_ERROR; } } else { newstream = modulemd_module_stream_copy (stream, NULL, NULL); } g_ptr_array_add (self->streams, newstream); translation = g_hash_table_lookup ( self->translations, modulemd_module_stream_get_stream_name (stream)); if (translation != NULL) { modulemd_module_stream_associate_translation (newstream, translation); } return modulemd_module_stream_get_mdversion (newstream); } GStrv modulemd_module_get_stream_names_as_strv (ModulemdModule *self) { g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); if (!self->streams) { return NULL; } g_autoptr (GHashTable) stream_names = g_hash_table_new (g_str_hash, g_str_equal); for (guint i = 0; i < self->streams->len; i++) { g_hash_table_add (stream_names, (void *)modulemd_module_stream_get_stream_name ( g_ptr_array_index (self->streams, i))); } return modulemd_ordered_str_keys_as_strv (stream_names); } GPtrArray * modulemd_module_get_all_streams (ModulemdModule *self) { g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); return self->streams; } GPtrArray * modulemd_module_get_streams_by_stream_name_as_list (ModulemdModule *self, const gchar *stream_name) { g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); return modulemd_module_search_streams (self, stream_name, 0, NULL, NULL); } ModulemdModuleStream * modulemd_module_get_stream_by_NSVC (ModulemdModule *self, const gchar *stream_name, const guint64 version, const gchar *context) { return modulemd_module_get_stream_by_NSVCA ( self, stream_name, version, context, NULL, NULL); } GPtrArray * modulemd_module_search_streams_by_glob (ModulemdModule *self, const gchar *stream_name, const gchar *version, const gchar *context, const gchar *arch) { gsize i = 0; g_autoptr (GPtrArray) matching_streams = NULL; ModulemdModuleStream *under_consideration = NULL; g_autofree gchar *version_str = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); /* Assume the worst-case scenario that all streams match to spare us extra * mallocs. */ matching_streams = g_ptr_array_sized_new (self->streams->len); for (i = 0; i < self->streams->len; i++) { g_clear_pointer (&version_str, g_free); under_consideration = (ModulemdModuleStream *)g_ptr_array_index (self->streams, i); /* Skip this one unless the stream name matches */ if (!modulemd_fnmatch ( stream_name, modulemd_module_stream_get_stream_name (under_consideration))) { continue; } /* Skip this one unless the stream version matches OR the version is zero * which indicates that it shouldn't prevent the other cases from * matching. */ if (version) { version_str = g_strdup_printf ( "%" PRIu64, modulemd_module_stream_get_version (under_consideration)); if (!modulemd_fnmatch (version, version_str)) { continue; } } if (!modulemd_fnmatch ( context, modulemd_module_stream_get_context (under_consideration))) { continue; } if (!modulemd_fnmatch ( arch, modulemd_module_stream_get_arch (under_consideration))) { continue; } g_ptr_array_add (matching_streams, under_consideration); } g_ptr_array_sort (matching_streams, compare_streams); return g_steal_pointer (&matching_streams); } GPtrArray * modulemd_module_search_streams_by_nsvca_glob (ModulemdModule *self, const gchar *nsvca_pattern) { gsize i = 0; g_autoptr (GPtrArray) matching_streams = NULL; ModulemdModuleStream *under_consideration = NULL; g_autofree gchar *nsvca = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); /* Assume the worst-case scenario that all streams match to spare us extra * mallocs. */ matching_streams = g_ptr_array_sized_new (self->streams->len); for (i = 0; i < self->streams->len; i++) { under_consideration = (ModulemdModuleStream *)g_ptr_array_index (self->streams, i); nsvca = modulemd_module_stream_get_NSVCA_as_string (under_consideration); if (nsvca_pattern == NULL || modulemd_fnmatch (nsvca_pattern, nsvca)) { g_ptr_array_add (matching_streams, under_consideration); } g_clear_pointer (&nsvca, g_free); } return g_steal_pointer (&matching_streams); } GPtrArray * modulemd_module_search_streams (ModulemdModule *self, const gchar *stream_name, const guint64 version, const gchar *context, const gchar *arch) { g_autofree gchar *version_str = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); if (version) { version_str = g_strdup_printf ("%" PRIu64, version); } return modulemd_module_search_streams_by_glob ( self, stream_name, version_str, context, arch); } ModulemdModuleStream * modulemd_module_get_stream_by_NSVCA (ModulemdModule *self, const gchar *stream_name, const guint64 version, const gchar *context, const gchar *arch, GError **error) { g_autoptr (GPtrArray) matching_streams = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), NULL); matching_streams = modulemd_module_search_streams (self, stream_name, version, context, arch); if (matching_streams->len == 0) { g_set_error ( error, MODULEMD_ERROR, MMD_ERROR_NO_MATCHES, "No streams matched"); return NULL; } if (matching_streams->len > 1) { g_set_error (error, MODULEMD_ERROR, MMD_ERROR_TOO_MANY_MATCHES, "Multiple ModulemdModuleStreams matched"); return NULL; } /* Exactly one result, so return it */ return g_ptr_array_index (matching_streams, 0); } typedef struct _modulemd_nsvca { const gchar *stream_name; guint64 version; const gchar *context; const gchar *arch; } modulemd_nsvca; static void modulemd_nsvca_free (gpointer nsvca) { /* All of the fields are just pointers to static data, * so nothing to free here. */ g_free ((modulemd_nsvca *)nsvca); } G_DEFINE_AUTOPTR_CLEANUP_FUNC (modulemd_nsvca, modulemd_nsvca_free); static gboolean match_nsvca (gconstpointer haystraw, gconstpointer needle) { ModulemdModuleStream *stream = (ModulemdModuleStream *)haystraw; modulemd_nsvca *nsvca = (modulemd_nsvca *)needle; if (!g_str_equal (nsvca->stream_name, modulemd_module_stream_get_stream_name (stream))) { return FALSE; } if (nsvca->version) { if (nsvca->version != modulemd_module_stream_get_version (stream)) { return FALSE; } } if (nsvca->context) { if (!g_str_equal (nsvca->context, modulemd_module_stream_get_context (stream))) { return FALSE; } } if (nsvca->arch) { if (!g_str_equal (nsvca->arch, modulemd_module_stream_get_arch (stream))) { return FALSE; } } return TRUE; } void modulemd_module_remove_streams_by_NSVCA (ModulemdModule *self, const gchar *stream_name, const guint64 version, const gchar *context, const gchar *arch) { gboolean found = FALSE; guint index; g_autoptr (modulemd_nsvca) nsvca = g_malloc0_n (1, sizeof (modulemd_nsvca)); nsvca->stream_name = stream_name; nsvca->version = version; nsvca->context = context; nsvca->arch = arch; /* Iterate through the streams and remove any that match the requested * parameters */ do { found = g_ptr_array_find_with_equal_func ( self->streams, nsvca, match_nsvca, &index); if (found) { g_ptr_array_remove_index (self->streams, index); } } while (found); } void modulemd_module_add_translation (ModulemdModule *self, ModulemdTranslation *translation) { gsize i; ModulemdModuleStream *stream = NULL; ModulemdTranslation *newtrans = NULL; g_return_if_fail ( g_str_equal (modulemd_translation_get_module_name (translation), modulemd_module_get_module_name (self))); newtrans = modulemd_translation_copy (translation); g_hash_table_replace ( self->translations, g_strdup (modulemd_translation_get_module_stream (translation)), newtrans); for (i = 0; i < self->streams->len; i++) { stream = (ModulemdModuleStream *)g_ptr_array_index (self->streams, i); if (!g_str_equal (modulemd_translation_get_module_stream (newtrans), modulemd_module_stream_get_stream_name (stream))) { continue; } modulemd_module_stream_associate_translation (stream, newtrans); } } GPtrArray * modulemd_module_get_translated_streams (ModulemdModule *self) { return modulemd_ordered_str_keys (self->translations, modulemd_strcmp_sort); } ModulemdTranslation * modulemd_module_get_translation (ModulemdModule *self, const gchar *stream) { return g_hash_table_lookup (self->translations, stream); } gboolean modulemd_module_upgrade_streams (ModulemdModule *self, ModulemdModuleStreamVersionEnum mdversion, GError **error) { g_autoptr (GPtrArray) new_streams = NULL; ModulemdModuleStreamVersionEnum current_mdversion; g_autoptr (ModulemdModuleStream) modulestream = NULL; g_autoptr (ModulemdModuleStream) upgraded_stream = NULL; g_autofree gchar *nsvca = NULL; g_autoptr (GError) nested_error = NULL; g_return_val_if_fail (MODULEMD_IS_MODULE (self), FALSE); new_streams = g_ptr_array_new_full (self->streams->len, g_object_unref); for (guint i = 0; i < self->streams->len; i++) { modulestream = g_object_ref ( MODULEMD_MODULE_STREAM (g_ptr_array_index (self->streams, i))); current_mdversion = modulemd_module_stream_get_mdversion (modulestream); nsvca = modulemd_module_stream_get_NSVCA_as_string (modulestream); if (current_mdversion <= MD_MODULESTREAM_VERSION_UNSET) { g_set_error (error, MODULEMD_ERROR, MMD_ERROR_VALIDATE, "ModuleStream %s had invalid mdversion %i", nsvca, current_mdversion); return FALSE; } if (current_mdversion == mdversion) { /* Already at the right version, so just add it to the new list */ g_ptr_array_add (new_streams, g_steal_pointer (&modulestream)); } else { upgraded_stream = modulemd_module_stream_upgrade ( modulestream, mdversion, &nested_error); if (!upgraded_stream) { g_propagate_prefixed_error (error, g_steal_pointer (&nested_error), "Error upgrading module stream %s", nsvca); return FALSE; } g_ptr_array_add (new_streams, g_steal_pointer (&upgraded_stream)); } g_clear_pointer (&nsvca, g_free); g_clear_object (&modulestream); } /* Replace the old stream list with the new one */ g_ptr_array_unref (self->streams); self->streams = g_steal_pointer (&new_streams); return TRUE; }